Storybook 10.4.2 (react-vite) with the addon-vitest/a11y/docs/mcp addons.
.storybook/preview.tsx wired to the real provider tree (QueryClient + ConfigProvider
+ MemoryRouter), real CSS + i18n, and MSW reusing src/test/handlers.ts. 8 colocated
stories for real components (Button/Badge/Input/Checkbox/VisibilityBadge/LabelEditor/
Highlight/SearchResultRow) incl. one CssCheck. Boilerplate removed.
112 web tests (existing 85 survived + 27 storybook); typecheck/lint/build clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#38 enum-type SearchHitView.visibility + tighten VisibilityBadge prop.
#28 set_fields 422 carries the offending field (FieldErrorView); the object form
highlights it (both direct-edit and create-redirect paths name the field).
#41 normalize localized_text values to the default language on save.
#26 pin pnpm via packageManager + align CI to pnpm 11.
85 web tests; api suite green; bundle 145.8 KB gz; en/sv parity.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DEFAULT_LANGUAGE/DEFAULT_TIMEZONE env config surfaced via public GET /api/config;
SPA config provider defaults the UI language from the instance (overridable per
browser). Content authoring collapsed to a single language (LabelEditor +
localized_text) at the instance default. The multilingual content SCHEMA is left
completely untouched (dormant) — re-enabling is UI-only, zero migration. Storage
stays UTC; timezone exposed for future display/PDF use.
81 web tests; full backend green; bundle 145.7 KB gz; en/sv parity 106/106.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Keep the multilingual content schema (dormant); simplify authoring inputs to one
language. Default language + timezone via env vars (no settings table). Public
/api/config endpoint surfaces them to the SPA. Per-account UI language deferred.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per WAI-ARIA, aria-selected must be on the same element carrying role="tab".
The previous impl placed it on an inner <span> via the render-prop, making it
invisible to assistive technology. Move both role="tab" and aria-selected to
the NavLink, compute currentKind once from useParams, drop the render-prop.
Add a Vitest assertion that the selected tab has aria-selected="true" and an
unselected tab has aria-selected="false".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Single docker compose (Postgres + Meilisearch) for dev and tests. .env.example
now works out-of-the-box (SESSION_COOKIE_SECURE=false for http://localhost login;
MEILI_* matching compose).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
POST /api/admin/field-definitions (EditCatalogue) over the existing db layer,
validated through FieldType::from_parts (422 on inconsistent type/binding),
dup key -> 409, nonexistent vocabulary / empty key -> 422. /fields two-pane
screen: grouped list + create form with conditional vocabulary/authority-kind
selects, reused LabelEditor; creating a field invalidates the shared
[field-definitions] cache so it appears in the object editor too. Fields nav
enabled — no disabled nav stubs remain.
api tests green (8 admin_fields + suite); web 72 tests; bundle 145.4 KB gz.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>