Commit Graph

162 Commits

Author SHA1 Message Date
logaritmisk e18cad9c6a feat(web): unsaved-changes guard (useBlocker + beforeunload) on the object form (#46)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 23:26:15 +02:00
logaritmisk 537b847acb feat(web): code-aware field errors + min count validation (#46)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 23:20:30 +02:00
logaritmisk 3900bc362c feat(web): disable submit while saving + Save & create another + Cmd/Ctrl+Enter (#46)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 23:15:21 +02:00
logaritmisk ed0c13907c refactor(web): migrate to data router (createBrowserRouter) to enable useBlocker (#46)
Convert app.tsx route tree verbatim to a module-level data router via
createRoutesFromElements + RouterProvider, and the test harness to
createMemoryRouter + RouterProvider. The search NavLink-click test now mounts
its routes as real data-router routes so RouterProvider intercepts the link
(descendant <Routes> under a catch-all let it fall through to a jsdom navigation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 23:07:03 +02:00
logaritmisk f3881e8c7c build(web): upgrade Vitest 3→4 (browser-playwright provider) (#46)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 23:03:21 +02:00
logaritmisk 6efe09d40c feat(web): assemble header — breadcrumb, search, user menu; remove standalone sign out (#54)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 19:27:43 +02:00
logaritmisk 5c8fe3cd81 feat(web): UserMenu (email/role + sign out) + HeaderSearch components (#54) 2026-06-07 19:23:43 +02:00
logaritmisk 4b55218c69 feat(web): set breadcrumb trails on all AppShell routes (#54) 2026-06-07 19:18:43 +02:00
logaritmisk af6004f731 refactor(web): remove eslint-disable from useBreadcrumb via ref (#54) 2026-06-07 19:15:03 +02:00
logaritmisk 18cb35beff feat(web): page-driven breadcrumb context + header render + objects wiring (#54)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 19:11:31 +02:00
logaritmisk dbaf22500e feat(web): ui/menu Base UI dropdown wrapper + story (#54) 2026-06-07 19:05:25 +02:00
logaritmisk 4fad3c43f0 feat(web): render configured app_name for brand + login; drop hardcoded app.name (#54)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 19:01:15 +02:00
logaritmisk 8511aebb53 feat(web): object-detail tab title, caption element fix, login title (#57)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 17:22:18 +02:00
logaritmisk 6e1f5ea50f feat(web): page <h1> + document.title on list/form routes (#57)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 17:17:01 +02:00
logaritmisk 70025e1e71 feat(web): useDocumentTitle hook (restores prior title on unmount) (#57) 2026-06-07 17:12:41 +02:00
logaritmisk 40384d91dd style(web): match ui/ no-semicolon convention in PageTitle (#57) 2026-06-07 17:11:29 +02:00
logaritmisk d3e88be70f feat(web): PageTitle h1 component + story (#57) 2026-06-07 17:09:30 +02:00
logaritmisk eead013ccd fix(web): raise dark --primary contrast to AA for button labels (#59) 2026-06-07 16:40:47 +02:00
logaritmisk 4f3db60ed2 feat(web): mount ThemeSwitch in header + pre-paint theme init (#59) 2026-06-07 16:37:04 +02:00
logaritmisk 6d17e5f84d feat(web): ThemeSwitch icon segmented control + theme.* i18n (#59) 2026-06-07 16:33:16 +02:00
logaritmisk d452dd9b35 feat(web): useTheme hook with live system tracking (#59) 2026-06-07 16:29:59 +02:00
logaritmisk e5c03383fe feat(web): theme core — resolve/read/apply tri-state theme (#59)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 16:28:21 +02:00
logaritmisk a9e6788b0b fix(web): LabelEditor preserves other-language labels on edit (#55)
Editing a term/authority/field that already had labels in other languages
silently replaced the whole multilingual set with one default-language entry.
onChange now keeps non-default-language entries; the editor shows only the
default-language label (no longer falling back to an other-language one, which
made the clear/edit path write the wrong language) and surfaces a hint when
other-language labels exist on the record.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 14:37:25 +02:00
logaritmisk 93234aae29 chore(web): add check:colors guard banning raw color utilities outside ui/ (#49)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 14:22:15 +02:00
logaritmisk cde7be9f2a refactor(web): migrate feature screens to design tokens + radius token (#49)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 14:15:54 +02:00
logaritmisk 04ed0c50e2 feat(web): indigo brand token + status tokens + Badge success/warning variants (#49)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 14:08:08 +02:00
logaritmisk 303c986d40 chore(web): raise bundle budget 180→250 KB gz (#47)
Generous ceiling so the budget stops blocking per-feature work (this is the third
raise in three frontend milestones) while still catching gross regressions. A
vendor-split / bundle audit can revisit always-loaded weight later.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 13:35:35 +02:00
logaritmisk fcad638549 feat(web): per-mutation success/error toast metadata (#47)
Declare meta on all 18 mutation hooks: meta.successMessage (toast.* key)
on every discrete user action, meta.suppressErrorToast where the consuming
component already renders the error inline. Corrected useUpdateFieldDefinition
to suppress (FieldForm renders update.isError as form.rejected inline).

Add an RTL+MSW integration test wiring the real MutationCache via
makeQueryClient() + ToastRegion: success toast, catch-all error toast, and
suppressed-no-toast. Tidy the toast Close aria-label to t("common.close")
with en/sv parity.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 12:55:54 +02:00
logaritmisk 604d4f6005 feat(web): Base UI toast region + global mutation feedback wiring (#47)
Add a module-scope Base UI toast manager bridged to the QueryClient so
every mutation can give consistent feedback. A MutationCache (extracted
into a makeQueryClient() factory for test reuse) emits a catch-all,
type-aware error toast (unless meta.suppressErrorToast) and an opt-in
success toast (meta.successMessage), reading mutation.meta + i18n.t
outside React. meta is type-checked via a react-query Register
augmentation. ToastRegion is mounted app-wide in main.tsx. Adds a toast
i18n namespace (en/sv parity) and a validated story.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 12:46:26 +02:00
logaritmisk 03d5b59b48 feat(web): readable, grouped object detail (labels, placeholders, actions toolbar) (#45)
Refactor object-detail.tsx to resolve term/authority ids to labels via
FlexibleFieldValue, group flexible fields by def.group in definition order
(ungrouped → trailing "Other"), always show core fields with "—" placeholders,
and move Edit (button-styled Link) + Delete into a right-aligned toolbar.

Move formatDate into lib/format-date.ts so the component module no longer
co-exports a non-component (clears the react-refresh/only-export-components
warning); both flexible-field-value.tsx and object-detail.tsx import it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 11:44:35 +02:00
logaritmisk 2e38af565a feat(web): FlexibleFieldValue — resolve term/authority/localized field values (#45)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 11:32:17 +02:00
logaritmisk 6a62cf64bf chore(web): drop dead objects.selectPrompt i18n key (#44)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 00:13:32 +02:00
logaritmisk c052ddc5af test(web): widen findBy timeout for the lazy/portaled narrow-drawer detail test (#44)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 00:03:46 +02:00
logaritmisk e7b0f65686 chore(web): raise bundle budget 165→180 KB gz (#44)
The collapsed-sidebar tooltips use Base UI's Tooltip, which pulls floating-ui
into the always-loaded shell chunk. Kept the richer tooltip over native title;
the index is a feature-rich admin SPA bundle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 23:58:03 +02:00
logaritmisk b8f70212a1 feat(web): responsive object detail (pane/drawer) at canonical /objects/:id (#44, #58)
Wide (>=1024px): right-hand pane beside the table with a close control.
Narrow: Base UI Drawer sliding from the right (lazy-loaded so its code splits
out of the main chunk). Both preserve the table's query string on close.

Remove the index SelectPrompt route (the table is the landing view) and delete
the now-unused SelectPrompt. Make table rows keyboard-activatable
(role=link, tabIndex, Enter).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 23:53:10 +02:00
logaritmisk 184e4ea2a5 feat(web): collapsible icon sidebar (persisted, auto-collapse on narrow) (#44, #58)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 23:44:40 +02:00
logaritmisk 04c33cb1aa feat(web): useMediaQuery hook + Base UI tooltip wrapper (#44)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 23:40:19 +02:00
logaritmisk 49f694d1fb feat(web): full-width sortable/filterable objects table with URL state (#44)
Replace the narrow ObjectList with a full-width ObjectsTable whose state
(sort/order/q/visibility/limit/offset) lives entirely in the URL via
useSearchParams. Sortable headers toggle sort+dir with aria-sort, a
debounced quick-filter and visibility chips mirror the search-panel
pattern, and a pagination footer offers prev/next + page-size select.
Rows deep-link to /objects/:id preserving the query string.

useObjectsPage now takes an ObjectListParams object (sort/order/
visibility/q) with keepPreviousData. ObjectsPage renders the table as
the full-width landing view, surfacing the nested <Outlet/> detail as a
simple right-side panel only when a :id child route is active (Phase 3
makes this responsive). object-list.tsx and its test are removed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 23:34:13 +02:00
logaritmisk 98c00d3732 chore(web): regenerate API types (object list params + timestamps) (#44)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 23:24:42 +02:00
logaritmisk 4267aae4e5 chore(web): raise bundle budget 150→165 KB gz (#27)
The index chunk is a feature-rich admin SPA bundle (Base UI + TanStack Query +
react-hook-form + i18n); 150 KB was set early and now trips on most features.
The combobox itself lands in the lazy object-form chunk.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 10:59:12 +02:00
logaritmisk c84b84b153 feat(web): use searchable combobox for term/authority fields on the object form (#27) 2026-06-06 10:41:28 +02:00
logaritmisk 0188e730e8 feat(web): searchable combobox (Base UI) for term/authority options (#27) 2026-06-06 10:37:01 +02:00
logaritmisk c9120848f5 feat(web): edit/delete authorities in place (#30) 2026-06-05 20:35:26 +02:00
logaritmisk 83ca506702 feat(web): rename vocabularies + edit/delete terms in place (#30) 2026-06-05 20:32:35 +02:00
logaritmisk 65ca79f2bd feat(web): edit/delete field definitions on /fields (in-place edit pane) (#36) 2026-06-05 20:24:57 +02:00
logaritmisk 194f18c8ed feat(web): reusable DeleteConfirmDialog with in-use handling + stories 2026-06-05 20:12:23 +02:00
logaritmisk 282e6430d4 feat(web): mutation hooks + InUseError + i18n for reference-data edit/delete 2026-06-05 20:06:23 +02:00
logaritmisk 78c950d2ee chore(web): regenerate API types for reference-data edit/delete
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 20:04:03 +02:00
logaritmisk b2d026f217 feat(web): set up Storybook (preview + MSW + stories for real components) 2026-06-05 16:55:40 +02:00
logaritmisk e6fc3eaf2c build(web): pin pnpm via packageManager + align CI to pnpm 11 (#26)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 15:50:40 +02:00