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 acb30978cd
commit b28298a2ec
14 changed files with 748 additions and 15 deletions

View File

@@ -326,6 +326,17 @@ async def get_repo_doi(
)
@router.get("/by-id/{repo_id}", response_model=RepoRead)
async def get_repo_by_id(
repo_id: uuid.UUID,
session: AsyncSession = Depends(get_session),
) -> ManagedRepo:
repo = await session.get(ManagedRepo, repo_id)
if repo is None:
raise HTTPException(status_code=404, detail=f"Repo '{repo_id}' not found")
return repo
@router.get("/{slug}/", response_model=RepoRead)
async def get_repo(
slug: str,

View File

@@ -166,6 +166,17 @@ async def get_tokens_by_repo(
]
@router.get("/{event_id}", response_model=TokenEventRead)
async def get_token_event(
event_id: uuid.UUID,
session: AsyncSession = Depends(get_session),
) -> TokenEvent:
event = await session.get(TokenEvent, event_id)
if event is None:
raise HTTPException(status_code=404, detail="Token event not found")
return event
@router.get("/", response_model=list[TokenEventRead])
async def list_token_events(
task_id: uuid.UUID | None = None,