mirror of
https://github.com/stablyai/orca.git
synced 2026-10-03 00:02:19 +00:00
fix dashboard bucket parity for unified agent tabs
This commit is contained in:
+41
@@ -3,6 +3,7 @@ import { makePaneKey } from '../../../../shared/stable-pane-id'
|
||||
import { folderWorkspaceKey } from '../../../../shared/workspace-scope'
|
||||
import type { FolderWorkspace } from '../../../../shared/folder-workspace-types'
|
||||
import type { ProjectGroup } from '../../../../shared/project-group-types'
|
||||
import type { Tab } from '../../../../shared/tab-types'
|
||||
import type { TerminalTab } from '../../../../shared/terminal-tab-types'
|
||||
import type { AgentStatusEntry } from '../../../../shared/agent-status-types'
|
||||
import { buildDashboardSnapshot, type DashboardSnapshotState } from './build-dashboard-snapshot'
|
||||
@@ -205,6 +206,46 @@ describe('buildDashboardSnapshot folder workspaces', () => {
|
||||
expect(buildDashboardBucketCounts(mixedState, NOW)).toEqual(expected)
|
||||
})
|
||||
|
||||
it('keeps done structured sessions visible when their tab exists only in unified tabs', () => {
|
||||
const structuredState = state()
|
||||
structuredState.tabsByWorktree = { [WORKSPACE_ID]: [] }
|
||||
structuredState.unifiedTabsByWorktree = {
|
||||
[WORKSPACE_ID]: [
|
||||
{
|
||||
id: TAB_ID,
|
||||
entityId: 'session-1',
|
||||
groupId: 'group-1',
|
||||
worktreeId: WORKSPACE_ID,
|
||||
contentType: 'agent-session',
|
||||
label: 'Codex Chat',
|
||||
customLabel: null,
|
||||
color: null,
|
||||
sortOrder: 0,
|
||||
createdAt: NOW,
|
||||
isPinned: false,
|
||||
agentSessionAgent: 'codex'
|
||||
} satisfies Tab
|
||||
]
|
||||
}
|
||||
structuredState.agentStatusByPaneKey = {
|
||||
[PANE_KEY]: {
|
||||
...entry(),
|
||||
state: 'done',
|
||||
sessionBoundary: true
|
||||
}
|
||||
}
|
||||
|
||||
const snapshot = buildDashboardSnapshot(structuredState, NOW)
|
||||
const expected = { attention: 0, working: 0, done: 0, idle: 0 }
|
||||
for (const card of snapshot.cards) {
|
||||
expected[card.bucket] += 1
|
||||
}
|
||||
|
||||
expect(snapshot.cards).toHaveLength(1)
|
||||
expect(snapshot.cards[0]).toMatchObject({ paneKey: PANE_KEY, bucket: 'done' })
|
||||
expect(buildDashboardBucketCounts(structuredState, NOW)).toEqual(expected)
|
||||
})
|
||||
|
||||
it('places folder-workspace agents in their real project group without git assumptions', () => {
|
||||
const sshState = state()
|
||||
sshState.sshTargetLabels = new Map([['ssh-1', 'openclaw']])
|
||||
|
||||
@@ -78,7 +78,7 @@ export type DashboardSnapshotState = Pick<
|
||||
Partial<
|
||||
DashboardCardTerminalInputState &
|
||||
DashboardLaunchDetectionState &
|
||||
Pick<AppState, 'runtimeEnvironments' | 'sshTargetLabels'>
|
||||
Pick<AppState, 'runtimeEnvironments' | 'sshTargetLabels' | 'unifiedTabsByWorktree'>
|
||||
>
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@ const mocks = vi.hoisted(() => ({
|
||||
repos: [],
|
||||
worktreesByRepo: {},
|
||||
tabsByWorktree: {},
|
||||
unifiedTabsByWorktree: {},
|
||||
agentStatusByPaneKey: {},
|
||||
retainedAgentsByPaneKey: {},
|
||||
migrationUnsupportedByPtyId: {},
|
||||
|
||||
@@ -16,6 +16,7 @@ export function useAgentBucketCounts(): AgentBucketCounts {
|
||||
repos,
|
||||
worktreesByRepo,
|
||||
tabsByWorktree,
|
||||
unifiedTabsByWorktree,
|
||||
agentStatusByPaneKey,
|
||||
retainedAgentsByPaneKey,
|
||||
migrationUnsupportedByPtyId,
|
||||
@@ -31,6 +32,7 @@ export function useAgentBucketCounts(): AgentBucketCounts {
|
||||
repos: s.repos,
|
||||
worktreesByRepo: s.worktreesByRepo,
|
||||
tabsByWorktree: s.tabsByWorktree,
|
||||
unifiedTabsByWorktree: s.unifiedTabsByWorktree,
|
||||
agentStatusByPaneKey: s.agentStatusByPaneKey,
|
||||
retainedAgentsByPaneKey: s.retainedAgentsByPaneKey,
|
||||
migrationUnsupportedByPtyId: s.migrationUnsupportedByPtyId,
|
||||
@@ -50,6 +52,7 @@ export function useAgentBucketCounts(): AgentBucketCounts {
|
||||
repos,
|
||||
worktreesByRepo,
|
||||
tabsByWorktree,
|
||||
unifiedTabsByWorktree,
|
||||
agentStatusByPaneKey,
|
||||
retainedAgentsByPaneKey,
|
||||
migrationUnsupportedByPtyId,
|
||||
@@ -72,6 +75,7 @@ export function useAgentBucketCounts(): AgentBucketCounts {
|
||||
repos,
|
||||
worktreesByRepo,
|
||||
tabsByWorktree,
|
||||
unifiedTabsByWorktree,
|
||||
agentStatusByPaneKey,
|
||||
retainedAgentsByPaneKey,
|
||||
migrationUnsupportedByPtyId,
|
||||
|
||||
@@ -59,6 +59,7 @@ function makeSnapshotWatchState(): DashboardSnapshotWatchState {
|
||||
repos: [],
|
||||
worktreesByRepo: {},
|
||||
tabsByWorktree: {},
|
||||
unifiedTabsByWorktree: {},
|
||||
agentStatusByPaneKey: {},
|
||||
retainedAgentsByPaneKey: {},
|
||||
migrationUnsupportedByPtyId: {},
|
||||
@@ -182,6 +183,7 @@ describe('useDashboardPopoutBridge', () => {
|
||||
'repos',
|
||||
'worktreesByRepo',
|
||||
'tabsByWorktree',
|
||||
'unifiedTabsByWorktree',
|
||||
'retainedAgentsByPaneKey',
|
||||
'migrationUnsupportedByPtyId',
|
||||
'runtimeAgentOrchestrationByPaneKey',
|
||||
@@ -241,6 +243,19 @@ describe('useDashboardPopoutBridge', () => {
|
||||
expect(republished).toEqual(profileInputs.map((next) => Object.keys(next)[0]))
|
||||
})
|
||||
|
||||
it('republishes when the unified agent-session tab projection changes', () => {
|
||||
const previousState = makeSnapshotWatchState()
|
||||
expect(
|
||||
dashboardSnapshotInputsChanged(
|
||||
{
|
||||
...previousState,
|
||||
unifiedTabsByWorktree: { 'worktree-1': [] }
|
||||
},
|
||||
previousState
|
||||
)
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
it('releases every dashboard listener when the experiment is disabled', async () => {
|
||||
await act(async () => root.render(<Harness enabled />))
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ export function dashboardSnapshotInputsChanged(
|
||||
state.repos !== previousState.repos ||
|
||||
state.worktreesByRepo !== previousState.worktreesByRepo ||
|
||||
state.tabsByWorktree !== previousState.tabsByWorktree ||
|
||||
state.unifiedTabsByWorktree !== previousState.unifiedTabsByWorktree ||
|
||||
state.retainedAgentsByPaneKey !== previousState.retainedAgentsByPaneKey ||
|
||||
state.migrationUnsupportedByPtyId !== previousState.migrationUnsupportedByPtyId ||
|
||||
state.runtimeAgentOrchestrationByPaneKey !== previousState.runtimeAgentOrchestrationByPaneKey ||
|
||||
|
||||
@@ -13,6 +13,7 @@ export function useLiveDashboardSnapshot(): DashboardSnapshot {
|
||||
const repos = useAppStore((s) => s.repos)
|
||||
const worktreesByRepo = useAppStore((s) => s.worktreesByRepo)
|
||||
const tabsByWorktree = useAppStore((s) => s.tabsByWorktree)
|
||||
const unifiedTabsByWorktree = useAppStore((s) => s.unifiedTabsByWorktree)
|
||||
const agentStatusByPaneKey = useAppStore((s) => s.agentStatusByPaneKey)
|
||||
const retainedAgentsByPaneKey = useAppStore((s) => s.retainedAgentsByPaneKey)
|
||||
const migrationUnsupportedByPtyId = useAppStore((s) => s.migrationUnsupportedByPtyId)
|
||||
@@ -68,6 +69,7 @@ export function useLiveDashboardSnapshot(): DashboardSnapshot {
|
||||
repos,
|
||||
worktreesByRepo,
|
||||
tabsByWorktree,
|
||||
unifiedTabsByWorktree,
|
||||
agentStatusByPaneKey,
|
||||
retainedAgentsByPaneKey,
|
||||
migrationUnsupportedByPtyId,
|
||||
@@ -107,6 +109,7 @@ export function useLiveDashboardSnapshot(): DashboardSnapshot {
|
||||
repos,
|
||||
worktreesByRepo,
|
||||
tabsByWorktree,
|
||||
unifiedTabsByWorktree,
|
||||
agentStatusByPaneKey,
|
||||
retainedAgentsByPaneKey,
|
||||
migrationUnsupportedByPtyId,
|
||||
|
||||
Reference in New Issue
Block a user