diff --git a/src/renderer/components/team/TeamDetailView.tsx b/src/renderer/components/team/TeamDetailView.tsx index 15255d28..9dca9155 100644 --- a/src/renderer/components/team/TeamDetailView.tsx +++ b/src/renderer/components/team/TeamDetailView.tsx @@ -1,4 +1,4 @@ -import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { lazy, memo, Suspense, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { api } from '@renderer/api'; import { SessionContextPanel } from '@renderer/components/chat/SessionContextPanel/index'; @@ -202,6 +202,69 @@ function filterKanbanTasks(tasks: TeamTaskWithKanban[], query: string): TeamTask ); } +const TeamOfflineStatusBanner = memo(function TeamOfflineStatusBanner({ + teamName, + onLaunch, +}: { + teamName: string; + onLaunch: () => void; +}): React.JSX.Element { + const summary = useStore( + useShallow((s) => { + const team = s.teamByName[teamName]; + if (!team) { + return null; + } + + return { + memberCount: team.memberCount, + expectedMemberCount: team.expectedMemberCount, + confirmedCount: team.confirmedCount, + runtimeAlivePendingCount: team.runtimeAlivePendingCount, + teamLaunchState: team.teamLaunchState, + partialLaunchFailure: team.partialLaunchFailure, + missingMemberCount: team.missingMembers?.length ?? 0, + }; + }) + ); + + const message = + summary?.teamLaunchState === 'partial_pending' + ? summary.runtimeAlivePendingCount != null && summary.runtimeAlivePendingCount > 0 + ? `Last launch is still reconciling - ${summary.confirmedCount ?? 0}/${summary.expectedMemberCount ?? summary.memberCount} teammates confirmed alive, ${summary.runtimeAlivePendingCount} runtime${summary.runtimeAlivePendingCount === 1 ? '' : 's'} pending bootstrap` + : 'Last launch is still reconciling' + : summary?.partialLaunchFailure + ? summary.missingMemberCount > 0 + ? `Last launch failed partway - ${summary.missingMemberCount}/${summary.expectedMemberCount ?? summary.missingMemberCount} teammates did not join` + : 'Last launch failed partway' + : 'Team is offline'; + + return ( +
Team not launched yet
- This is a draft team —{' '} - {currentTeamSummary?.displayName || teamName} has been configured - with {currentTeamSummary?.memberCount ?? 0} member - {currentTeamSummary?.memberCount === 1 ? '' : 's'} but hasn't been provisioned - by CLI yet. Click Launch to select a model and start the team. + This is a draft team - {draftDisplayName} has been configured with{' '} + {draftMemberCount} member + {draftMemberCount === 1 ? '' : 's'} but hasn't been provisioned by CLI yet. + Click Launch to select a model and start the team.