feat(dashboard): add entity detail modal and fixed-layout tables

Replace Inputs.table() with buildEntityTable() across workstreams and
tasks pages. Add click-to-detail modal (openEntityModal) on all entity
list views: workstreams, tasks, extension points, and technical debt.

- New component: src/components/entity-modal.js
  - openEntityModal(entity, type) — full-detail overlay (Esc/click-outside to close)
  - buildEntityTable(rows, cols, onRowClick) — table-layout:fixed, overflow-safe wrapper
  - CSS injected lazily; no separate stylesheet required

- Tables: table-layout:fixed keeps content within the content column;
  title col 32%, workstream col 14%, all cells ellipsis + title tooltip
- Cards (EP, TD): onclick → modal; workstream name span gets title tooltip
- Blocked task cards also wired to modal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-27 18:28:44 +01:00
parent bd6e16394a
commit 0546a1bb2a
5 changed files with 479 additions and 36 deletions

View File

@@ -132,9 +132,10 @@ const _domainBreakdown = [...new Set(openWs.map(w => _idToDomain[w.id] ?? "unkno
# Workstreams
```js
import {injectTocTop} from "./components/toc-sidebar.js";
import {withDocHelp} from "./components/doc-overlay.js";
import "./components/help-tip.js";
import {injectTocTop} from "./components/toc-sidebar.js";
import {withDocHelp} from "./components/doc-overlay.js";
import "./components/help-tip.js";
import {openEntityModal, buildEntityTable} from "./components/entity-modal.js";
// ── Live indicator ────────────────────────────────────────────────────────────
const _liveEl = html`<div class="live-indicator">
@@ -270,14 +271,24 @@ display(Plot.plot({
```js
display(_filtersForm);
display(Inputs.table(filtered.map(w => ({
Title: w.title,
Domain: w.domain,
Status: w.status,
Owner: w.owner ?? "—",
Due: w.due_date ?? "—",
Updated: new Date(w.updated_at).toLocaleDateString(),
})), {rows: 20}));
{
// Enrich each workstream with tasks/deps data from open_workstreams summary
const _openWsMap = Object.fromEntries(openWs.map(w => [w.id, w]));
const _wsTable = buildEntityTable(
filtered,
[
{label: "Title", key: "title", cls: "et-title-col et-title-cell",
render: w => w.title},
{label: "Domain", key: "domain"},
{label: "Status", key: "status"},
{label: "Owner", render: w => w.owner ?? "—"},
{label: "Due", render: w => w.due_date ?? "—"},
{label: "Updated", render: w => new Date(w.updated_at).toLocaleDateString()},
],
w => openEntityModal({...w, ..._openWsMap[w.id]}, "workstream"),
);
display(_wsTable);
}
```
## Dependencies