mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-09 00:49:41 +02:00
feat(tabs,header): group tabs by state and add header stats styles (#426)
Two directions from Discussion #426, each a per-device setting and the new default. Tab Grouping (tabGrouping: 'state' | 'none', default 'state', option C): tabs are grouped needs you (red, plus failed sessions), waiting (yellow), working and idle (also ended, exited panes and web tabs), most urgent on top. The desktop header strip draws a row per group with its label and count in a left gutter; the flat vertical rail and the sidebar draw a section per group; tablets keep their scrolling row with inline dividers; phones keep the chip row in group order without headings. Classification is the home screens' own (_mobileOverviewState/_mobileOverviewExit), the fold into four groups is pure in CodemanTabTriage (constants.js). It is flex `order` plus aria-hidden heading/break elements reconciled in place after both render paths, never a DOM reorder, so Alt+N, the keyboard walk and drag keep reading tab order; a drop is refused across groups. Named groups in the vertical rail take precedence. Header Stats Style (headerStatsStyle: 'classic' | 'compact' | 'tiles', default 'tiles', option G): tiles give WS, CPU, MEM and each plan window a label-over-value tile with a bar underneath; compact is one WS/CPU/MEM pill with sparklines plus a plan-ring pill; classic is the header as before. Desktop only (classic below 768px and in solo windows). The clustered styles move #connectionIndicator into #headerSystemStats and #planUsageChip after it, and classic moves them back to comment anchors; WS stays out of a hidden System Stats pill. The extra parts are always rendered and hidden by default in CSS, so classic is unchanged. Tests: test/tab-triage.test.ts, test/header-stats-style.test.ts; three source pins in test/tab-rail-order.test.ts follow renamed lines. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+11
-10
@@ -205,10 +205,11 @@ describe('vertical tab rail row order', () => {
|
||||
it('keeps the Alt+N badge on the tab index while the cards are sorted', () => {
|
||||
// `_tabIdx` counts the loop over sessionOrder, and only `style="order:…"`
|
||||
// moves the card — so the badge names a shortcut, not a row position.
|
||||
expect(appJs).toContain(
|
||||
'const railSortOrder = this._tabRailSortOrder(tabOrder.filter((id) => this.sessions.has(id)));'
|
||||
);
|
||||
expect(appJs).toContain('` style="order:${railSortOrder.get(id)}"`');
|
||||
// `listOrder` is the rail sort's map, or the state grouping's when that is
|
||||
// on (test/tab-triage.test.ts); either way it only sets the inline order.
|
||||
expect(appJs).toContain('const liveIds = tabOrder.filter((id) => this.sessions.has(id));');
|
||||
expect(appJs).toContain('const railSortOrder = this._tabRailSortOrder(liveIds);');
|
||||
expect(appJs).toContain('` style="order:${listOrder.get(id)}"`');
|
||||
expect(appJs).toMatch(/_tabIdx < 9 \? '<span class="tab-number">' \+ \(_tabIdx \+ 1\)/);
|
||||
// The loop itself still walks the user's order, which is what makes the
|
||||
// badge, drag-and-drop and the arrow-key walk agree with each other.
|
||||
@@ -219,12 +220,11 @@ describe('vertical tab rail row order', () => {
|
||||
// A session going working→idle never adds or removes a tab, so the full
|
||||
// rebuild is not reached — and a rebuild here would restart every card's
|
||||
// animation on every SSE tick anyway.
|
||||
expect(appJs).toContain(
|
||||
'const railSortOrder = this._tabRailSortOrder(this.sessionOrder.filter((sid) => this.sessions.has(sid)));'
|
||||
);
|
||||
expect(appJs).toContain('const liveIds = this.sessionOrder.filter((sid) => this.sessions.has(sid));');
|
||||
expect(appJs).toContain('const railSortOrder = this._tabRailSortOrder(liveIds);');
|
||||
expect(appJs).toContain('if (tab.style.order !== railOrder) tab.style.order = railOrder;');
|
||||
// An empty string is what clears the property when the rail stops sorting.
|
||||
expect(appJs).toContain("const railOrder = railSortOrder?.has(id) ? String(railSortOrder.get(id)) : '';");
|
||||
expect(appJs).toContain("const railOrder = listOrder?.has(id) ? String(listOrder.get(id)) : '';");
|
||||
});
|
||||
|
||||
it('drops the drag affordance while sorting, so a card cannot snap back', () => {
|
||||
@@ -280,9 +280,10 @@ describe('vertical tab rail sort setting', () => {
|
||||
expect(html).toContain("document.documentElement.dataset.tabRailSort='activity';");
|
||||
expect(settingsUi).toContain('root.dataset.tabRailSort = sort;');
|
||||
// A sort flip leaves orientation on 'vertical' both times, so it has to
|
||||
// count as a change of its own or nothing re-renders.
|
||||
// count as a change of its own or nothing re-renders. The same holds for a
|
||||
// grouping flip (tabGrouping, test/tab-triage.test.ts).
|
||||
expect(settingsUi).toContain(
|
||||
'const changed = orientationChanged || previousDetail !== detail || previousSort !== sort;'
|
||||
'const changed = orientationChanged || previousDetail !== detail || previousSort !== sort || previousGrouping !== grouping;'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user