feat(dashboard): merge Analytics into Dashboard, remove Kanban Board

Closes issue #5 (Dashboard | Update menu & page):
- Analytics content (heatmap, sparkline, token/cost/workflow/productivity
  charts) moves into a new "Analytics" tab on the Dashboard page, alongside
  the existing Monitor/Health tabs. The standalone Analytics page, its
  /analytics route, and its sidebar menu entry are removed.
- The Kanban Board page, its /kanban route, and its sidebar menu entry are
  removed entirely (page content deleted, not just hidden).
- Updated ARCHITECTURE.md, README.md, client/README.md, docs/API.md, and
  the affected client tests/snapshots to match.
This commit is contained in:
2026-08-25 11:45:39 +07:00
parent 8c026d4cc7
commit 8ce20e8163
13 changed files with 1445 additions and 4564 deletions
+14 -25
View File
@@ -428,20 +428,18 @@ graph TD
APP["App.tsx<br/>Router + WebSocket"]
LAYOUT["Layout.tsx<br/>Sidebar + Outlet"]
SIDEBAR["Sidebar.tsx<br/>Nav (scroll-bounded with overflow<br/>chevrons) + Connection Status"]
DASH["Dashboard.tsx"]
KANBAN["KanbanBoard.tsx"]
DASH["Dashboard.tsx<br/>(Monitor / Analytics / Health tabs)"]
SESS["Sessions.tsx"]
DETAIL["SessionDetail.tsx"]
ACTIVITY["ActivityFeed.tsx"]
SETTINGS_P["Settings.tsx"]
ANALYTICS_P["Analytics.tsx"]
WORKFLOWS_P["Workflows.tsx"]
NOTFOUND["NotFound.tsx"]
APP --> LAYOUT
LAYOUT --> SIDEBAR
LAYOUT --> DASH & KANBAN & SESS & DETAIL & ACTIVITY & ANALYTICS_P & WORKFLOWS_P & SETTINGS_P & NOTFOUND
LAYOUT --> DASH & SESS & DETAIL & ACTIVITY & WORKFLOWS_P & SETTINGS_P & NOTFOUND
DASH --> SC1["StatCard x6<br/>(sessions/agents/subagents/<br/>events today/total events/cost)<br/>3-column grid"]
DASH --> AC1["AgentCard[]<br/>with collapsible subagent hierarchy"]
@@ -547,25 +545,23 @@ graph TD
EB --> TYPES
subgraph Pages
D[Dashboard]
K[KanbanBoard]
D["Dashboard<br/>(Monitor / Analytics / Health)"]
S[Sessions]
SD[SessionDetail]
AF[ActivityFeed]
AN[Analytics]
WF[Workflows]
SET[Settings]
NF[NotFound]
end
APP --> D & K & S & SD & AF & AN & WF
D & K & S & SD & AF & AN & WF --> API
D & K & S & SD & AF & AN & WF --> EB
D & K & S & SD & AF & AN & WF --> FMT
APP --> D & S & SD & AF & WF
D & S & SD & AF & WF --> API
D & S & SD & AF & WF --> EB
D & S & SD & AF & WF --> FMT
SET --> API
SET --> EB
SET --> FMT
D & K & S & AF & AN & WF --> DS
D & S & AF & WF --> DS
DS --> API
API --> TYPES
@@ -580,7 +576,6 @@ graph TD
end
D --> STC & AGC & STB
K --> AGC
S --> STB & ES
SD --> AGC & STB
AF --> STB & ES
@@ -598,12 +593,10 @@ graph TD
```mermaid
graph LR
ROOT["/ (index)"] --> DASH[Dashboard]
KANBAN_R["/kanban"] --> KANBAN[KanbanBoard]
ROOT["/ (index)"] --> DASH["Dashboard<br/>(Monitor / Analytics / Health)"]
SESS_R["/sessions"] --> SESS[Sessions]
DETAIL_R["/sessions/:id"] --> DETAIL[SessionDetail]
ACT_R["/activity"] --> ACT[ActivityFeed]
AN_R["/analytics"] --> AN[Analytics]
WF_R["/workflows"] --> WF[Workflows]
CC_R["/cc-config"] --> CC[CcConfig]
LANES_R["/lanes"] -->|redirect| RUN_R["/run"]
@@ -616,12 +609,10 @@ graph LR
| Route | Page | Data Sources |
| --------------- | ------------- | ------------------------------------------------------ |
| `/` | Dashboard | Two tabs (Monitor / Health). Monitor: `GET /api/stats`, `GET /api/agents`, `GET /api/events`, `GET /api/agents?session_id={sid}` (subagent hierarchy), dynamic item counts via `ResizeObserver`. Health: `GET /api/settings/info` + `GET /api/workflows` (5 s auto-refresh) — composite health score, storage donut, cache/error/success gauges, tool invocation bars, subagent effectiveness, model token distribution, compaction stats |
| `/kanban` | KanbanBoard | View toggle persisted in `localStorage`. Agents view: `GET /api/agents?status={each}` per-status (default 10000 cap). Sessions view: `GET /api/sessions?status={each}&limit=10000` per-status. Each column then paginates client-side at `COLUMN_PAGE_SIZE=10`; the WS subscription scopes to the active view. |
| `/` | Dashboard | Three tabs (Monitor / Analytics / Health). Monitor: `GET /api/stats`, `GET /api/agents`, `GET /api/events`, `GET /api/agents?session_id={sid}` (subagent hierarchy), dynamic item counts via `ResizeObserver`. Analytics (merged from the former standalone `/analytics` page): `GET /api/analytics` + `GET /api/pricing/cost` — event heatmap, cost/token/workflow/productivity sub-tabs. Health: `GET /api/settings/info` + `GET /api/workflows` (5 s auto-refresh) — composite health score, storage donut, cache/error/success gauges, tool invocation bars, subagent effectiveness, model token distribution, compaction stats |
| `/sessions` | Sessions | `GET /api/sessions?status=&q=&limit=PAGE_SIZE&offset=page*PAGE_SIZE` — true server-side pagination. The search box passes `q` to the server (300 ms debounced). Response carries `total` for the paginator UI. Cost computation runs server-side over the visible page only. Polls `/api/run` (and listens for `run_status`) to badge any row whose session is currently being driven from `/run` with a clickable green **▶ Run** pill |
| `/sessions/:id` | SessionDetail | `GET /api/sessions/:id` (agents + events), `GET /api/sessions/:id/stats` (overview tiles, top tools, subagent breakdown, token totals — debounced live-refresh on `new_event`/`agent_*`/`session_updated`), `GET /api/sessions/:id/transcripts` (Conversation tab transcript list), `GET /api/sessions/:id/transcript` (cursor-paginated message stream, including inline `session_event` rename markers; optional `run_id` resolves a workflow inner agent's nested transcript). Probes `/api/run` (and listens for `run_status`) to surface a green "Open in Run page" banner when this session is currently being driven by an in-flight Run handle. When the session sits in the Waiting overlay, renders a yellow waiting-for-input banner naming the `awaiting_reason` (Needs input / Turn done / At prompt / Interrupted) and how long it has waited; every Waiting `StatusBadge` across the app carries the same reason as a hover tooltip, with an inline nested chip on the wider surfaces (Sessions table, session-detail header) — compact card badges (Kanban/Dashboard) stay tooltip-only |
| `/sessions/:id` | SessionDetail | `GET /api/sessions/:id` (agents + events), `GET /api/sessions/:id/stats` (overview tiles, top tools, subagent breakdown, token totals — debounced live-refresh on `new_event`/`agent_*`/`session_updated`), `GET /api/sessions/:id/transcripts` (Conversation tab transcript list), `GET /api/sessions/:id/transcript` (cursor-paginated message stream, including inline `session_event` rename markers; optional `run_id` resolves a workflow inner agent's nested transcript). Probes `/api/run` (and listens for `run_status`) to surface a green "Open in Run page" banner when this session is currently being driven by an in-flight Run handle. When the session sits in the Waiting overlay, renders a yellow waiting-for-input banner naming the `awaiting_reason` (Needs input / Turn done / At prompt / Interrupted) and how long it has waited; every Waiting `StatusBadge` across the app carries the same reason as a hover tooltip, with an inline nested chip on the wider surfaces (Sessions table, session-detail header) — compact card badges (Dashboard) stay tooltip-only |
| `/activity` | ActivityFeed | `GET /api/events?limit=100` — click row to expand inline payload; "Session →" button navigates to `/sessions/:id` |
| `/analytics` | Analytics | `GET /api/analytics` |
| `/workflows` | Workflows | `GET /api/workflows?status=active\|completed`, `GET /api/workflows/session/:id` + WebSocket auto-refresh (3s debounce) |
| `/cc-config` | CcConfig | 12-tab Claude Code configuration explorer. Reads via `GET /api/cc-config/{overview,skills,agents,commands,output-styles,plugins,marketplaces,mcp,hooks,hook-scripts,keybindings,statusline,settings,memory}`. Mutations for skills/agents/commands/output-styles/memory — including the per-project file-based auto-memory store (`*.md` under `~/.claude/projects/<slug>/memory/`, grouped by project and searchable in the Memory tab, with clickable `MEMORY.md` index links that scroll to + highlight the matching fact file) — via `PUT /api/cc-config/file` + `DELETE /api/cc-config/file` (timestamped backups, atomic writes). The Keybindings tab additionally offers a structured inline editor that persists via `PUT /api/cc-config/keybindings` (same backup-first, atomic-write guarantees). `GET /api/cc-config/file?path=…` for single-file viewer. `GET /api/cc-config/backups` for the recovery modal. Subscribes to `cc_config_changed` WS messages for live refresh on both dashboard mutations and external file edits picked up by `cc-watcher`. The Settings tab leads with a client-side **Current configuration** summary that resolves the `/config` options (model, verbose, theme, output style, effort, auto-compact, notifications, …) across user / project / project-local scopes, showing defaults when unset. Live / Offline indicator next to the title |
| `/run` | Workspace | Merged workspace page combining lanes and runs. Attaches to a tmux-backed pseudoterminal tied to a lane: the UI selects a lane, calls `POST /api/run` with that lane's `id`, and receives a `runId` + tmux session name. The Workspace displays a horizontal lane strip at the top, the selected lane's pipeline map, and a real interactive terminal (xterm.js) fed by `/ws-pty/:runId` binary frames below. `TerminalView` re-attaches 1.5 s after any unexpected socket close (server restart included) and stops only on the server's `exit` frame — a dead socket used to leave the pane frozen on its last frame, looking live while swallowing every keystroke and mouse report. It also calls `preventDefault()` on Shift+Tab (keeping xterm's own handling): xterm emits `ESC[Z` for that combo but, unlike plain Tab, never marks the event cancelled, so the browser's default moved focus out of the terminal and the pane saw only the first press — `shift+tab to cycle` (claude's permission mode) looked dead in the browser while working in a real terminal. It also installs a custom wheel handler that returns `false`: without it, xterm falls back on an alt-screen buffer to translating each wheel notch into a cursor-key press (`ESC[A`/`ESC[B`), which a `claude` pane reads as arrow up/down and uses to walk the prompt history instead of scrolling. That handler suppresses only the emulation branch — real mouse reports are emitted by a separate listener xterm registers when the pane's program enables mouse tracking. Its xterm viewport scrollbar is hidden by design (`.xterm-viewport` rule in `client/src/index.css`): tmux repaints the whole pane, so xterm's scrollback is always empty and scrolling happens via mouse reports forwarded to the pane's program, not the DOM. Pre-flight: `GET /api/run/{tmux,binary,cwds,files}` for tmux availability + `claude` binary check + `@`-file autocomplete. Start/resume: `POST /api/run` (requires `laneId`; optionally accepts `prompt` to send immediately); `GET /api/run/:id` (returns handle); `DELETE /api/run/:id` (stops). History: `GET /api/run/history?laneId=<n>` lists only that lane's runs. PTY streaming: `/ws-pty/:runId` delivers raw PTY frames as binary WebSocket frames — no JSON envelope overhead, direct to xterm.js for live rendering; the same tmux session can have multiple simultaneous clients (browser Workspace, `ccam lanes shell` CLI, other tools), all synced live. Lane self-heal: `GET /api/lanes/:id` auto-corrects `run_id`/`status` if the tmux session has been killed externally. Tier 1 TUI parity: tmux session is a real shell, not headless — supports editors, pagers, interactive subcommands. **The console never writes a lane's stage** — stage moves only through `ccam stage` commands. Live / Offline indicator next to the title |
@@ -1852,19 +1843,17 @@ graph TD
end
subgraph "Page State"
US1["useState<br/>Dashboard"]
US2["useState<br/>KanbanBoard"]
US1["useState<br/>Dashboard<br/>(Monitor/Analytics/Health)"]
US3["useState<br/>Sessions"]
US4["useState<br/>SessionDetail"]
US5["useState<br/>ActivityFeed"]
US6["useState<br/>Analytics"]
US8["useState<br/>Workflows"]
US7["useState<br/>Settings"]
end
REST --> US1 & US2 & US3 & US4 & US5 & US6 & US8 & US7
REST --> US1 & US3 & US4 & US5 & US8 & US7
WSM --> EB
EB --> US1 & US2 & US3 & US4 & US5 & US6 & US8 & US7
EB --> US1 & US3 & US4 & US5 & US8 & US7
EB --> NOTIF_H
EB --> SAGI_H
LS --> NOTIF_H