Gate resource popover store slices

Avoids subscribing the closed resource status segment to popover-only high-churn store maps.
This commit is contained in:
Neil 2026-05-21 20:35:46 -07:00 committed by GitHub
parent 98822fdf7e
commit a97191d4aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 161 additions and 5 deletions

View File

@ -32,7 +32,7 @@ import { cn } from '@/lib/utils'
import { activateAndRevealWorktree } from '@/lib/worktree-activation'
import { activateTabAndFocusPane } from '@/lib/activate-tab-and-focus-pane'
import { useAppStore } from '../../store'
import { useAllWorktrees, useWorktreeMap } from '../../store/selectors'
import { useWorktreeMap } from '../../store/selectors'
import { runWorktreeDelete } from '../sidebar/delete-worktree-flow'
import { runSleepWorktree } from '../sidebar/sleep-worktree-flow'
import { useDaemonActions, DaemonActionDialog } from '../shared/useDaemonActions'
@ -55,6 +55,12 @@ import {
isResourceSessionActivationKey,
navigateResourceSessionToTab
} from './resource-session-navigation'
import {
getResourceUsageAllWorktrees,
getResourceUsageRepos,
getResourceUsageRuntimePaneTitlesByTabId,
getResourceUsageTabsByWorktree
} from './resource-usage-open-slices'
const POLL_MS = 2_000
const SESSIONS_POLL_MS = 10_000
@ -659,16 +665,12 @@ export function ResourceUsageStatusSegment({
const fetchSnapshot = useAppStore((s) => s.fetchMemorySnapshot)
const workspaceSessionReady = useAppStore((s) => s.workspaceSessionReady)
const ptyIdsByTabId = useAppStore((s) => s.ptyIdsByTabId)
const tabsByWorktree = useAppStore((s) => s.tabsByWorktree)
const runtimePaneTitlesByTabId = useAppStore((s) => s.runtimePaneTitlesByTabId)
const setActiveView = useAppStore((s) => s.setActiveView)
const openModal = useAppStore((s) => s.openModal)
const openSpacePage = useAppStore((s) => s.openSpacePage)
const activeView = useAppStore((s) => s.activeView)
const workspaceSpaceScannedAt = useAppStore((s) => s.workspaceSpaceAnalysis?.scannedAt ?? null)
const workspaceSpaceScanning = useAppStore((s) => s.workspaceSpaceScanning)
const repos = useAppStore((s) => s.repos)
const allWorktrees = useAllWorktrees()
const activeRuntimeEnvironmentId = useAppStore(
(s) => s.settings?.activeRuntimeEnvironmentId ?? null
)
@ -684,6 +686,19 @@ export function ResourceUsageStatusSegment({
const [killConfirm, setKillConfirm] = useState<UnifiedSessionRow | null>(null)
const [killing, setKilling] = useState(false)
const [spaceScanReady, setSpaceScanReady] = useState(false)
// Why: tab titles can update on terminal keystrokes. The resource popover's
// merged tree needs them only while open, so closed status-bar badges should
// not subscribe to those high-churn maps.
const runtimePaneTitlesByTabId = useAppStore((s) =>
getResourceUsageRuntimePaneTitlesByTabId(s, open, runtimeEnvironmentActive)
)
const repos = useAppStore((s) => getResourceUsageRepos(s, open, runtimeEnvironmentActive))
const allWorktrees = useAppStore((s) =>
getResourceUsageAllWorktrees(s, open, runtimeEnvironmentActive)
)
const tabsByWorktree = useAppStore((s) =>
getResourceUsageTabsByWorktree(s, open, runtimeEnvironmentActive)
)
const previousSpaceScanningRef = useRef(workspaceSpaceScanning)
const lastSeenSpaceScanAtRef = useRef<number | null>(workspaceSpaceScannedAt)
// Why: this segment only understands the local Electron PTY/resource daemon.

View File

@ -0,0 +1,92 @@
import { describe, expect, it } from 'vitest'
import {
getResourceUsageAllWorktrees,
getResourceUsageRepos,
getResourceUsageRuntimePaneTitlesByTabId,
getResourceUsageTabsByWorktree
} from './resource-usage-open-slices'
import type { AppState } from '../../store'
const terminalTab = (id: string): AppState['tabsByWorktree'][string][number] => ({
id,
ptyId: null,
worktreeId: 'wt-1',
title: id,
customTitle: null,
color: null,
sortOrder: 0,
createdAt: 0
})
const worktree = (): AppState['worktreesByRepo'][string][number] => ({
id: 'wt-1',
repoId: 'repo-1',
path: '/repo/wt-1',
displayName: 'wt-1',
comment: '',
branch: 'main',
head: 'abc123',
isBare: false,
isMainWorktree: false,
linkedIssue: null,
linkedPR: null,
linkedLinearIssue: null,
isArchived: false,
isUnread: false,
isPinned: false,
sortOrder: 0,
lastActivityAt: 0
})
describe('resource usage open slices', () => {
it('returns stable empty slices while the popover is closed', () => {
const tabsByWorktree = { 'wt-1': [terminalTab('tab-1')] }
const runtimePaneTitlesByTabId = {
'tab-1': { 'tab-1:0': 'Working' }
} as AppState['runtimePaneTitlesByTabId']
const closedTabs = getResourceUsageTabsByWorktree({ tabsByWorktree }, false)
const closedTitles = getResourceUsageRuntimePaneTitlesByTabId(
{ runtimePaneTitlesByTabId },
false
)
expect(closedTabs).toBe(getResourceUsageTabsByWorktree({ tabsByWorktree: {} }, false))
expect(closedTitles).toBe(
getResourceUsageRuntimePaneTitlesByTabId({ runtimePaneTitlesByTabId: {} }, false)
)
expect(closedTabs).toEqual({})
expect(closedTitles).toEqual({})
})
it('returns live slices while the popover is open', () => {
const tabsByWorktree = { 'wt-1': [terminalTab('tab-1')] }
const runtimePaneTitlesByTabId = {
'tab-1': { 'tab-1:0': 'Working' }
} as AppState['runtimePaneTitlesByTabId']
expect(getResourceUsageTabsByWorktree({ tabsByWorktree }, true)).toBe(tabsByWorktree)
expect(getResourceUsageRuntimePaneTitlesByTabId({ runtimePaneTitlesByTabId }, true)).toBe(
runtimePaneTitlesByTabId
)
})
it('gates repo and worktree slices while closed or runtime-backed', () => {
const repos = [{ id: 'repo-1', path: '/repo', kind: 'git' }] as AppState['repos']
const row = worktree()
const worktreesByRepo = {
'repo-1': [row]
}
expect(getResourceUsageRepos({ repos }, false, false)).toBe(
getResourceUsageRepos({ repos: [] }, false, false)
)
expect(getResourceUsageAllWorktrees({ worktreesByRepo }, false, false)).toBe(
getResourceUsageAllWorktrees({ worktreesByRepo: {} }, false, false)
)
expect(getResourceUsageRepos({ repos }, true, true)).toEqual([])
expect(getResourceUsageAllWorktrees({ worktreesByRepo }, true, true)).toEqual([])
expect(getResourceUsageRepos({ repos }, true, false)).toBe(repos)
expect(getResourceUsageAllWorktrees({ worktreesByRepo }, true, false)).toEqual([row])
})
})

View File

@ -0,0 +1,49 @@
import type { AppState } from '../../store'
import { getAllWorktreesFromState } from '../../store/selectors'
const EMPTY_TABS_BY_WORKTREE: AppState['tabsByWorktree'] = {}
const EMPTY_RUNTIME_PANE_TITLES_BY_TAB_ID: AppState['runtimePaneTitlesByTabId'] = {}
const EMPTY_REPOS: AppState['repos'] = []
const EMPTY_WORKTREES: ReturnType<typeof getAllWorktreesFromState> = []
function shouldReadPopoverSlices(open: boolean, runtimeEnvironmentActive: boolean): boolean {
return open && !runtimeEnvironmentActive
}
export function getResourceUsageTabsByWorktree(
state: Pick<AppState, 'tabsByWorktree'>,
open: boolean,
runtimeEnvironmentActive = false
): AppState['tabsByWorktree'] {
return shouldReadPopoverSlices(open, runtimeEnvironmentActive)
? state.tabsByWorktree
: EMPTY_TABS_BY_WORKTREE
}
export function getResourceUsageRuntimePaneTitlesByTabId(
state: Pick<AppState, 'runtimePaneTitlesByTabId'>,
open: boolean,
runtimeEnvironmentActive = false
): AppState['runtimePaneTitlesByTabId'] {
return shouldReadPopoverSlices(open, runtimeEnvironmentActive)
? state.runtimePaneTitlesByTabId
: EMPTY_RUNTIME_PANE_TITLES_BY_TAB_ID
}
export function getResourceUsageRepos(
state: Pick<AppState, 'repos'>,
open: boolean,
runtimeEnvironmentActive: boolean
): AppState['repos'] {
return shouldReadPopoverSlices(open, runtimeEnvironmentActive) ? state.repos : EMPTY_REPOS
}
export function getResourceUsageAllWorktrees(
state: Pick<AppState, 'worktreesByRepo'>,
open: boolean,
runtimeEnvironmentActive: boolean
): ReturnType<typeof getAllWorktreesFromState> {
return shouldReadPopoverSlices(open, runtimeEnvironmentActive)
? getAllWorktreesFromState(state)
: EMPTY_WORKTREES
}