diff --git a/workplans/CUST-WP-0030-dashboard-entity-list-ux.md b/workplans/CUST-WP-0030-dashboard-entity-list-ux.md new file mode 100644 index 0000000..a67e9c1 --- /dev/null +++ b/workplans/CUST-WP-0030-dashboard-entity-list-ux.md @@ -0,0 +1,180 @@ +--- +id: CUST-WP-0030 +type: workplan +title: "Dashboard Entity List UX" +domain: custodian +repo: the-custodian +status: todo +owner: custodian +topic_slug: custodian +created: "2026-03-29" +updated: "2026-03-29" +state_hub_workstream_id: "9d8e1c33-2067-4593-a5d8-d28dda3b1d21" +--- + +# Dashboard Entity List UX + +## Goal + +Make every entity table in the dashboard navigable and self-documenting. +Two new UI primitives: + +1. **REF cell** — running row number (1-based); click copies a deep-link + (`/data//`) to the clipboard; double-click opens + the link in a new tab. +2. **Name cell** — second column, titled after the record type; shows the + entity name truncated at 80 chars with full-name tooltip on hover. + +Support these cells with a landing page (`/data/[type]/[id]`) that renders +a key-value view of every field in the record, each key decorated with a +`` (one-sentence description + link to the relevant help-doc +section). + +Pilot all three features on the **Token Cost** page, then extend to other +entity tables in later workplans. + +## Background + +Current entity tables show only IDs (often truncated UUIDs) with no way to +navigate to a record detail view or discover what a field means. For a +person reviewing agent activity the tables are hard to parse. Providing a +running reference number, an entity name column, and a click-through detail +page substantially lowers the cognitive load. + +The `` custom element already exists in +`src/components/help-tip.js` and is used on several pages — the field-help +registry will reuse it as the rendering layer. + +## Implementation Plan + +The pilot targets the Token Cost page. Observable Framework supports +parameterised pages via `[param].md` file naming. The API already exposes +`GET /token-events/?task_id=…` and `GET /token-events/summary/`; a +per-record GET endpoint is needed before the landing page can work. + +### Component layer +- `src/components/ref-cell.js` — exports `refCell(index, type, id)` that + returns an `HTMLElement` with click/dblclick handlers. +- `src/components/field-help.js` — exports `FIELD_HELP` map and + `fieldRow(key, value)` helper that wraps the key in ``. + +### API layer +- `GET /token-events/{event_id}` — returns `TokenEventRead` for a single + event; needed by the landing page data loader. + +### Dashboard pages +- `src/data/token-events/[id].json.py` — data loader that calls the new + single-event endpoint; returns JSON for the landing page. +- `src/data/token-events/[id].md` — landing page: key-value table, each + row built with `fieldRow()`. +- `src/token-cost.md` — updated: REF column (refCell) and Name column + added to By Repo, By Workplan, and Top Tasks tables. + +## Tasks + +```task +id: T01 +title: "REF cell component" +status: done +priority: high +description: > + Create src/components/ref-cell.js. + Export refCell(index, recordType, id) → HTMLElement. + - Displays 1-based index as monospace text, cursor:pointer. + - Single click: copies `${location.origin}/data/${recordType}/${id}` to + clipboard; briefly flashes "Copied!" as a transient tooltip using the + existing help-tip positioning pattern. + - Double click: window.open(deeplink, '_blank'). + - No external dependencies; plain DOM. +state_hub_task_id: "8ee527cf-436b-4bab-bdb8-406314a38d99" +``` + +```task +id: T02 +title: "GET /token-events/{event_id} endpoint" +status: todo +priority: high +description: > + Add GET /token-events/{event_id} to api/routers/token_events.py. + Returns TokenEventRead (already defined in schemas/token_event.py). + 404 if not found. + No migration needed. + Add a test in tests/test_token_events.py: get by id → 200, unknown id → 404. +state_hub_task_id: "02c27d25-d744-4da0-9bcb-b40ada54d5a5" +``` + +```task +id: T03 +title: "Field-help registry" +status: todo +priority: medium +description: > + Create src/components/field-help.js. + Export FIELD_HELP: a plain object keyed by field name. + Each entry: { label, description, doc } — matches help-tip attributes. + Cover at minimum all TokenEventRead fields: + id, tokens_in, tokens_out, tokens_total, task_id, workstream_id, + repo_id, session_id, model, agent, ref_type, ref_id, note, created_at. + Export fieldRow(key, value) → HTMLElement () that wraps key in a + (or plain if key is not in FIELD_HELP) and value in a + second . + Import HelpTip from ./help-tip.js to ensure the custom element is + registered. +state_hub_task_id: "7721d884-bd70-459f-b36d-450d69aac549" +``` + +```task +id: T04 +title: "Token-event landing page" +status: todo +priority: medium +description: > + Create two files: + 1. src/data/token-events/[id].json.py — data loader. + Reads `id` from argv[1]; calls GET /token-events/{id}; + exits 1 if 404 so Observable renders an error page. + 2. src/data/token-events/[id].md — landing page. + Imports fieldRow from components/field-help.js. + Fetches FileAttachment("token-events/{id}.json").json(). + Renders an HTML with one row per field using fieldRow(). + Title: "Token Event · {id.slice(0,8)}…". + Back link: "← Token Cost". +state_hub_task_id: "dc63746d-74b3-434a-925c-1cead480198f" +``` + +```task +id: T05 +title: "Apply REF and Name columns to Token Cost page" +status: todo +priority: high +description: > + Update src/token-cost.md. + Import refCell from ./components/ref-cell.js. + For each of the three entity tables (By Repo, By Workplan, Top Tasks): + - Prepend a "REF" column using refCell(i+1, recordType, row.id). + Record types: "repos" for By Repo (using repo_id), "workstreams" for + By Workplan (using scope_id), "token-events" for Top Tasks (using + task_id — note: links to the task landing page, not a token event page, + until T04 is done; use recordType "tasks"). + - Add a Name column as the second data column: + - By Repo: repo_slug (no truncation needed, slugs are short) + - By Workplan: scope_id displayed as first 8 chars + "…" (unchanged) + → replace with workstream title if available; for now show scope_id + truncated to 36 chars with full UUID tooltip. + - Top Tasks: task_id truncated to 80 chars with full-id tooltip. + Keep all existing columns unchanged. +state_hub_task_id: "3225cc6c-2574-41e9-b8fd-e5e703a9dd7c" +``` + +```task +id: T06 +title: "Consistency gate and docs update" +status: todo +priority: low +description: > + 1. Run `cd state-hub && make test` — all token_events tests must pass. + 2. Run `make fix-consistency REPO=the-custodian`. + 3. Add a one-paragraph entry to src/docs/reference.md describing the + /data// URL scheme and the REF column convention. +state_hub_task_id: "107cb5bb-ff0c-4c97-af04-2cdeff11f0b2" +```