Skip to content

fix: replace settings redirect with API key prompt modal#2

Open
CJFWeatherhead wants to merge 7 commits intomainfrom
fix/spa-routing-and-auth-modal
Open

fix: replace settings redirect with API key prompt modal#2
CJFWeatherhead wants to merge 7 commits intomainfrom
fix/spa-routing-and-auth-modal

Conversation

@CJFWeatherhead
Copy link
Copy Markdown
Member

Summary

Replace the onMount redirect to /settings with a modal overlay that prompts for API credentials on whichever page the user is visiting. This fixes several broken standard browser behaviours.

Problems fixed

  • Refresh loses the page — the old goto(base + "/settings") ran on every page load when credentials had not been validated yet, so any refresh redirected to Settings
  • Back button loops — navigating back just triggered another redirect to Settings
  • Direct URL access fails — visiting e.g. /nodes directly showed a blank page briefly before redirecting, because the SPA had no fallback for unknown paths
  • First-time flow is confusing — new users were dumped on the Settings page with no clear indication of what to do

Changes

File Change
src/lib/parts/ApiKeyPrompt.svelte New — modal overlay prompting for API URL + key when !App.hasApi. Validates credentials with a direct fetch before persisting them.
src/routes/+layout.svelte Removed goto(settings) redirect and its imports. Added ApiKeyPrompt component.
svelte.config.js Added fallback: "200.html" to adapter-static so unknown paths get a usable SPA shell instead of a 404.
Caddyfile Extended try_files with {path}/index.html and /200.html fallback for robust serving of pre-rendered routes and SPA fallback.
src/index.test.ts Replaced the placeholder 1+2=3 test with 32 unit tests covering funcs.ts utilities.
.github/workflows/ci.yml New — CI pipeline: lint + type-check, unit tests, static build (with and without ENDPOINT), Docker build smoke test.
README.md Added Authentication Flow section describing the new behaviour.

Behaviour after this change

  1. First visit (no credentials) — API key prompt modal appears over the requested page. Enter credentials, modal validates and dismisses, you remain on the page you originally requested.
  2. Returning user — page loads directly, no prompt, no redirect.
  3. Refresh — works on any page (each route has pre-rendered HTML; JS hydrates and polls data).
  4. Back button — works normally (no redirect loop).
  5. Settings page — fully functional for changing credentials, theme, TTL, debug settings.
  6. Invalid key mid-session — existing toast notification; user navigates to Settings manually.

Testing

  • 32 unit tests (all passing via vitest run)
  • svelte-check — 0 errors, 0 warnings
  • Static build verified with both ENDPOINT="" and ENDPOINT=/admin
  • All pre-rendered routes + 200.html fallback confirmed in build output

Replace the onMount redirect to /settings with a modal overlay that
prompts for API credentials on any page when they are missing. This
fixes:

- Browser refresh losing the current page (redirect to /settings)
- Back button creating redirect loops
- Direct URL access to routes showing blank pages

Changes:
- Add ApiKeyPrompt.svelte modal that validates credentials inline
- Remove goto(/settings) redirect from +layout.svelte
- Add adapter-static fallback (200.html) for unknown routes
- Update Caddyfile try_files to serve index.html and SPA fallback
- Replace placeholder test with 32 unit tests for funcs.ts utilities
- Add CI workflow (lint, type-check, test, build, Docker smoke test)
- Document authentication flow in README
- Add e2e/mock-api.mjs: lightweight mock Headscale API server returning
  fixture data matching openapiv2.json types (users, nodes, preauth keys,
  API keys, policy). Validates Bearer token auth.

- Add e2e/navigation.spec.ts: 25 Playwright E2E tests covering:
  - Unauthenticated: prompt appears on all pages, invalid key rejected
  - Auth flow: credentials dismiss modal, user stays on requested page
  - Authenticated navigation: all routes render real content
  - Refresh: preserves current page
  - Back button: forward/back navigation works correctly
  - Direct URL access: no white screen on any route

- Fix Caddyfile: use {ENDPOINT}/200.html for SPA fallback so it
  resolves correctly when build output is inside /app/admin/

- Fix Dockerfile: export ENDPOINT env var to Caddy stage so
  Caddyfile can reference it

- Add Playwright to devDependencies and test:e2e script
- Add E2E job to CI workflow
- Add Docker smoke test for /admin/nonexistent/ (fallback)
- Add Playwright artifacts to .gitignore
- Add src/routes/+error.svelte: replaces SvelteKit's blank default error
  page with a styled fallback (status code + message + 'Go to dashboard'
  button) so any routing error produces a visible screen, not a blank page.

- Add e2e/docker.spec.ts: 10 Playwright tests that run against the
  production Docker build (Caddy + /admin base path). Covers refresh,
  direct URL access, unauthenticated modal, and post-auth refresh.

- Add playwright.docker.config.ts: separate Playwright config for the
  Docker suite; baseURL set to http://localhost:8080/admin/ (with trailing
  slash) so relative paths like './nodes/' resolve to /admin/nodes/.

- Add e2e-docker CI job: builds the Docker image, starts the container +
  mock API, waits for both to be ready via curl retry, runs the Docker
  E2E suite, then tears down.

- Add /healthz endpoint to mock-api.mjs for CI readiness checks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant