Skip to content

feat(web): redesign API token modal with show/hide and inline retry#117

Merged
CoderCoco merged 6 commits into
mainfrom
claude/issue-64-9QSsY
May 5, 2026
Merged

feat(web): redesign API token modal with show/hide and inline retry#117
CoderCoco merged 6 commits into
mainfrom
claude/issue-64-9QSsY

Conversation

@CoderCoco
Copy link
Copy Markdown
Owner

Closes #64

Summary

  • Replaces the bespoke password-input + page-reload modal with a shadcn Dialog (focus trap, scroll-lock, ESC/overlay dismissal disabled), Eye/EyeOff show-hide toggle, and an external "Where do I find this?" link to a new #api-token anchor in docs/docs/setup.md.
  • Refactors api.ts so 401s park their request in a pendingRetries queue instead of returning a hanging promise; retryPendingAfterAuth() re-issues the queue with the new bearer when the operator saves a token. The dialog dismisses inline on success and surfaces an inline Invalid token — check 'app/server_config.json' or 'API_TOKEN' error if the retry comes back 401 again. No more window.location.reload().
  • Inline paste validation rejects empty / whitespace / < 16-char tokens before any network call (server still has the final say via 401).
  • Updates the e2e harness for the new flow: AuthGatePage page object now points at the new placeholder/button labels; the existing save spec is rewritten to assert inline dismissal (no reload), and two new specs cover the validation-error and second-401 paths.
  • Adds an ### API token subsection (anchor #api-token) to docs/docs/setup.md documenting precedence, generation, storage, and rotation; trims the now-stale "Save & reload" reference under the Docker section.

Test plan

  • npm run app:lint from repo root passes.
  • npm run app:build produces a working production bundle.
  • npm run app:test — full unit/integration suite stays green (274/274 locally).
  • npm run app:test:e2e — auth-gate suite passes against the production build, including the two new specs.
  • Manual sanity check: clear localStorage.apiToken, hit a protected route, paste a valid token — modal dismisses without a page reload and the dashboard renders. Repeat with a wrong token — inline 401 error appears and the modal stays open.
  • docs/docs/setup.md#api-token resolves on the published Docusaurus site.

https://claude.ai/code/session_01WjsbdUtxDJZL3GaAvhyzav


Generated by Claude Code

claude added 4 commits May 2, 2026 05:33
Replaces the page-reload-on-save flow with a shadcn Dialog that retries
the parked /api/* requests instead, surfaces an inline 401 error when
the typed token still doesn't work, and links to a new #api-token
section in the setup docs explaining where the value comes from.

Closes #64

https://claude.ai/code/session_01WjsbdUtxDJZL3GaAvhyzav
The save flow no longer reloads — the dialog dismisses inline after the
parked /api/* requests succeed on retry. Update the existing spec to
match the new placeholder/button labels and 16-char minimum, and add two
new specs covering the validation error and the second-401 inline error
paths added in this PR.

https://claude.ai/code/session_01WjsbdUtxDJZL3GaAvhyzav
# Conflicts:
#	app/packages/web/e2e/specs/auth-gate.spec.ts
Copilot AI review requested due to automatic review settings May 5, 2026 01:19
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the web dashboard’s API-token auth flow to use an in-app shadcn Dialog (with show/hide + inline validation/errors) and replaces the previous “save + reload” behavior with an inline retry mechanism that replays requests that previously failed with 401.

Changes:

  • Redesign ApiTokenModal into a blocking shadcn Dialog with show/hide toggle, inline validation, doc link, and inline 401 error messaging.
  • Refactor api.ts so 401s enqueue “pending retries” that can be replayed after a token is saved, instead of returning a never-resolving promise or forcing a full reload.
  • Update docs and Playwright e2e coverage to reflect the new inline-retry flow (including validation + second-401 paths).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
docs/docs/setup.md Adds an ### API token section and updates Docker instructions to reflect “Save” (no reload).
app/packages/web/src/components/ApiTokenModal.tsx Replaces bespoke modal with shadcn Dialog, adds show/hide, validation, inline retry + error states, and docs link.
app/packages/web/src/App.tsx Switches from conditional rendering to always rendering the dialog overlay controlled by needsToken.
app/packages/web/src/api.ts Introduces pendingRetries queue + retryPendingAfterAuth() to replay requests after auth succeeds.
app/packages/web/e2e/specs/auth-gate.spec.ts Updates existing auth-gate test for inline dismissal and adds new validation + “second 401” coverage.
app/packages/web/e2e/pages/AuthGatePage.ts Updates page object locators/semantics for the new dialog UI.

Comment thread docs/docs/setup.md Outdated
Comment on lines +298 to +303
1. **`API_TOKEN` environment variable** — wins, even when set to empty (use
this to deliberately disable auth in scripts/CI). Required when running
under `NODE_ENV=production`; the server refuses to boot otherwise.
2. **`api_token` field in `app/server_config.json`** — the persisted file
bind-mounted by `docker-compose.yml`. Edit it directly or let the
server write it via `/api/config`.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e0304fe. The bullet now reads:

API_TOKEN environment variable — takes precedence over server_config.json when set, including when set to empty. An empty value is normalized to "no token configured" and prevents the config file from being consulted, but it is not a supported way to disable auth — NODE_ENV=production startup fails when neither source supplies a non-empty token.

The second bullet also notes "Used when API_TOKEN is absent" to make the two-source resolution unambiguous.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing unit tests

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in e0304feApiTokenModal.test.tsx with 14 specs covering:

  • Dialog visibility (open true/false)
  • Password show/hide toggle
  • Inline validation: whitespace token, short token, live re-validate on input change
  • No network call when client validation fails
  • setStoredApiToken + retryPendingAfterAuth called on valid submit
  • onSuccess called when retry resolves true
  • Inline server error shown when retry resolves false; cleared on next input change
  • onSuccess not called when retry resolves false

Generated by Claude Code

- Add 14 Vitest+RTL specs covering: dialog visibility, password
  show/hide toggle, inline validation (whitespace / short token /
  live re-validate), submission → setStoredApiToken + retryPendingAfterAuth,
  onSuccess on accepted token, inline server error on 401 retry, and
  server-error cleared on input change.
- Correct the API_TOKEN bullet in docs/docs/setup.md: empty env var
  prevents the config file from being consulted but is not a supported
  way to disable auth (production startup fails either way); both
  sources satisfy the production non-empty-token requirement.

https://claude.ai/code/session_01WjsbdUtxDJZL3GaAvhyzav
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Comment thread docs/docs/setup.md Outdated
a non-empty token.
2. **`api_token` field in `app/server_config.json`** — the persisted file
bind-mounted by `docker-compose.yml`. Used when `API_TOKEN` is absent.
Edit it directly or let the server write it via `/api/config`.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — ConfigService.saveConfig() writes only the WatchdogConfig shape, so calling /api/config with an existing api_token in the file would actually clobber it. Fixed in c2e8b09:

Edit the file directly; the dashboard's /api/config endpoint only manages watchdog settings and does not write the token.


Generated by Claude Code

The previous wording suggested operators could let the server write
the token via /api/config, but ConfigService.saveConfig() only writes
watchdog fields and would actually clobber an existing api_token in
server_config.json. Spell out that the file must be edited directly.

https://claude.ai/code/session_01WjsbdUtxDJZL3GaAvhyzav
@CoderCoco CoderCoco merged commit 3ef17a1 into main May 5, 2026
8 checks passed
@CoderCoco CoderCoco deleted the claude/issue-64-9QSsY branch May 5, 2026 02:18
CoderCoco pushed a commit that referenced this pull request May 5, 2026
Resolves App.tsx/DashboardPage/CostsPage/DiscordPage/LogsPage conflicts
between the polling indicator work (#65) and the page-redesign series
that landed on main (#77, #79, #115, #116, #117).

- App.tsx now wraps the redesigned ApiTokenModal (rendered inline as a
  Dialog overlay rather than swapping the tree) inside PollingProvider
  + GameStatusProvider so polling persists across the auth-token flow.
- Each redesigned page (Dashboard, Costs, Discord, Logs) now hosts a
  PollingIndicator next to its existing header chrome (search input,
  range selector, ServerlessBadge, LIVE badge).
- LogsPage.test.tsx mounts the page through a PollingProvider wrapper
  so the new indicator can read the registry under jsdom.
- polling.spec.ts updated to use main's page-object fixtures
  (DashboardPage / AppLayout) and the redesigned STOPPED status label.
CoderCoco added a commit that referenced this pull request May 8, 2026
Closes #68

## Summary

- **Dashboard**: replaced bare "No games configured" text with a shadcn
`Card` showing a Server icon, "No games deployed" heading, a
one-paragraph Terraform explanation, and two CTA links — "Open setup
guide" (docs site) and "Edit `terraform.tfvars`" (example file on
GitHub).
- **Discord wizard**: enhanced `SetupWizard` to accept `cfg` and show
live `CheckCircle2` checkmarks as each precondition is met (client ID
set → step 1, both secrets set → step 2, interactions URL present → step
3, guild added → step 4). Wizard now shows whenever `allowedGuilds` is
empty, not only when both guilds and token are absent.
- **Watchdog**: added a `tooltip` prop to the `Field` helper and wrapped
each label with a `HelpCircle` icon + shadcn `Tooltip` carrying
plain-language help text for all three inputs.
- **API token modal**: already had the "Where do I find this?" link from
#117 — no changes needed.

## Test plan

- [ ] Unit tests: 339 passing (`npm run app:test`)
- [ ] E2e tests: 56 passing (`npm run app:test:e2e`)
- [ ] Navigate to `/` with no games configured — card with "No games
deployed", setup guide link, and `terraform.tfvars` link renders.
- [ ] Navigate to `/discord` with `allowedGuilds: []` — "Get started"
wizard renders with numbered steps.
- [ ] Configure client ID only — step 1 shows a green check, steps 2–4
remain numbered.
- [ ] Add bot token + public key — step 2 gains a green check.
- [ ] Navigate to `/settings` — hover each watchdog label to confirm
tooltip text appears.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

feat(web): redesign API token modal with show/hide, paste validation, docs link

3 participants