feat(sidebar): add single-project display mode

This commit is contained in:
Bohdan Triapitsyn
2026-08-21 16:25:51 +03:00
parent bbb2fdbe19
commit b879cf323f
30 changed files with 557 additions and 61 deletions
@@ -5,6 +5,7 @@
- `SessionSidebar.tsx` now acts mainly as orchestration; core logic moved to focused hooks/components.
- Layout (web/desktop): top navigation (`SidebarNav`: New session, Scheduled, Multi-run, Archive), then the `recent` zone, then one zone per project with a **flat** session list. There is no rendered worktree grouping level.
- **Two grouping display modes** (`useSessionDisplayStore.sessionGroupingMode`, toggled in the view dropdown): `'by-worktree'` (default) renders the worktree-grouped `sectionsForRender` with slim PR-aware branch sub-headers inside each project zone; `'flat'` renders `flatSectionsForRender` — one merged non-archived group per project (`id: 'flat'`, `folderScopes` listing every contributing scope) with per-row branch markers. Both derive from the same `projectSections` data layer, which alone feeds bootstrap demand planning and PR polling.
- **Project display is independent from grouping.** `'all'` keeps every project zone; `'single'` is web/desktop/PWA-only and renders one selected project under the always-present Chats section. Its project header is a non-collapsible picker ordered by the current project sort. Recent and collapse/expand-all controls are hidden without changing their persisted preferences. Opening a materialized project session updates the picker from the session's confirmed directory; changing only a draft target does not. In `'single'` + `'flat'`, active sessions reveal in batches of 20. `'single'` + `'by-worktree'` retains the ordinary per-group limits. Project display mode, session grouping, project sort, and the Recent preference are server-backed shared settings with the hydrated browser store as the migration/failure cache. The selected single project and sticky-header preference remain device-local.
- When sticky zone headers are enabled, project headers are sticky "zone" bands (`SortableProjectItem`); on a vibrant desktop the scrolling content fades behind an unmasked, non-interactive copy of the stuck icon/title without painting a background. The transparent fade zone blocks interaction with obscured rows. The `recent` section uses the same overlay while it is the leading sticky header. Collapsed projects show an aggregated busy/unseen indicator (`ProjectAggregateStatusIndicator`), derived from the live status index and notification store scoped to the project's directories.
- **Activity is a dot plus a counter, never a spinner.** The row's left gutter shows a static dot — primary while the session runs (`busy`/`retry`), info while it is unread — and the metadata slot on the right swaps the goal/branch/date group for the elapsed time of the turn (`SessionActivityDuration`, ticking once per second). The readout takes the dot's color in each state — primary while running, info once it is waiting to be read — so the pair reads as one indicator. A running spinner repainted a composited layer per row every frame for the whole turn; the counter conveys the same "something is happening" at 1 fps. The counter follows the unread marker's lifetime exactly: it survives the turn ending, disappears when the session is read, and never lingers on the session being watched (which is marked read as it goes idle). Aggregate indicators for collapsed groups, folders, and projects show the dot only — a group may hold several running turns, so a single counter would have nothing to count. The same treatment applies to the mobile sessions sheet and session switcher rows. The worktree-move indicator stays a spinner: it marks a short user-initiated operation, not a session state.
- Session rows have a single layout (former `minimal`); the `default`/`minimal` display mode was removed (`session-display-mode` store v4 migration drops the key). Rows show an inline branch label (from `node.worktree` or recent's `secondaryMeta`) when the session lives outside the project root, and bold titles while unread.