181 lines
6.6 KiB
Markdown
181 lines
6.6 KiB
Markdown
---
|
|
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
|
|
(`<origin>/data/<recordtype>/<id>`) 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
|
|
`<help-tip>` (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 `<help-tip>` 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 `<help-tip>`.
|
|
|
|
### 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: done
|
|
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: done
|
|
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 (<tr>) that wraps key in a
|
|
<help-tip> (or plain <td> if key is not in FIELD_HELP) and value in a
|
|
second <td>.
|
|
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: done
|
|
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 <table> with one row per field using fieldRow().
|
|
Title: "Token Event · {id.slice(0,8)}…".
|
|
Back link: "<a href='/token-cost'>← Token Cost</a>".
|
|
state_hub_task_id: "dc63746d-74b3-434a-925c-1cead480198f"
|
|
```
|
|
|
|
```task
|
|
id: T05
|
|
title: "Apply REF and Name columns to Token Cost page"
|
|
status: done
|
|
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/<type>/<id> URL scheme and the REF column convention.
|
|
state_hub_task_id: "107cb5bb-ff0c-4c97-af04-2cdeff11f0b2"
|
|
```
|