Frontend UX: FieldsPage selection is not deep-linkable (state-only, inconsistent with vocab/objects routing) #72

Closed
opened 2026-06-09 21:27:18 +00:00 by logaritmisk · 1 comment
Owner

web/src/fields/fields-page.tsx:15 keeps the selected field definition in plain component state:

const [selected, setSelected] = useState<FieldDefinitionView | null>(null);

Consequences:

  • reload loses the selection (back to the create form),
  • a field can't be linked/shared ("look at recording_date"),
  • back/forward don't navigate selections,
  • it's inconsistent with the rest of the app: vocabularies use /vocabularies/:id, objects use /objects/:id + query params, search uses ?q=.

Suggested fix

Either a route param (/fields/:key, matching vocabularies) or a search param (?key=…, matching the objects-table pattern of syncing via useSearchParams with { replace: true }). Route param is the better fit since selection is the page's primary state. FieldList.onSelect navigates; the page derives selected from the param + the already-cached field-defs query, and falls back to the create form when the key is absent/unknown.

Note: FieldForm is keyed by selected?.key and the page is lazy-loaded — both keep working unchanged.

`web/src/fields/fields-page.tsx:15` keeps the selected field definition in plain component state: ```tsx const [selected, setSelected] = useState<FieldDefinitionView | null>(null); ``` Consequences: - reload loses the selection (back to the create form), - a field can't be linked/shared ("look at `recording_date`"), - back/forward don't navigate selections, - it's inconsistent with the rest of the app: vocabularies use `/vocabularies/:id`, objects use `/objects/:id` + query params, search uses `?q=`. ## Suggested fix Either a route param (`/fields/:key`, matching vocabularies) or a search param (`?key=…`, matching the objects-table pattern of syncing via `useSearchParams` with `{ replace: true }`). Route param is the better fit since selection is the page's primary state. `FieldList.onSelect` navigates; the page derives `selected` from the param + the already-cached field-defs query, and falls back to the create form when the key is absent/unknown. Note: `FieldForm` is keyed by `selected?.key` and the page is lazy-loaded — both keep working unchanged.
Author
Owner

Fixed in ada5d06 (merged as 3ad0e56).

Went with the route-param option: the route is now /fields/:key? (optional segment, so /fields still renders the create form). FieldList.onSelect navigates to /fields/<key>, cancel/done navigates back to /fields, and the page derives selected from the already-cached useFieldDefinitions() query — no extra fetch, and FieldForm's key={selected?.key ?? "create"} remount behavior is unchanged.

Unknown/stale keys (including the key of a just-deleted field) fall back to the create form gracefully.

Tests: deep link opens the locked edit form, select→cancel round-trips through the URL, unknown key falls back to create. Reload/share/back-forward now all work, consistent with /vocabularies/:id.

Fixed in ada5d06 (merged as 3ad0e56). Went with the route-param option: the route is now `/fields/:key?` (optional segment, so `/fields` still renders the create form). `FieldList.onSelect` navigates to `/fields/<key>`, cancel/done navigates back to `/fields`, and the page derives `selected` from the already-cached `useFieldDefinitions()` query — no extra fetch, and `FieldForm`'s `key={selected?.key ?? "create"}` remount behavior is unchanged. Unknown/stale keys (including the key of a just-deleted field) fall back to the create form gracefully. Tests: deep link opens the locked edit form, select→cancel round-trips through the URL, unknown key falls back to create. Reload/share/back-forward now all work, consistent with `/vocabularies/:id`.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: logaritmisk/biggus-dickus#72