feat(dashboard): entity list UX — REF column, name cells, detail pages (CUST-WP-0030)

- ref-cell.js: REF column component — click=copy deeplink, dblclick=open
- field-help.js: field registry + fieldRow helper with help-tip decoration;
  FK fields (task_id, workstream_id, repo_id) render as async-linked cells
  with entity-title bubble-help on hover
- GET /token-events/{id} endpoint + get-by-id tests
- GET /repos/by-id/{repo_id} UUID lookup endpoint
- Landing pages: /token-events/[id], /workstreams/[id], /repos/[slug], /tasks/[id]
- token-cost.md: REF + Name columns on all three tables; parallel fetch of
  workstreams/tasks for title resolution
- reference.md: entity detail page URL scheme documented

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-29 22:35:35 +02:00
parent 8a2e786111
commit 20ce332d55
15 changed files with 824 additions and 16 deletions

View File

@@ -8,7 +8,7 @@ status: done
owner: custodian
topic_slug: custodian
created: "2026-03-29"
updated: "2026-03-29"
updated: "2026-03-30"
state_hub_workstream_id: "9d8e1c33-2067-4593-a5d8-d28dda3b1d21"
---
@@ -178,3 +178,78 @@ description: >
/data/<type>/<id> URL scheme and the REF column convention.
state_hub_task_id: "107cb5bb-ff0c-4c97-af04-2cdeff11f0b2"
```
## Amendments & Improvements
Post-completion fixes and enhancements discovered during manual testing.
### A01 — amendment — Deep-link URL prefix wrong
`ref-cell.js` generated deep-links as `<origin>/data/<type>/<id>` but
Observable Framework serves pages at `/<type>/<id>` (the `src/data/`
directory is for data loaders, not pages). Fixed by removing the `/data/`
prefix from the `deepLink` construction in `ref-cell.js`. The T01
description was also inaccurate in stating the `/data/` path.
### A02 — amendment — FileAttachment rejects template literals
T04 used `` FileAttachment(`../data/token-events/${eventId}.json`) `` in
the landing page. Observable Framework requires `FileAttachment` to be
called with a single **literal** string (it processes them statically at
compile time). This caused a `SyntaxError` that also aborted the cell
defining `eventId`, cascading into a `RuntimeError: wsId is not defined`
on the next cell. Fixed by replacing all `FileAttachment` calls in landing
pages with direct `fetch(${API}/...)` calls.
### A03 — amendment — Workstream and repo landing pages missing
T04 only created a token-event landing page. The By Workplan and By Repo
tables also had REF links (to `/workstreams/<id>` and `/repos/<slug>`),
both returning 404. Added:
- `src/workstreams/[id].md` — fetches `GET /workstreams/{id}`
- `src/repos/[slug].md` — fetches `GET /repos/{slug}/`
- Corresponding unused data loaders left in `src/data/` for reference.
### A04 — amendment — Repos router uses slug, not UUID
T05 passed `repo_id` (UUID) to `refCell` for the By Repo table, but the
repos API uses slug-based routing (`GET /repos/{slug}/`). Passing a UUID
returned 404. Fixed by passing `repo_slug` to `refCell` so the deep-link
resolves correctly.
### A05 — amendment — Top Tasks refCell used wrong record type
T05 specified `"token-events"` as the record type for Top Tasks, but the
column contains `task_id` (a task UUID, not a token-event UUID), so the
landing page returned "Token event not found". Fixed by:
- Changing record type to `"tasks"` in the `refCell` call.
- Creating `src/tasks/[id].md` (fetches `GET /tasks/{task_id}`).
### I02 — improvement — Entity FK fields on detail pages link to their targets
On every detail page (token-event, task, workstream, repo), fields that hold
a foreign-key UUID (`task_id`, `workstream_id`, `repo_id`) now render as
clickable links with an async-loaded bubble-help showing the entity title.
Implementation:
- `GET /repos/by-id/{repo_id}` added to `api/routers/repos.py` — UUID
lookup needed because the existing repos router uses slug routing.
- `FIELD_LINKS` registry added to `src/components/field-help.js` mapping
each FK field to `{apiUrl, getUrl, getTitle}` resolution rules.
`getUrl` receives `(id, data)` so slug-routed entities can derive their
page URL from the fetched entity (e.g. `repo_id` → `/repos/{data.slug}`).
- `_linkCell(key, id)` helper added: renders a short-UUID link immediately,
then fetches the entity asynchronously and wraps the anchor in a
`<help-tip label="{title}" description="{type} · {full-uuid}">` once
the data arrives.
- `fieldRow` updated to dispatch to `_linkCell` whenever the field key is
in `FIELD_LINKS` and the value is non-null.
### I01 — improvement — Workstream and task Name columns show titles
T05 originally showed truncated UUIDs in the Workstream and Task name
columns (the summary data carries only IDs, not titles). Improved by
fetching `/workstreams/` and `/tasks/` in parallel with the token-event
poll and building lookup maps (`wsMap`, `taskMap`). The Name column now
displays `workstream.title` and `task.title` (truncated to 80 chars) with
the full UUID as tooltip.