Commit Graph

33 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 5c8fe3cd81 feat(web): UserMenu (email/role + sign out) + HeaderSearch components (#54) 2026-06-07 19:23:43 +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 6d17e5f84d feat(web): ThemeSwitch icon segmented control + theme.* i18n (#59) 2026-06-07 16:33:16 +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 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 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 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 282e6430d4 feat(web): mutation hooks + InUseError + i18n for reference-data edit/delete 2026-06-05 20:06:23 +02:00
logaritmisk 0c9db7bcdb feat(web): highlight the offending field on a set_fields 422 (#28)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 15:39:49 +02:00
logaritmisk 9d0475e8ec feat(web): single-language content authoring (LabelEditor + localized_text at default lang)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 15:05:20 +02:00
logaritmisk ff513e1712 fix(web): search 503 vs error (#34); terms/authorities list error states (#31); authority-tab a11y + dead keys (#32); authority-kind test (#37) 2026-06-04 17:28:01 +02:00
logaritmisk fd1c22191b polish(web): fields form resets error, shared labelText, drop dead nav.soon, a11y required marker, Other group last
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 14:29:25 +02:00
logaritmisk 37c80121ed feat(web): /fields two-pane screen (grouped list + create form) + nav (no stubs left)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 14:22:57 +02:00
logaritmisk 4dd00362b8 polish(web): search pill aria-pressed, keepPreviousData, plural result count, URL-hydration test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 12:47:38 +02:00
logaritmisk 358d793e44 feat(web): /search two-pane screen (debounced query, visibility filter, load more) + nav
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 12:40:46 +02:00
logaritmisk 38673e52ba feat(web): authorities kind-tabbed screen (list/create) + nav
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 09:32:57 +02:00
logaritmisk ac30eadbb2 feat(web): vocabularies two-pane screen (list/create + terms/add) + nav
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 09:22:38 +02:00
logaritmisk 8d2323ed95 feat(web): shared sv/en LabelEditor
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 09:14:16 +02:00
logaritmisk 39b7fc51e9 feat(web): PublishControl stepper (legal one-step moves, confirm-on-public, gate/illegal errors)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 08:35:02 +02:00
logaritmisk 5087e34280 feat(web): delete object with confirm dialog
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 01:00:57 +02:00
logaritmisk 9880f24dd2 feat(web): nested object routes + in-pane edit form + edit flow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 00:54:02 +02:00
logaritmisk 30d851182e feat(web): new-object full-width page + create flow + /objects/new
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 00:46:49 +02:00
logaritmisk 616c232a22 feat(web): ObjectForm (core + dynamic flexible fields, RHF, validation)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 00:40:19 +02:00
logaritmisk cb191225cc feat(web): dynamic FieldInput (text/integer/date/boolean/localized_text/term/authority)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 00:31:05 +02:00
logaritmisk 478b4ce44e feat(web): i18n with react-i18next (sv/en)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 22:42:47 +02:00