Skip to content

feat(tabs): grouped vertical rail from owner tab layouts - #517

Open
aakhter wants to merge 1 commit into
Ark0N:masterfrom
aakhter:pr/grouped-vertical-rail
Open

aakhter wants to merge 1 commit into
Ark0N:masterfrom
aakhter:pr/grouped-vertical-rail

Conversation

@aakhter

@aakhter aakhter commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

This is the first of a short stack that gives the vertical tab rail named groups, built on the owner tab-layout API that already shipped as backend only (GET/PUT /api/tab-layout).

It adds a small pure module, tab-layout-browser.js, that reads GET /api/tab-layout, projects the owner's groups onto the live sessions and open web tabs, and renders them as collapsible sections in the vertical rail. The browser never writes the layout in this PR. Creating, renaming and moving tabs between groups come in follow-ups.

No change for existing users. Grouping only applies when the rail is vertical and the owner has at least one group. With no layout, a failed read, zero groups, the horizontal strip, phones or the sidebar, the rail markup is byte-identical to today. A test renders the old and new code side by side and compares them.

Grouping only changes how rows are drawn.

  • sessionOrder, Alt+N, Ctrl+Tab and the palette keep reading the server-projected order.
  • Each grouped row reuses the flat row's markup, so its badge still names its Alt+N key.
  • In webview-tabs.js the only change is a small extracted renderWebviewTab(), with identical markup.

Collapse is a per-device preference in localStorage. A collapsed group always keeps the active row visible, selecting a hidden session reveals just that row, and lineage arcs to a hidden session anchor to its group header.

Drag-reorder is off in the grouped rail until grouped editing lands, because a flat-order drop can't express a move between groups.

There are no server changes, no new settings and no new SSE events. The page refreshes the layout on the existing tab:layoutChanged event (owner-scoped, newest version wins).

Tests

  • Two new test files cover the projection, the markup, collapse storage, load sequencing and the app integration, including the byte-identity check.
  • @vitest-environment jsdom currently fails on master (No such built-in module: node:), so the rail test runs the real modules in an explicit JSDOM window rather than relying on it.
  • typecheck, lint, format, frontend-syntax, public-assets, browser-excludes and build all pass, plus 28 related test files.
  • Checked in Chromium against an isolated instance: flat rail with no groups; a group created through the API appears live over SSE; collapse persists across reload; removing the group returns the exact flat markup.

Open questions for review

  • With the default activity sort, rows sort within each group, so Alt+N badges may not count 1, 2, 3 down a group.
  • Group headers are plain buttons for now; tree/treeitem semantics come in the next slice.

The vertical tab rail now reads the owner's tab layout (GET /api/tab-layout)
and draws its groups as collapsible sections. This is the first frontend
consumer of the tab-layout backend and it is read-only: nothing in the
browser writes the layout yet.

- tab-layout-browser.js (new, pure, loaded before app.js): projects the
  layout onto the live sessions and open web tabs, renders the grouped
  markup, stores collapse per device, and sequences loads newest-wins with
  a bounded retry on failure.
- app.js: loads the layout on init and on tab:layoutChanged, renders the
  grouped rail from the same per-row markup the flat rail uses, falls
  through to a full render whenever the grouping structure changes, and
  withholds drag-reorder in the grouped rail.
- Grouping is opt-in by construction. With no layout, a failed read, a
  layout without groups, or a horizontal strip, the rail renders exactly
  as before (byte-identical markup).
- Grouping is a render layer only: sessionOrder, Alt+N, Ctrl+Tab and the
  palette keep reading the server-projected order, and row badges keep
  their Alt+N slot.
- A collapsed group still shows the active row; lineage arcs to a hidden
  session anchor to its group header.
- webview-tabs.js: renderWebviewTab() extracted so a single web tab can be
  placed into its group with unchanged markup.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant