The delete dialogs (DeleteObjectDialog and the shared
DeleteConfirmDialog) left their confirm button enabled during the
in-flight request, so a double-click fired a second DELETE that 404'd
and surfaced a spurious error. Disable cancel + confirm while pending
and swap the confirm label to a new actions.deleting ("Deleting…" /
"Tar bort…").
The login button disabled itself during login.isPending but kept the
"Sign in" label; it now shows auth.signingIn ("Signing in…" /
"Loggar in…") so slow networks get visible feedback.
Each fix is covered by a gated-MSW (or gated-promise) test asserting
the pending label + disabled state before releasing the request.
Closes#70
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keyboard focus was invisible on the objects-table sort headers and
page-size select, breadcrumb links, the external-URI link, and the
combobox input/clear/trigger. Apply the shared focusRing helper in app
code and the kit's inline focus-visible classes (matching input.tsx)
in ui/combobox.
Make the search result count a role="status" live region so screen
readers announce updated counts while typing; the existing search test
now asserts the count through getByRole("status").
Closes#69
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tooltip, toast, and combobox popups still hardcoded light colors
(bg-white, neutral-*, indigo-50) and rendered as white boxes in dark
mode; the objects-table page-size select did the same in app code.
Swap all of them to theme tokens (popover/accent/muted/destructive/
success) and replace the toast's literal "×" with the lucide X icon.
Wire browser chrome into the theme: color-scheme via CSS on
:root/.dark (follows the in-app toggle, not just the OS), a
theme-color meta kept in sync by the preload script and applyTheme(),
plus a unit test for the meta sync.
Extend check-no-raw-colors to also flag shadeless white/black
utilities outside components/ui/ so the objects-table case can't
recur.
Closes#68
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Same timing-window race as object-new-page: the 50ms delay let the logout
resolve (menu unmounts on me=null) before findByText caught 'Signing out…'
on the slow CI runner. Hold the logout open with a promise released only
after the pending state is asserted.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 'narrow: detail renders inside a portaled drawer' test lazy-loads the
drawer chunk and exceeded the 5s default on the slow CI container (setup
alone took ~486s). Bump testTimeout on both vitest projects.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- CI runs the @vitest/browser-playwright (storybook) project, which needs the
chromium browser downloaded — add 'playwright install --with-deps chromium'.
- object-new-page in-flight test held the create mutation open with a 50ms
delay and raced the pending-state assertion (failed under CI timing); gate it
on a promise released only after asserting 'saving…', so it's deterministic.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds web/GUARDRAILS.md capturing the recurring CI-guardrail and
test-harness lessons in one place: the check:size (250 KB-gz largest
chunk) and check:colors (design-token) guards, the jsdom/storybook
vitest split, MSW onUnhandledRequest:"error" overrides, RTL
accessible-name collisions, Storybook nested-router/portal handling,
and the components/ui code-style split. Wires a pointer from CLAUDE.md.
All claims verified against the live scripts, ci.yaml, and src/test/.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>