mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
perf: reduce redundant sidebar agent status subscriptions (#29840)
* perf: reduce sidebar agent status subscription work * test: align sidebar store mocks with subscription API --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
@@ -20,38 +20,43 @@ const sleepMocks = vi.hoisted(() => ({
|
||||
let worktreeCardProperties: WorktreeCardProperty[] = ['status', 'comment']
|
||||
let settings: Partial<GlobalSettings> | null = null
|
||||
|
||||
vi.mock('@/store', () => ({
|
||||
useAppStore: (selector: (state: unknown) => unknown) =>
|
||||
selector({
|
||||
browserTabsByWorktree: {},
|
||||
createBrowserTab: vi.fn(),
|
||||
deleteFolderWorkspace: vi.fn(),
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch: vi.fn(),
|
||||
fetchIssue: vi.fn(),
|
||||
fetchLinearIssue: vi.fn(),
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
openTaskPage: vi.fn(),
|
||||
projectGroups: [],
|
||||
ptyIdsByTabId: {},
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
renamingWorktreeId: null,
|
||||
setActiveWorktree: vi.fn(),
|
||||
setRemoteBrowserPageHandle: vi.fn(),
|
||||
setRenamingWorktreeId,
|
||||
settings,
|
||||
sshConnectionStates: new Map(),
|
||||
sshTargetLabels: new Map(),
|
||||
tabsByWorktree: {},
|
||||
updateWorktreeMeta,
|
||||
workspacePortScan: null,
|
||||
worktreeCardProperties
|
||||
vi.mock('@/store', () => {
|
||||
const getState = () => ({
|
||||
browserTabsByWorktree: {},
|
||||
createBrowserTab: vi.fn(),
|
||||
deleteFolderWorkspace: vi.fn(),
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch: vi.fn(),
|
||||
fetchIssue: vi.fn(),
|
||||
fetchLinearIssue: vi.fn(),
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
openTaskPage: vi.fn(),
|
||||
projectGroups: [],
|
||||
ptyIdsByTabId: {},
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
renamingWorktreeId: null,
|
||||
setActiveWorktree: vi.fn(),
|
||||
setRemoteBrowserPageHandle: vi.fn(),
|
||||
setRenamingWorktreeId,
|
||||
settings,
|
||||
sshConnectionStates: new Map(),
|
||||
sshTargetLabels: new Map(),
|
||||
tabsByWorktree: {},
|
||||
updateWorktreeMeta,
|
||||
workspacePortScan: null,
|
||||
worktreeCardProperties
|
||||
})
|
||||
return {
|
||||
useAppStore: Object.assign((selector: (state: unknown) => unknown) => selector(getState()), {
|
||||
getState,
|
||||
subscribe: () => () => {}
|
||||
})
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/components/ui/hover-card', () => ({
|
||||
HoverCard: ({ children }: { children: ReactNode }) => <>{children}</>,
|
||||
|
||||
@@ -23,33 +23,38 @@ let worktreesByRepo: Record<string, Worktree[]> = {}
|
||||
let worktreeCardProperties: WorktreeCardProperty[] = ['status']
|
||||
let deleteStateByWorktreeId: Record<string, { isDeleting: boolean; error: string | null }> = {}
|
||||
|
||||
vi.mock('@/store', () => ({
|
||||
useAppStore: (selector: (state: unknown) => unknown) =>
|
||||
selector({
|
||||
deleteStateByWorktreeId,
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
fetchLinearIssue,
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
runtimeEnvironments,
|
||||
runtimeStatusByEnvironmentId,
|
||||
removedSshTargetLabels,
|
||||
settings: null,
|
||||
sshConnectionStates,
|
||||
sshStateByEnvironment,
|
||||
sshTargetLabels,
|
||||
sshTargetsHydrated: true,
|
||||
updateWorktreeMeta,
|
||||
worktreesByRepo,
|
||||
worktreeCardProperties
|
||||
vi.mock('@/store', () => {
|
||||
const getState = () => ({
|
||||
deleteStateByWorktreeId,
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
fetchLinearIssue,
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
runtimeEnvironments,
|
||||
runtimeStatusByEnvironmentId,
|
||||
removedSshTargetLabels,
|
||||
settings: null,
|
||||
sshConnectionStates,
|
||||
sshStateByEnvironment,
|
||||
sshTargetLabels,
|
||||
sshTargetsHydrated: true,
|
||||
updateWorktreeMeta,
|
||||
worktreesByRepo,
|
||||
worktreeCardProperties
|
||||
})
|
||||
return {
|
||||
useAppStore: Object.assign((selector: (state: unknown) => unknown) => selector(getState()), {
|
||||
getState,
|
||||
subscribe: () => () => {}
|
||||
})
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/lib/worktree-activation', () => ({
|
||||
activateAndRevealWorktree: vi.fn()
|
||||
|
||||
@@ -20,28 +20,33 @@ let worktreeCardProperties: WorktreeCardProperty[] = []
|
||||
let settings: Partial<GlobalSettings> | null = null
|
||||
const WORKTREE_CARD_IMPORT_TIMEOUT_MS = 15_000
|
||||
|
||||
vi.mock('@/store', () => ({
|
||||
useAppStore: (selector: (state: unknown) => unknown) =>
|
||||
selector({
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
fetchLinearIssue,
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings,
|
||||
sshConnectionStates: new Map(),
|
||||
sshTargetLabels: new Map(),
|
||||
updateWorktreeMeta,
|
||||
workspacePortScan: null,
|
||||
worktreeCardProperties
|
||||
vi.mock('@/store', () => {
|
||||
const getState = () => ({
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
fetchLinearIssue,
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings,
|
||||
sshConnectionStates: new Map(),
|
||||
sshTargetLabels: new Map(),
|
||||
updateWorktreeMeta,
|
||||
workspacePortScan: null,
|
||||
worktreeCardProperties
|
||||
})
|
||||
return {
|
||||
useAppStore: Object.assign((selector: (state: unknown) => unknown) => selector(getState()), {
|
||||
getState,
|
||||
subscribe: () => () => {}
|
||||
})
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/lib/worktree-activation', () => ({
|
||||
activateAndRevealWorktree: vi.fn()
|
||||
|
||||
@@ -17,34 +17,39 @@ let worktreeCardProperties: WorktreeCardProperty[] = ['status']
|
||||
let root: Root | null = null
|
||||
let container: HTMLDivElement | null = null
|
||||
|
||||
vi.mock('@/store', () => ({
|
||||
useAppStore: (selector: (state: unknown) => unknown) =>
|
||||
selector({
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
fetchLinearIssue,
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache: {
|
||||
'local::repo-1::feature/branch': {
|
||||
data: null,
|
||||
fetchedAt: Date.now(),
|
||||
linkedReviewHintKey: ''
|
||||
}
|
||||
},
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings: { experimentalNewWorktreeCardStyle: true },
|
||||
sshConnectionStates: new Map(),
|
||||
sshTargetLabels: new Map(),
|
||||
updateWorktreeMeta,
|
||||
workspacePortScan: null,
|
||||
worktreeCardProperties
|
||||
vi.mock('@/store', () => {
|
||||
const getState = () => ({
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
fetchLinearIssue,
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache: {
|
||||
'local::repo-1::feature/branch': {
|
||||
data: null,
|
||||
fetchedAt: Date.now(),
|
||||
linkedReviewHintKey: ''
|
||||
}
|
||||
},
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings: { experimentalNewWorktreeCardStyle: true },
|
||||
sshConnectionStates: new Map(),
|
||||
sshTargetLabels: new Map(),
|
||||
updateWorktreeMeta,
|
||||
workspacePortScan: null,
|
||||
worktreeCardProperties
|
||||
})
|
||||
return {
|
||||
useAppStore: Object.assign((selector: (state: unknown) => unknown) => selector(getState()), {
|
||||
getState,
|
||||
subscribe: () => () => {}
|
||||
})
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/lib/sidebar-worktree-activation', () => ({
|
||||
activateWorktreeFromSidebar: vi.fn()
|
||||
|
||||
@@ -14,27 +14,32 @@ const updateWorktreeMeta = vi.fn()
|
||||
let worktreeCardProperties: WorktreeCardProperty[] = []
|
||||
const WORKTREE_CARD_IMPORT_TIMEOUT_MS = 15_000
|
||||
|
||||
vi.mock('@/store', () => ({
|
||||
useAppStore: (selector: (state: unknown) => unknown) =>
|
||||
selector({
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
fetchLinearIssue,
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings: null,
|
||||
sshConnectionStates: new Map(),
|
||||
sshTargetLabels: new Map(),
|
||||
updateWorktreeMeta,
|
||||
worktreeCardProperties
|
||||
vi.mock('@/store', () => {
|
||||
const getState = () => ({
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
fetchLinearIssue,
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings: null,
|
||||
sshConnectionStates: new Map(),
|
||||
sshTargetLabels: new Map(),
|
||||
updateWorktreeMeta,
|
||||
worktreeCardProperties
|
||||
})
|
||||
return {
|
||||
useAppStore: Object.assign((selector: (state: unknown) => unknown) => selector(getState()), {
|
||||
getState,
|
||||
subscribe: () => () => {}
|
||||
})
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/lib/worktree-activation', () => ({ activateAndRevealWorktree: vi.fn() }))
|
||||
|
||||
|
||||
@@ -19,29 +19,34 @@ let hostedReviewCache: Record<string, unknown> = {}
|
||||
let prCache: Record<string, unknown> = {}
|
||||
let settings: Partial<GlobalSettings> | null = null
|
||||
|
||||
vi.mock('@/store', () => ({
|
||||
useAppStore: (selector: (state: unknown) => unknown) =>
|
||||
selector({
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
fetchLinearIssue,
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache,
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
prCache,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings,
|
||||
sshConnectionStates: new Map(),
|
||||
sshTargetLabels: new Map(),
|
||||
updateWorktreeMeta,
|
||||
workspacePortScan: null,
|
||||
worktreeCardProperties
|
||||
vi.mock('@/store', () => {
|
||||
const getState = () => ({
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
fetchLinearIssue,
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache,
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
prCache,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings,
|
||||
sshConnectionStates: new Map(),
|
||||
sshTargetLabels: new Map(),
|
||||
updateWorktreeMeta,
|
||||
workspacePortScan: null,
|
||||
worktreeCardProperties
|
||||
})
|
||||
return {
|
||||
useAppStore: Object.assign((selector: (state: unknown) => unknown) => selector(getState()), {
|
||||
getState,
|
||||
subscribe: () => () => {}
|
||||
})
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/lib/worktree-activation', () => ({
|
||||
activateAndRevealWorktree: vi.fn()
|
||||
|
||||
@@ -16,28 +16,33 @@ let worktreeCardProperties: WorktreeCardProperty[] = []
|
||||
let settings: Partial<GlobalSettings> | null = null
|
||||
const WORKTREE_CARD_IMPORT_TIMEOUT_MS = 15_000
|
||||
|
||||
vi.mock('@/store', () => ({
|
||||
useAppStore: (selector: (state: unknown) => unknown) =>
|
||||
selector({
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
fetchLinearIssue,
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings,
|
||||
sshConnectionStates: new Map(),
|
||||
sshTargetLabels: new Map(),
|
||||
updateWorktreeMeta,
|
||||
workspacePortScan: null,
|
||||
worktreeCardProperties
|
||||
vi.mock('@/store', () => {
|
||||
const getState = () => ({
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
fetchLinearIssue,
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings,
|
||||
sshConnectionStates: new Map(),
|
||||
sshTargetLabels: new Map(),
|
||||
updateWorktreeMeta,
|
||||
workspacePortScan: null,
|
||||
worktreeCardProperties
|
||||
})
|
||||
return {
|
||||
useAppStore: Object.assign((selector: (state: unknown) => unknown) => selector(getState()), {
|
||||
getState,
|
||||
subscribe: () => () => {}
|
||||
})
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/lib/worktree-activation', () => ({
|
||||
activateAndRevealWorktree: vi.fn()
|
||||
|
||||
@@ -24,28 +24,33 @@ let workspaceDeleteModifierPressed = false
|
||||
let gitConflictOperationByWorktree: Record<string, GitConflictOperation> = {}
|
||||
let WorktreeCard: typeof WorktreeCardComponent
|
||||
|
||||
vi.mock('@/store', () => ({
|
||||
useAppStore: (selector: (state: unknown) => unknown) =>
|
||||
selector({
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
gitConflictOperationByWorktree,
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
openModal,
|
||||
projectGroups,
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings,
|
||||
sshConnectionStates: new Map(),
|
||||
sshTargetLabels: new Map(),
|
||||
browserTabsByWorktree,
|
||||
ptyIdsByTabId,
|
||||
tabsByWorktree,
|
||||
updateWorktreeMeta,
|
||||
worktreeCardProperties
|
||||
vi.mock('@/store', () => {
|
||||
const getState = () => ({
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
gitConflictOperationByWorktree,
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
openModal,
|
||||
projectGroups,
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings,
|
||||
sshConnectionStates: new Map(),
|
||||
sshTargetLabels: new Map(),
|
||||
browserTabsByWorktree,
|
||||
ptyIdsByTabId,
|
||||
tabsByWorktree,
|
||||
updateWorktreeMeta,
|
||||
worktreeCardProperties
|
||||
})
|
||||
return {
|
||||
useAppStore: Object.assign((selector: (state: unknown) => unknown) => selector(getState()), {
|
||||
getState,
|
||||
subscribe: () => () => {}
|
||||
})
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/lib/worktree-activation', () => ({
|
||||
activateAndRevealWorktree: vi.fn()
|
||||
|
||||
@@ -22,33 +22,38 @@ let sshStateByEnvironment = new Map()
|
||||
let worktreesByRepo: Record<string, Worktree[]> = {}
|
||||
let worktreeCardProperties: WorktreeCardProperty[] = ['status']
|
||||
|
||||
vi.mock('@/store', () => ({
|
||||
useAppStore: (selector: (state: unknown) => unknown) =>
|
||||
selector({
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
fetchLinearIssue,
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
runtimeEnvironments,
|
||||
runtimeStatusByEnvironmentId,
|
||||
removedSshTargetLabels,
|
||||
settings: null,
|
||||
sshConnectionStates,
|
||||
sshStateByEnvironment,
|
||||
sshTargetLabels,
|
||||
sshTargetsHydrated: true,
|
||||
updateWorktreeMeta,
|
||||
worktreesByRepo,
|
||||
worktreeCardProperties
|
||||
vi.mock('@/store', () => {
|
||||
const getState = () => ({
|
||||
deleteStateByWorktreeId: {},
|
||||
fetchHostedReviewForBranch,
|
||||
fetchIssue,
|
||||
fetchLinearIssue,
|
||||
gitConflictOperationByWorktree: {},
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
runtimeEnvironments,
|
||||
runtimeStatusByEnvironmentId,
|
||||
removedSshTargetLabels,
|
||||
settings: null,
|
||||
sshConnectionStates,
|
||||
sshStateByEnvironment,
|
||||
sshTargetLabels,
|
||||
sshTargetsHydrated: true,
|
||||
updateWorktreeMeta,
|
||||
worktreesByRepo,
|
||||
worktreeCardProperties
|
||||
})
|
||||
return {
|
||||
useAppStore: Object.assign((selector: (state: unknown) => unknown) => selector(getState()), {
|
||||
getState,
|
||||
subscribe: () => () => {}
|
||||
})
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/lib/worktree-activation', () => ({
|
||||
activateAndRevealWorktree: vi.fn()
|
||||
|
||||
+9
-10
@@ -47,16 +47,15 @@ type WorktreeListComponent = React.ComponentType<{
|
||||
|
||||
let WorktreeList: WorktreeListComponent
|
||||
|
||||
vi.mock('@/store', () => {
|
||||
const useAppStore = ((selector: (state: Record<string, unknown>) => unknown) =>
|
||||
selector(mockStore.state)) as ((
|
||||
selector: (state: Record<string, unknown>) => unknown
|
||||
) => unknown) & {
|
||||
getState: () => Record<string, unknown>
|
||||
}
|
||||
useAppStore.getState = () => mockStore.state
|
||||
return { useAppStore }
|
||||
})
|
||||
vi.mock('@/store', () => ({
|
||||
useAppStore: Object.assign(
|
||||
(selector: (state: Record<string, unknown>) => unknown) => selector(mockStore.state),
|
||||
{
|
||||
getState: () => mockStore.state,
|
||||
subscribe: () => () => {}
|
||||
}
|
||||
)
|
||||
}))
|
||||
|
||||
// Why: honor the real getItemKey so each virtual row's React key equals
|
||||
// getRenderRowKey(row). This is what makes the parent card remount when it
|
||||
|
||||
@@ -51,16 +51,15 @@ function makeFolderWorkspacePathStatusMockState(): Record<string, unknown> {
|
||||
}
|
||||
}
|
||||
|
||||
vi.mock('@/store', () => {
|
||||
const useAppStore = ((selector: (state: Record<string, unknown>) => unknown) =>
|
||||
selector(mockStore.state)) as ((
|
||||
selector: (state: Record<string, unknown>) => unknown
|
||||
) => unknown) & {
|
||||
getState: () => Record<string, unknown>
|
||||
}
|
||||
useAppStore.getState = () => mockStore.state
|
||||
return { useAppStore }
|
||||
})
|
||||
vi.mock('@/store', () => ({
|
||||
useAppStore: Object.assign(
|
||||
(selector: (state: Record<string, unknown>) => unknown) => selector(mockStore.state),
|
||||
{
|
||||
getState: () => mockStore.state,
|
||||
subscribe: () => () => {}
|
||||
}
|
||||
)
|
||||
}))
|
||||
|
||||
vi.mock('@tanstack/react-virtual', () => ({
|
||||
defaultRangeExtractor: ({ startIndex, endIndex }: { startIndex: number; endIndex: number }) =>
|
||||
|
||||
@@ -52,16 +52,15 @@ function makeFolderWorkspacePathStatusMockState(): Record<string, unknown> {
|
||||
}
|
||||
}
|
||||
|
||||
vi.mock('@/store', () => {
|
||||
const useAppStore = ((selector: (state: Record<string, unknown>) => unknown) =>
|
||||
selector(mockStore.state)) as ((
|
||||
selector: (state: Record<string, unknown>) => unknown
|
||||
) => unknown) & {
|
||||
getState: () => Record<string, unknown>
|
||||
}
|
||||
useAppStore.getState = () => mockStore.state
|
||||
return { useAppStore }
|
||||
})
|
||||
vi.mock('@/store', () => ({
|
||||
useAppStore: Object.assign(
|
||||
(selector: (state: Record<string, unknown>) => unknown) => selector(mockStore.state),
|
||||
{
|
||||
getState: () => mockStore.state,
|
||||
subscribe: () => () => {}
|
||||
}
|
||||
)
|
||||
}))
|
||||
|
||||
vi.mock('@tanstack/react-virtual', () => ({
|
||||
defaultRangeExtractor: ({ startIndex, endIndex }: { startIndex: number; endIndex: number }) =>
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
// @vitest-environment happy-dom
|
||||
import { act } from 'react'
|
||||
import { createRoot, type Root } from 'react-dom/client'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { useAppStore } from '@/store'
|
||||
import { readStoreListenerCount } from '@/store/store-listener-census'
|
||||
import { makeTab } from '@/store/slices/store-test-helpers'
|
||||
import type { AppState } from '@/store/types'
|
||||
import type { DashboardAgentRow } from '@/components/dashboard/useDashboardData'
|
||||
import { makePaneKey } from '../../../../shared/stable-pane-id'
|
||||
import {
|
||||
AGENT_STATUS_STALE_AFTER_MS,
|
||||
type AgentStatusEntry
|
||||
} from '../../../../shared/agent-status-types'
|
||||
import { useWorktreeAgentRows } from './useWorktreeAgentRows'
|
||||
|
||||
Reflect.set(globalThis, 'IS_REACT_ACT_ENVIRONMENT', true)
|
||||
|
||||
const LEAF = '11111111-1111-4111-8111-111111111111'
|
||||
const KEY_A = makePaneKey('tab-a', LEAF)
|
||||
const KEY_B = makePaneKey('tab-b', LEAF)
|
||||
const original = useAppStore.getState()
|
||||
let root: Root
|
||||
let container: HTMLDivElement
|
||||
let rows: DashboardAgentRow[]
|
||||
let renders: number
|
||||
|
||||
function Probe({
|
||||
worktreeId = 'folder-a',
|
||||
active = true
|
||||
}: {
|
||||
worktreeId?: string
|
||||
active?: boolean
|
||||
}) {
|
||||
rows = useWorktreeAgentRows(worktreeId, active)
|
||||
renders += 1
|
||||
return null
|
||||
}
|
||||
function entry(key: string, worktreeId: string): AgentStatusEntry {
|
||||
return {
|
||||
paneKey: key,
|
||||
worktreeId,
|
||||
state: 'working',
|
||||
agentType: 'claude',
|
||||
prompt: worktreeId,
|
||||
updatedAt: Date.now(),
|
||||
stateStartedAt: Date.now(),
|
||||
stateHistory: []
|
||||
}
|
||||
}
|
||||
function patch(update: Partial<AppState>) {
|
||||
act(() => useAppStore.setState(update))
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
vi.setSystemTime(2_000_000)
|
||||
useAppStore.setState({
|
||||
tabsByWorktree: {
|
||||
'folder-a': [makeTab({ id: 'tab-a', worktreeId: 'folder-a' })],
|
||||
'ssh-b': [makeTab({ id: 'tab-b', worktreeId: 'ssh-b' })]
|
||||
},
|
||||
unifiedTabsByWorktree: {},
|
||||
agentStatusByPaneKey: {
|
||||
[KEY_A]: entry(KEY_A, 'folder-a'),
|
||||
[KEY_B]: { ...entry(KEY_B, 'ssh-b'), connectionId: 'ssh:host' }
|
||||
},
|
||||
retainedAgentsByPaneKey: {},
|
||||
migrationUnsupportedByPtyId: {},
|
||||
runtimePaneTitlesByTabId: {},
|
||||
ptyIdsByTabId: {},
|
||||
terminalLayoutsByTabId: {},
|
||||
runtimeAgentOrchestrationByPaneKey: {},
|
||||
paneForegroundAgentByPaneKey: {}
|
||||
})
|
||||
renders = 0
|
||||
container = document.createElement('div')
|
||||
document.body.appendChild(container)
|
||||
root = createRoot(container)
|
||||
})
|
||||
afterEach(() => {
|
||||
act(() => root.unmount())
|
||||
container.remove()
|
||||
useAppStore.setState(original, true)
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
describe('mounted worktree agent row subscriptions', () => {
|
||||
it('listens once while active and releases its listener while inactive', () => {
|
||||
const baseline = readStoreListenerCount() ?? 0
|
||||
act(() => root.render(<Probe />))
|
||||
expect(readStoreListenerCount()).toBe(baseline + 1)
|
||||
expect(rows[0].entry.prompt).toBe('folder-a')
|
||||
act(() => root.render(<Probe active={false} />))
|
||||
expect(readStoreListenerCount()).toBe(baseline)
|
||||
expect(rows).toEqual([])
|
||||
const before = renders
|
||||
patch({ activeWorktreeId: 'ssh-b' })
|
||||
expect(renders).toBe(before)
|
||||
patch({
|
||||
agentStatusByPaneKey: {
|
||||
...useAppStore.getState().agentStatusByPaneKey,
|
||||
[KEY_A]: { ...entry(KEY_A, 'folder-a'), prompt: 'changed while disabled' }
|
||||
}
|
||||
})
|
||||
act(() => root.render(<Probe />))
|
||||
expect(rows[0].entry.prompt).toBe('changed while disabled')
|
||||
expect(readStoreListenerCount()).toBe(baseline + 1)
|
||||
})
|
||||
|
||||
it('switches worktrees and applies an SSH status update immediately', () => {
|
||||
act(() => root.render(<Probe />))
|
||||
act(() => root.render(<Probe worktreeId="ssh-b" />))
|
||||
expect(rows[0].paneKey).toBe(KEY_B)
|
||||
act(() =>
|
||||
useAppStore
|
||||
.getState()
|
||||
.setAgentStatus(
|
||||
KEY_B,
|
||||
{ state: 'blocked', agentType: 'claude', prompt: 'remote permission' },
|
||||
undefined,
|
||||
{ updatedAt: Date.now() + 1 },
|
||||
{ tabId: 'tab-b', worktreeId: 'ssh-b', connectionId: 'ssh:host' }
|
||||
)
|
||||
)
|
||||
expect(rows[0].entry.prompt).toBe('remote permission')
|
||||
expect(rows[0].state).toBe('blocked')
|
||||
})
|
||||
|
||||
it('keeps unrelated cards stable while a working agent reports new tool output', () => {
|
||||
act(() => root.render(<Probe />))
|
||||
const beforeRows = rows
|
||||
const before = renders
|
||||
act(() =>
|
||||
useAppStore
|
||||
.getState()
|
||||
.setAgentStatus(
|
||||
KEY_B,
|
||||
{ state: 'working', agentType: 'claude', prompt: 'new output', toolName: 'Read' },
|
||||
undefined,
|
||||
{ updatedAt: Date.now() + 1 },
|
||||
{ tabId: 'tab-b', worktreeId: 'ssh-b', connectionId: 'ssh:host' }
|
||||
)
|
||||
)
|
||||
expect(rows).toBe(beforeRows)
|
||||
expect(renders).toBe(before)
|
||||
act(() =>
|
||||
useAppStore
|
||||
.getState()
|
||||
.setAgentStatus(
|
||||
KEY_A,
|
||||
{ state: 'working', agentType: 'claude', prompt: 'local output', toolName: 'Edit' },
|
||||
undefined,
|
||||
{ updatedAt: Date.now() + 2 },
|
||||
{ tabId: 'tab-a', worktreeId: 'folder-a' }
|
||||
)
|
||||
)
|
||||
expect(rows[0].entry.toolName).toBe('Edit')
|
||||
expect(renders).toBe(before + 1)
|
||||
})
|
||||
|
||||
it('decays on an epoch-only freshness tick', () => {
|
||||
act(() => root.render(<Probe />))
|
||||
expect(rows[0].state).toBe('working')
|
||||
vi.setSystemTime(Date.now() + AGENT_STATUS_STALE_AFTER_MS + 1)
|
||||
patch({ agentStatusEpoch: useAppStore.getState().agentStatusEpoch + 1 })
|
||||
expect(rows[0].state).toBe('idle')
|
||||
})
|
||||
|
||||
it('observes title, PTY, layout, orchestration, foreground, migration and retention inputs', () => {
|
||||
act(() => root.render(<Probe />))
|
||||
const updates: Partial<AppState>[] = [
|
||||
{ runtimePaneTitlesByTabId: { 'tab-a': { 0: 'Claude Code' } } },
|
||||
{ ptyIdsByTabId: { 'tab-a': ['pty-a'] } },
|
||||
{
|
||||
terminalLayoutsByTabId: {
|
||||
'tab-a': {
|
||||
root: { type: 'leaf', leafId: LEAF },
|
||||
activeLeafId: LEAF,
|
||||
expandedLeafId: null
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
runtimeAgentOrchestrationByPaneKey: {
|
||||
[KEY_A]: { taskId: 'task', dispatchId: 'dispatch', taskTitle: 'New task' }
|
||||
}
|
||||
},
|
||||
{ paneForegroundAgentByPaneKey: { [KEY_A]: { agent: 'claude', shellForeground: false } } },
|
||||
{
|
||||
migrationUnsupportedByPtyId: {
|
||||
legacy: {
|
||||
ptyId: 'legacy',
|
||||
worktreeId: 'folder-a',
|
||||
tabId: 'tab-a',
|
||||
leafId: LEAF,
|
||||
paneKey: KEY_A,
|
||||
reason: 'legacy-numeric-pane-key',
|
||||
source: 'local',
|
||||
updatedAt: Date.now()
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
retainedAgentsByPaneKey: {
|
||||
[KEY_B]: {
|
||||
entry: entry(KEY_B, 'folder-a'),
|
||||
worktreeId: 'folder-a',
|
||||
tab: makeTab({ id: 'tab-b', worktreeId: 'folder-a' }),
|
||||
agentType: 'claude',
|
||||
startedAt: Date.now()
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
for (const update of updates) {
|
||||
const before = rows
|
||||
patch(update)
|
||||
expect(rows).not.toBe(before)
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import { useCallback, useMemo, useSyncExternalStore } from 'react'
|
||||
import type { DashboardAgentRow } from '@/components/dashboard/useDashboardData'
|
||||
import { applyAgentRowLineage } from '@/components/dashboard/agent-row-lineage'
|
||||
import { migrationUnsupportedToAgentStatusEntry } from '@/lib/migration-unsupported-agent-entry'
|
||||
import { useAppStore } from '@/store'
|
||||
import type { AppState } from '@/store/types'
|
||||
import {
|
||||
EMPTY_LIVE_PTY_IDS,
|
||||
EMPTY_PANE_FOREGROUND_AGENTS,
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
|
||||
// Why frozen: shared by every inactive card, and callers only read these rows.
|
||||
const EMPTY_AGENT_ROWS = Object.freeze([]) as unknown as DashboardAgentRow[]
|
||||
const subscribeToNothing = (): (() => void) => () => {}
|
||||
|
||||
export { buildWorktreeAgentRows } from './worktree-agent-rows'
|
||||
export {
|
||||
@@ -53,63 +54,57 @@ export {
|
||||
* selector work on high-frequency agent status pings.
|
||||
*/
|
||||
export function useWorktreeAgentRows(worktreeId: string, active = true): DashboardAgentRow[] {
|
||||
const selectAgentFreshness = useMemo(
|
||||
() => createWorktreeAgentFreshnessSelector(worktreeId),
|
||||
[worktreeId]
|
||||
)
|
||||
const tabs = useAppStore((s) => (active ? s.tabsByWorktree[worktreeId] : EMPTY_TABS))
|
||||
// Why: narrow the subscriptions to only THIS worktree's entries via
|
||||
// useShallow. Subscribing to the whole agentStatusByPaneKey map would make
|
||||
// every on-screen card re-render on any agent-status update anywhere —
|
||||
// O(worktrees²) render amplification. Pre-filtering here means the card
|
||||
// only re-renders when something relevant to THIS worktree changes.
|
||||
const liveEntries = useAppStore(
|
||||
useShallow((s) =>
|
||||
active ? selectLiveAgentStatusEntriesForWorktree(s, worktreeId) : EMPTY_LIVE_ENTRIES
|
||||
)
|
||||
)
|
||||
// Why: keep the store selector limited to stable raw records. Converting
|
||||
// migration entries creates fresh objects with Date.now(), which breaks
|
||||
// useSyncExternalStore's cached-snapshot contract and can blank Electron.
|
||||
const migrationUnsupported = useAppStore(
|
||||
useShallow((s) =>
|
||||
active
|
||||
? selectMigrationUnsupportedEntriesForWorktree(s, worktreeId)
|
||||
: EMPTY_MIGRATION_UNSUPPORTED_ENTRIES
|
||||
)
|
||||
)
|
||||
const retained = useAppStore(
|
||||
useShallow((s) =>
|
||||
active ? selectRetainedAgentEntriesForWorktree(s, worktreeId) : EMPTY_RETAINED
|
||||
)
|
||||
)
|
||||
const runtimePaneTitlesByTabId = useAppStore(
|
||||
useShallow((s) =>
|
||||
active ? selectRuntimePaneTitlesForWorktree(s, worktreeId) : EMPTY_RUNTIME_PANE_TITLES
|
||||
)
|
||||
)
|
||||
const ptyIdsByTabId = useAppStore(
|
||||
useShallow((s) => (active ? selectLivePtyIdsForWorktree(s, worktreeId) : EMPTY_LIVE_PTY_IDS))
|
||||
)
|
||||
const terminalLayoutsByTabId = useAppStore(
|
||||
useShallow((s) =>
|
||||
active ? selectTerminalLayoutsForWorktree(s, worktreeId) : EMPTY_TERMINAL_LAYOUTS
|
||||
)
|
||||
)
|
||||
const runtimeAgentOrchestrationByPaneKey = useAppStore(
|
||||
useShallow((s) =>
|
||||
active
|
||||
? selectRuntimeAgentOrchestrationForWorktree(s, worktreeId)
|
||||
: EMPTY_WORKTREE_AGENT_ORCHESTRATION
|
||||
)
|
||||
)
|
||||
const paneForegroundAgentByPaneKey = useAppStore(
|
||||
useShallow((s) =>
|
||||
active ? selectPaneForegroundAgentsForWorktree(s, worktreeId) : EMPTY_PANE_FOREGROUND_AGENTS
|
||||
)
|
||||
)
|
||||
const agentFreshnessSignature = useAppStore((s) =>
|
||||
active ? selectAgentFreshness(s) : EMPTY_WORKTREE_AGENT_FRESHNESS_SIGNATURE
|
||||
const selectInputs = useMemo(() => {
|
||||
const selectAgentFreshness = createWorktreeAgentFreshnessSelector(worktreeId)
|
||||
const readInputs = (state: AppState) =>
|
||||
[
|
||||
active ? state.tabsByWorktree[worktreeId] : EMPTY_TABS,
|
||||
active ? selectLiveAgentStatusEntriesForWorktree(state, worktreeId) : EMPTY_LIVE_ENTRIES,
|
||||
active
|
||||
? selectMigrationUnsupportedEntriesForWorktree(state, worktreeId)
|
||||
: EMPTY_MIGRATION_UNSUPPORTED_ENTRIES,
|
||||
active ? selectRetainedAgentEntriesForWorktree(state, worktreeId) : EMPTY_RETAINED,
|
||||
active ? selectRuntimePaneTitlesForWorktree(state, worktreeId) : EMPTY_RUNTIME_PANE_TITLES,
|
||||
active ? selectLivePtyIdsForWorktree(state, worktreeId) : EMPTY_LIVE_PTY_IDS,
|
||||
active ? selectTerminalLayoutsForWorktree(state, worktreeId) : EMPTY_TERMINAL_LAYOUTS,
|
||||
active
|
||||
? selectRuntimeAgentOrchestrationForWorktree(state, worktreeId)
|
||||
: EMPTY_WORKTREE_AGENT_ORCHESTRATION,
|
||||
active
|
||||
? selectPaneForegroundAgentsForWorktree(state, worktreeId)
|
||||
: EMPTY_PANE_FOREGROUND_AGENTS,
|
||||
active ? selectAgentFreshness(state) : EMPTY_WORKTREE_AGENT_FRESHNESS_SIGNATURE
|
||||
] as const
|
||||
let previous: ReturnType<typeof readInputs> | undefined
|
||||
return (state: AppState) => {
|
||||
if (!active && previous) {
|
||||
return previous
|
||||
}
|
||||
const next = readInputs(state)
|
||||
// The indexed selectors preserve equal records; compare references without allocating shallow-comparison maps.
|
||||
if (previous && next.every((value, index) => Object.is(value, previous?.[index]))) {
|
||||
return previous
|
||||
}
|
||||
previous = next
|
||||
return next
|
||||
}
|
||||
}, [worktreeId, active])
|
||||
const getInputs = useCallback(() => selectInputs(useAppStore.getState()), [selectInputs])
|
||||
const [
|
||||
tabs,
|
||||
liveEntries,
|
||||
migrationUnsupported,
|
||||
retained,
|
||||
runtimePaneTitlesByTabId,
|
||||
ptyIdsByTabId,
|
||||
terminalLayoutsByTabId,
|
||||
runtimeAgentOrchestrationByPaneKey,
|
||||
paneForegroundAgentByPaneKey,
|
||||
agentFreshnessSignature
|
||||
] = useSyncExternalStore(
|
||||
active ? useAppStore.subscribe : subscribeToNothing,
|
||||
getInputs,
|
||||
getInputs
|
||||
)
|
||||
|
||||
return useMemo<DashboardAgentRow[]>(() => {
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
// @vitest-environment happy-dom
|
||||
import { act } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import { writeFileSync } from 'node:fs'
|
||||
import { expect, it } from 'vitest'
|
||||
import { useAppStore } from '@/store'
|
||||
import { readStoreListenerCount } from '@/store/store-listener-census'
|
||||
import { makeTab } from '@/store/slices/store-test-helpers'
|
||||
import { makePaneKey } from '../../../../shared/stable-pane-id'
|
||||
import type { AgentStatusEntry } from '../../../../shared/agent-status-types'
|
||||
import { useWorktreeAgentRows } from './useWorktreeAgentRows'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import { selectAcknowledgedAgentTimes } from './worktree-card-agent-ack-inputs'
|
||||
|
||||
Reflect.set(globalThis, 'IS_REACT_ACT_ENVIRONMENT', true)
|
||||
|
||||
type Round = { elapsedMs: number; cpuMs: number; renders: number }
|
||||
type Result = { active: boolean; listeners: number; rounds: Round[] }
|
||||
|
||||
const LEAF = '11111111-1111-4111-8111-111111111111'
|
||||
const CARDS = Number(process.env.ORCA_BENCH_CARDS ?? 100)
|
||||
const WRITES = Number(process.env.ORCA_BENCH_WRITES ?? 500)
|
||||
|
||||
it.skipIf(!process.env.ORCA_AGENT_ROWS_BENCH)(
|
||||
'measures mounted agent row subscriptions',
|
||||
() => {
|
||||
const original = useAppStore.getState()
|
||||
const tabsByWorktree = Object.fromEntries(
|
||||
Array.from({ length: CARDS }, (_, index) => {
|
||||
const worktreeId = `wt-${index}`
|
||||
return [worktreeId, [makeTab({ id: `tab-${index}`, worktreeId })]]
|
||||
})
|
||||
)
|
||||
const entries: Record<string, AgentStatusEntry> = {}
|
||||
for (let index = 0; index < CARDS; index += 1) {
|
||||
const paneKey = makePaneKey(`tab-${index}`, LEAF)
|
||||
entries[paneKey] = {
|
||||
paneKey,
|
||||
tabId: `tab-${index}`,
|
||||
worktreeId: `wt-${index}`,
|
||||
state: 'working',
|
||||
agentType: 'claude',
|
||||
prompt: 'Do work',
|
||||
updatedAt: Date.now(),
|
||||
stateStartedAt: Date.now(),
|
||||
stateHistory: []
|
||||
}
|
||||
}
|
||||
useAppStore.setState({
|
||||
tabsByWorktree,
|
||||
agentStatusByPaneKey: entries,
|
||||
unifiedTabsByWorktree: {},
|
||||
runtimePaneTitlesByTabId: {},
|
||||
ptyIdsByTabId: {},
|
||||
terminalLayoutsByTabId: {},
|
||||
retainedAgentsByPaneKey: {},
|
||||
runtimeAgentOrchestrationByPaneKey: {},
|
||||
paneForegroundAgentByPaneKey: {}
|
||||
})
|
||||
const container = document.createElement('div')
|
||||
document.body.appendChild(container)
|
||||
const root = createRoot(container)
|
||||
const results: Result[] = []
|
||||
try {
|
||||
// A visible compact card uses both hooks; hidden details keep only the inactive hook.
|
||||
for (const active of [true, false]) {
|
||||
let renders = 0
|
||||
function VisibleProbe({ index }: { index: number }) {
|
||||
const rows = useWorktreeAgentRows(`wt-${index}`, true)
|
||||
useWorktreeAgentRows(`wt-${index}`, false)
|
||||
useAppStore(useShallow((state) => selectAcknowledgedAgentTimes(state, rows)))
|
||||
renders += 1
|
||||
return null
|
||||
}
|
||||
function HiddenProbe({ index }: { index: number }) {
|
||||
useWorktreeAgentRows(`wt-${index}`, false)
|
||||
renders += 1
|
||||
return null
|
||||
}
|
||||
const Probe = active ? VisibleProbe : HiddenProbe
|
||||
const baselineListeners = readStoreListenerCount() ?? 0
|
||||
act(() =>
|
||||
root.render(
|
||||
Array.from({ length: CARDS }, (_, index) => <Probe key={index} index={index} />)
|
||||
)
|
||||
)
|
||||
const listeners = (readStoreListenerCount() ?? 0) - baselineListeners
|
||||
const rounds: Round[] = []
|
||||
for (let round = 0; round < 6; round += 1) {
|
||||
const beforeRenders = renders
|
||||
const cpuStart = process.cpuUsage()
|
||||
const start = performance.now()
|
||||
for (let index = 0; index < WRITES; index += 1) {
|
||||
const key = makePaneKey(`tab-${index % CARDS}`, LEAF)
|
||||
act(() => {
|
||||
const previous = useAppStore.getState().agentStatusByPaneKey
|
||||
useAppStore.setState({
|
||||
agentStatusByPaneKey: {
|
||||
...previous,
|
||||
[key]: { ...previous[key], updatedAt: Date.now(), toolName: `tool-${index}` }
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
const elapsedMs = performance.now() - start
|
||||
const cpu = process.cpuUsage(cpuStart)
|
||||
expect(renders - beforeRenders).toBe(active ? WRITES : 0)
|
||||
if (round > 0) {
|
||||
rounds.push({
|
||||
elapsedMs,
|
||||
cpuMs: (cpu.user + cpu.system) / 1000,
|
||||
renders: renders - beforeRenders
|
||||
})
|
||||
}
|
||||
}
|
||||
results.push({ active, listeners, rounds })
|
||||
act(() => root.render(null))
|
||||
expect(readStoreListenerCount()).toBe(baselineListeners)
|
||||
}
|
||||
const report = { cards: CARDS, writes: WRITES, results }
|
||||
console.log(JSON.stringify(report))
|
||||
if (process.env.ORCA_BENCH_OUTPUT) {
|
||||
writeFileSync(process.env.ORCA_BENCH_OUTPUT, `${JSON.stringify(report, null, 2)}\n`)
|
||||
}
|
||||
} finally {
|
||||
act(() => root.unmount())
|
||||
container.remove()
|
||||
useAppStore.setState(original, true)
|
||||
}
|
||||
},
|
||||
120_000
|
||||
)
|
||||
@@ -75,6 +75,16 @@ describe('selectAcknowledgedAgentTimes', () => {
|
||||
expect(shallow(after, before)).toBe(true)
|
||||
})
|
||||
|
||||
it('reuses the projection across status-only publications and handles a different row list', () => {
|
||||
const state = { acknowledgedAgentsByPaneKey: { 'tab-a:leaf-a': 11, 'tab-a:leaf-b': 22 } }
|
||||
const first = selectAcknowledgedAgentTimes(state, AGENTS)
|
||||
expect(selectAcknowledgedAgentTimes({ ...state }, AGENTS)).toBe(first)
|
||||
expect(selectAcknowledgedAgentTimes(state, [AGENTS[1], AGENTS[0]])).toEqual([22, 11])
|
||||
expect(selectAcknowledgedAgentTimes({ acknowledgedAgentsByPaneKey: {} }, AGENTS)).toEqual([
|
||||
0, 0
|
||||
])
|
||||
})
|
||||
|
||||
it('updates when one of this card rows is acknowledged', () => {
|
||||
const initialTimes = selectedTimes
|
||||
act(() => {
|
||||
|
||||
@@ -3,10 +3,30 @@ import type { AppState } from '@/store/types'
|
||||
|
||||
type AcknowledgedAgentTimesState = Pick<AppState, 'acknowledgedAgentsByPaneKey'>
|
||||
|
||||
type AcknowledgedAgentRows = readonly Pick<DashboardAgentRow, 'paneKey'>[]
|
||||
|
||||
// Both keys are weak so departed rows and old acknowledgement snapshots can be collected.
|
||||
const projections = new WeakMap<
|
||||
AcknowledgedAgentTimesState['acknowledgedAgentsByPaneKey'],
|
||||
WeakMap<AcknowledgedAgentRows, readonly number[]>
|
||||
>()
|
||||
|
||||
/** Projects only the acknowledgement timestamps rendered by one card. */
|
||||
export function selectAcknowledgedAgentTimes(
|
||||
state: AcknowledgedAgentTimesState,
|
||||
agents: readonly Pick<DashboardAgentRow, 'paneKey'>[]
|
||||
): number[] {
|
||||
return agents.map((agent) => state.acknowledgedAgentsByPaneKey[agent.paneKey] ?? 0)
|
||||
agents: AcknowledgedAgentRows
|
||||
): readonly number[] {
|
||||
const source = state.acknowledgedAgentsByPaneKey
|
||||
let byRows = projections.get(source)
|
||||
if (!byRows) {
|
||||
byRows = new WeakMap()
|
||||
projections.set(source, byRows)
|
||||
}
|
||||
const cached = byRows.get(agents)
|
||||
if (cached) {
|
||||
return cached
|
||||
}
|
||||
const times = Object.freeze(agents.map((agent) => source[agent.paneKey] ?? 0))
|
||||
byRows.set(agents, times)
|
||||
return times
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user