perf(header): cap session tabs at 20; tooltip data loads on hover only

Auto-add means the strip only grows, so past 20 tabs the oldest one
leaves the working set (the newly opened tab is always the survivor).
The branch/worktree/PR/project subscriptions that feed the hover
tooltip moved into the tooltip body component, which mounts only while
the tooltip is open — a resting tab now subscribes only to its status
dot's session status and unread count.
This commit is contained in:
Bohdan Triapitsyn
2026-08-24 20:47:51 +03:00
parent 275d381bd0
commit dcacf4b3fc
4 changed files with 93 additions and 67 deletions
@@ -32,6 +32,15 @@ describe('useSessionTabsStore', () => {
expect(useSessionTabsStore.getState().tabIds).toBe(before);
});
test('caps the working set at 20, evicting the oldest tab', () => {
useSessionTabsStore.setState({ tabIds: Array.from({ length: 20 }, (_, i) => `s${i}`) });
useSessionTabsStore.getState().ensureTab('s-new');
const ids = useSessionTabsStore.getState().tabIds;
expect(ids).toHaveLength(20);
expect(ids[0]).toBe('s1');
expect(ids.at(-1)).toBe('s-new');
});
test('removeTabs drops only confirmed-gone ids and no-ops otherwise', () => {
useSessionTabsStore.setState({ tabIds: ['a', 'b'] });
const before = useSessionTabsStore.getState().tabIds;
@@ -24,6 +24,8 @@ interface SessionTabsStore {
removeTabs: (sessionIds: readonly string[]) => void;
}
const MAX_SESSION_TABS = 20;
type PersistedSessionTabs = { tabIds: string[] };
export const useSessionTabsStore = create<SessionTabsStore>()(
@@ -36,7 +38,11 @@ export const useSessionTabsStore = create<SessionTabsStore>()(
if (!sessionId) return;
const { tabIds } = get();
if (tabIds.includes(sessionId)) return;
set({ tabIds: [...tabIds, sessionId] });
// Soft cap: with auto-add the strip only ever grows, so past the cap
// the oldest tab (never the one being opened, which lands last)
// leaves the working set.
const next = [...tabIds, sessionId];
set({ tabIds: next.length > MAX_SESSION_TABS ? next.slice(next.length - MAX_SESSION_TABS) : next });
},
closeTab: (sessionId) => {