TUI: group sidebar cards by project, collapsible #124

Closed
opened 2026-08-25 12:18:23 +01:00 by naps62-yolo · 0 comments
Collaborator

The web sidebar groups sessions into collapsible directory folders; the TUI renders one flat list. At more than a handful of sessions the flat list stops being scannable, and the two clients stop describing the same machine.

Give the TUI sidebar a single layer of grouping: one group row per project, its sessions as cards beneath it. Single layer means exactly that — no nesting. Where the web builds a tree and folds linear chains, the TUI groups by the same key and shows the result as one row.

Grouping key. The same rule the web uses in sessionTreePath: the worktree's base_repo when present, else the session's cwd. A worktree session lands under its repository rather than in a group of its own.

Group label. The abbreviated path from #117, matching the web exactly — ~/git.naps.pt/naps62/maestro reads ~/g/n/maestro. Style the collapsed stem dim and the last segment normal, using the palette roles. Also show the group's session count, as the web's folder rows do.

Collapsing. Group rows are collapsible and remember their state across redraws, as collapsed does in web/src/catalog.ts:19. A collapsed group hides its cards and keeps its count visible.

Navigation is where the work is. visible_sidebar_order in crates/maestro-tui/src/app.rs:884 maps j/k to a Vec<Uuid> of sessions, which no longer describes what is on screen: group rows are focusable too, since collapsing one needs a highlight to act on. The highlight becomes a position in the rendered row sequence rather than a session id, and everything reading AppState::sidebar_highlight has to follow — session_under_highlight (app.rs:403) returns nothing when a group row is highlighted, and the actions bound to a highlighted card (attach, kill, spawn similar) must do nothing rather than act on a neighbouring session. Collapsing a group that contains the highlight must leave the highlight somewhere sensible, not pointing into hidden rows.

Mouse. RegionMap resolves a click to Region::SidebarRow and the router maps the row to a session. That mapping now has to account for group rows and hidden cards; a click on a group row toggles it.

Cards stay exactly two lines each (#121), which keeps the row-to-item arithmetic tractable — one group row plus two rows per visible card. Do not reintroduce variable-height cards to make this easier.

Tests: grouping puts a worktree session under its base repo, a repo with no sessions produces no row, collapse hides cards and keeps the count, j/k walk group rows and cards in visual order, a highlighted group row yields no session for the session-scoped actions, and collapsing the group containing the highlight leaves the highlight on a visible row.

Non-goals: no filter or search box, no nesting beyond one layer, and no change to how the web groups. Sorting can follow the web's existing order rather than inventing one.

Depends on: #117, #121, #123

The web sidebar groups sessions into collapsible directory folders; the TUI renders one flat list. At more than a handful of sessions the flat list stops being scannable, and the two clients stop describing the same machine. Give the TUI sidebar a single layer of grouping: one group row per project, its sessions as cards beneath it. Single layer means exactly that — no nesting. Where the web builds a tree and folds linear chains, the TUI groups by the same key and shows the result as one row. **Grouping key.** The same rule the web uses in `sessionTreePath`: the worktree's `base_repo` when present, else the session's cwd. A worktree session lands under its repository rather than in a group of its own. **Group label.** The abbreviated path from #117, matching the web exactly — `~/git.naps.pt/naps62/maestro` reads `~/g/n/maestro`. Style the collapsed stem dim and the last segment normal, using the palette roles. Also show the group's session count, as the web's folder rows do. **Collapsing.** Group rows are collapsible and remember their state across redraws, as `collapsed` does in `web/src/catalog.ts:19`. A collapsed group hides its cards and keeps its count visible. **Navigation** is where the work is. `visible_sidebar_order` in `crates/maestro-tui/src/app.rs:884` maps `j`/`k` to a `Vec<Uuid>` of sessions, which no longer describes what is on screen: group rows are focusable too, since collapsing one needs a highlight to act on. The highlight becomes a position in the rendered row sequence rather than a session id, and everything reading `AppState::sidebar_highlight` has to follow — `session_under_highlight` (`app.rs:403`) returns nothing when a group row is highlighted, and the actions bound to a highlighted card (attach, kill, spawn similar) must do nothing rather than act on a neighbouring session. Collapsing a group that contains the highlight must leave the highlight somewhere sensible, not pointing into hidden rows. **Mouse.** `RegionMap` resolves a click to `Region::SidebarRow` and the router maps the row to a session. That mapping now has to account for group rows and hidden cards; a click on a group row toggles it. Cards stay exactly two lines each (#121), which keeps the row-to-item arithmetic tractable — one group row plus two rows per visible card. Do not reintroduce variable-height cards to make this easier. Tests: grouping puts a worktree session under its base repo, a repo with no sessions produces no row, collapse hides cards and keeps the count, `j`/`k` walk group rows and cards in visual order, a highlighted group row yields no session for the session-scoped actions, and collapsing the group containing the highlight leaves the highlight on a visible row. Non-goals: no filter or search box, no nesting beyond one layer, and no change to how the web groups. Sorting can follow the web's existing order rather than inventing one. Depends on: #117, #121, #123
naps62-yolo added this to the TUI shell milestone 2026-08-25 12:18:23 +01:00
naps62-yolo added the area/tuidifficulty/hardtype/feat labels 2026-08-25 12:18:23 +01:00
naps62-yolo added a new dependency 2026-08-25 12:18:57 +01:00
naps62-yolo added a new dependency 2026-08-25 12:18:57 +01:00
naps62-yolo added a new dependency 2026-08-25 12:22:14 +01:00
This repo is archived. You cannot comment on issues.
1 Participants
Due Date
No due date set.
Reference: naps62/maestro#124