feat(ui): sidebar project tree, status bar and a tabbed workbench for workspaces

The Workspace page's lane strip moves into the sidebar as a project tree:
workspaces grouped by git repository (new GET /api/projects, cached in
memory, POST /api/projects/refresh), untracked worktrees with Adopt, inline
rename, drag/Alt+arrow ordering and a right-click row menu. The selected
workspace is the URL's ?lane=, one shared lane list feeds the tree, the new
bottom status bar and the page. The Changes panel gains an activity bar
(Files / Changes / Sessions, with resume), and split panes get a header.
This commit is contained in:
2026-10-01 16:33:25 +07:00
parent 5b3884b309
commit ba2c4e1914
39 changed files with 2431 additions and 1439 deletions
+4 -1
View File
@@ -184,6 +184,8 @@ client/
│ │ ├── EventDetail.tsx # Inline hook payload viewer (used by ActivityFeed + SessionDetail)
│ │ ├── EmptyState.tsx
│ │ ├── Sidebar.tsx
│ │ ├── ProjectTree.tsx # Sidebar Projects section: workspaces grouped by repo (`GET /api/projects`), untracked worktrees + Adopt, row menu
│ │ ├── StatusBar.tsx # Fixed bottom bar: Live/Disconnected, version, running / needs-you counts, today's cost
│ │ ├── Layout.tsx
│ │ ├── RemoteSources.tsx # Remote Data Sources settings panel (SSH multi-machine collection)
│ │ ├── SessionToolBadge.tsx # The CLI that produced a non-Claude session, by its AI Tools label (nothing for Claude)
@@ -217,6 +219,7 @@ client/
│ │
│ ├── hooks/
│ │ ├── useWebSocket.ts # Auto-reconnecting WebSocket hook
│ │ ├── useLanes.ts # ONE shared lane list (GET /api/lanes + `lane_update` frames, refetch on reconnect) for the sidebar tree, status bar and Workspace page
│ │ ├── useNotifications.ts # Browser push notification triggers
│ │ └── useTheme.ts # Dark/light/system mode + per-mode named theme: `dark` class, `data-mode`, `data-theme` on <html>, persisted to localStorage
│ │
@@ -469,7 +472,7 @@ graph TB
CcConfig["/cc-config (redirect)"]
Lanes["/lanes (redirect)"]
Run["/run (redirect)"]
Workspace["/workspace"]
Workspace["/workspace?lane=<id>"]
Settings["/settings (tabs: dashboard | claude-code | ...)"]
NF["/* (NotFound)"]