diff --git a/src/renderer/components/sidebar/GlobalTaskList.tsx b/src/renderer/components/sidebar/GlobalTaskList.tsx index dbca5d30..3a2ce4b2 100644 --- a/src/renderer/components/sidebar/GlobalTaskList.tsx +++ b/src/renderer/components/sidebar/GlobalTaskList.tsx @@ -18,7 +18,7 @@ import { NO_PROJECT_KEY, sortTasksByFreshness, } from '@renderer/utils/taskGrouping'; -import { resolveTeamStatus } from '@renderer/utils/teamListStatus'; +import { isTeamListStatusRunning, resolveTeamStatus } from '@renderer/utils/teamListStatus'; import { deriveTaskDisplayId } from '@shared/utils/taskIdentity'; import { Archive, @@ -361,7 +361,7 @@ export const GlobalTaskList = memo(function GlobalTaskList({ getCurrentProvisioningProgressForTeam(provisioningState, team.teamName), leadActivityByTeam ); - if (status === 'offline') { + if (!isTeamListStatusRunning(status)) { result.add(team.teamName); } } diff --git a/test/renderer/components/sidebar/GlobalTaskList.test.ts b/test/renderer/components/sidebar/GlobalTaskList.test.ts index fe302f7b..659ebc8c 100644 --- a/test/renderer/components/sidebar/GlobalTaskList.test.ts +++ b/test/renderer/components/sidebar/GlobalTaskList.test.ts @@ -3,7 +3,7 @@ import { createRoot } from 'react-dom/client'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import type { GlobalTask } from '../../../../src/shared/types'; +import type { GlobalTask, TeamSummary } from '../../../../src/shared/types'; interface StoreState { globalTasks: GlobalTask[]; @@ -19,7 +19,7 @@ interface StoreState { totalSessions: number; worktrees: { path: string }[]; }[]; - teams: { teamName: string; displayName: string }[]; + teams: (Pick & Partial)[]; provisioningRuns: Record; currentProvisioningRunIdByTeam: Record; leadActivityByTeam: Record; @@ -327,6 +327,41 @@ describe('GlobalTaskList project grouping', () => { }); }); + it('marks task cards as offline when the owning team has a partial launch failure', async () => { + vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true); + const aliveList = vi.fn(() => Promise.resolve([])); + setElectronApiForTest({ teams: { aliveList } }); + storeState.globalTasks = [makeTask(1)]; + storeState.teams = [ + { + teamName: 'alpha-team', + displayName: 'Alpha Team', + partialLaunchFailure: true, + teamLaunchState: 'partial_failure', + }, + ]; + + const host = document.createElement('div'); + document.body.appendChild(host); + const root = createRoot(host); + + await act(async () => { + root.render(React.createElement(GlobalTaskList)); + await flushMicrotasks(); + await flushMicrotasks(); + }); + + expect(aliveList).toHaveBeenCalled(); + expect( + host.querySelector('[data-testid="sidebar-task-item"]')?.getAttribute('data-team-offline') + ).toBe('true'); + + await act(async () => { + root.unmount(); + await flushMicrotasks(); + }); + }); + it('marks task cards as offline when alive-list is initialized before teams are loaded', async () => { vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true); const aliveList = vi.fn(() => Promise.resolve([]));