Frontend UX: object list should be a scannable, sortable, filterable table #44

Closed
opened 2026-06-06 18:50:53 +00:00 by logaritmisk · 1 comment
Owner

Severity: High. From a frontend UX audit. The object list is the screen curators triage in all day; today it's a thin nav list, not a data overview ("easy to get an overview of the data" is a core goal).

Problems

  • Thin single-line list, not a table. web/src/objects/object-list.tsx:63-82 renders each object as one <li> showing only object_number + object_name + a visibility badge. The list payload already carries the full AdminObjectView (current_location, current_owner, number_of_objects), so surfacing more columns is essentially free on the wire.
  • No sorting, no filtering. list_objects accepts only limit/offset (no sort/order_by/visibility). The only filter/free-text lives in a separate search-panel.tsx with a different interaction model (infinite "Load more" vs offset paging) — two parallel browsing UIs. A curator can't do "all drafts" or "sort by object number" from the list.
  • Pagination is prev/next only, LIMIT=50 hardcoded (object-list.tsx:10); no page-size selector, page jump, first/last, or keyboard paging. (The from–to of total footer is good.)
  • No recency axis: there are no created_at/updated_at fields on AdminObjectView — a backend schema gap. "What did I touch recently / what's stale" is the most common triage axis and is currently impossible.
  • No per-row quick actions and the <ul>/<li>/<a> markup isn't grid-navigable (no aria-sort, no column headers).

Suggested fixes

  • Render a real table (object number · name · visibility · current_location · count · Updated) with aligned columns and proper <table>/aria-sort semantics.
  • Add server-side sort/order_by + a visibility filter param; surface visibility filter chips and column-sort in the list. Unify the list and the search panel into one browsing surface (pick offset-paging or infinite-scroll for both).
  • Pagination controls: page-size dropdown (25/50/100/200 — backend allows 200), page jump, keyboard paging.
  • Backend: add created_at/updated_at to the object API view to back an "Updated" column + sort.

Source: frontend UX/design audit, 2026-06-06.

**Severity: High.** _From a frontend UX audit. The object list is the screen curators triage in all day; today it's a thin nav list, not a data overview ("easy to get an overview of the data" is a core goal)._ ## Problems - **Thin single-line list, not a table.** `web/src/objects/object-list.tsx:63-82` renders each object as one `<li>` showing only `object_number` + `object_name` + a visibility badge. The list payload already carries the full `AdminObjectView` (`current_location`, `current_owner`, `number_of_objects`), so surfacing more columns is essentially free on the wire. - **No sorting, no filtering.** `list_objects` accepts only `limit`/`offset` (no `sort`/`order_by`/`visibility`). The only filter/free-text lives in a *separate* `search-panel.tsx` with a different interaction model (infinite "Load more" vs offset paging) — two parallel browsing UIs. A curator can't do "all drafts" or "sort by object number" from the list. - **Pagination is prev/next only**, `LIMIT=50` hardcoded (`object-list.tsx:10`); no page-size selector, page jump, first/last, or keyboard paging. (The `from–to of total` footer is good.) - **No recency axis: there are no `created_at`/`updated_at` fields on `AdminObjectView`** — a backend schema gap. "What did I touch recently / what's stale" is the most common triage axis and is currently impossible. - **No per-row quick actions** and the `<ul>/<li>/<a>` markup isn't grid-navigable (no `aria-sort`, no column headers). ## Suggested fixes - Render a real table (object number · name · visibility · current_location · count · **Updated**) with aligned columns and proper `<table>`/`aria-sort` semantics. - Add server-side `sort`/`order_by` + a `visibility` filter param; surface visibility filter chips and column-sort in the list. **Unify** the list and the search panel into one browsing surface (pick offset-paging or infinite-scroll for both). - Pagination controls: page-size dropdown (25/50/100/200 — backend allows 200), page jump, keyboard paging. - **Backend:** add `created_at`/`updated_at` to the object API view to back an "Updated" column + sort. _Source: frontend UX/design audit, 2026-06-06._
Author
Owner

Done in 0a88a86 (merged to main). /objects is now a full-width, scannable data table: server-side sort/order + visibility filter + a Postgres q quick-filter on number/name (injection-safe — ORDER BY from a whitelisted enum, all values bound) with a correct filtered total; created_at/updated_at exposed on AdminObjectView and an Updated column (no migration — the columns already existed). All table state (sort/order/visibility/q/limit/offset) lives in the URL, so it's shareable and survives the row→detail→back round-trip. Pagination has prev/next + page-size (25/50/100/200).

Also landed the shell pieces (overlap with #58): a collapsible icon sidebar (lucide + Base UI tooltip, persisted, auto-collapse on narrow) and responsive object detail — a right pane on wide viewports / a Base UI Drawer on narrow — at a canonical, shareable /objects/:id.

Deferred to follow-ups: Meilisearch full-text unified into the table's search box (the dedicated Search screen stays for now) and the object-detail content fixes (#45).

Done in `0a88a86` (merged to `main`). `/objects` is now a full-width, scannable data table: server-side `sort`/`order` + `visibility` filter + a Postgres `q` quick-filter on number/name (injection-safe — ORDER BY from a whitelisted enum, all values bound) with a correct filtered total; `created_at`/`updated_at` exposed on `AdminObjectView` and an **Updated** column (no migration — the columns already existed). All table state (sort/order/visibility/q/limit/offset) lives in the URL, so it's shareable and survives the row→detail→back round-trip. Pagination has prev/next + page-size (25/50/100/200). Also landed the shell pieces (overlap with #58): a **collapsible icon sidebar** (lucide + Base UI tooltip, persisted, auto-collapse on narrow) and **responsive object detail** — a right pane on wide viewports / a Base UI Drawer on narrow — at a canonical, shareable **`/objects/:id`**. Deferred to follow-ups: Meilisearch full-text unified into the table's search box (the dedicated Search screen stays for now) and the object-detail *content* fixes (#45).
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#44