import { useEffect, useMemo, useState } from 'react'; import { Button } from '@renderer/components/ui/button'; import { useStore } from '@renderer/store'; import { getCurrentProvisioningProgressForTeam } from '@renderer/store/slices/teamSlice'; import { CheckCircle2, X } from 'lucide-react'; import { useShallow } from 'zustand/react/shallow'; import { ProvisioningProgressBlock } from './ProvisioningProgressBlock'; import { STEP_ORDER } from './provisioningSteps'; import type { ProvisioningStep } from './provisioningSteps'; interface TeamProvisioningBannerProps { teamName: string; } export const TeamProvisioningBanner = ({ teamName, }: TeamProvisioningBannerProps): React.JSX.Element | null => { const { progress, cancelProvisioning, teamMembers } = useStore( useShallow((s) => ({ progress: getCurrentProvisioningProgressForTeam(s, teamName), cancelProvisioning: s.cancelProvisioning, teamMembers: s.selectedTeamData?.members, })) ); const [dismissed, setDismissed] = useState(false); const bannerInstanceKey = useMemo(() => { if (!progress) return null; return `${teamName}:${progress.runId}:${progress.startedAt}`; }, [teamName, progress?.runId, progress?.startedAt]); useEffect(() => { setDismissed(false); }, [bannerInstanceKey]); // NOTE: we intentionally do NOT auto-dismiss "ready" banners. // Users frequently need to inspect launch output after fast stop→start cycles, // and auto-dismiss can make it look like no progress/logs were produced. if (!progress || dismissed) { return null; } if (progress.state === 'cancelled' || progress.state === 'disconnected') { return null; } const isReady = progress.state === 'ready'; const isFailed = progress.state === 'failed'; const isActive = progress.state === 'validating' || progress.state === 'spawning' || progress.state === 'monitoring' || progress.state === 'verifying'; const canCancel = progress.state === 'spawning' || progress.state === 'monitoring' || progress.state === 'verifying'; const progressStepIndex = STEP_ORDER.indexOf(progress.state as ProvisioningStep); if (isFailed) { return (

{progress.message}

= 0 ? progressStepIndex : -1} startedAt={progress.startedAt} pid={progress.pid} cliLogsTail={progress.cliLogsTail} assistantOutput={progress.assistantOutput} defaultLiveOutputOpen onCancel={null} />
); } const allTeammatesOnline = teamMembers != null && teamMembers.length > 0 && teamMembers.every((m) => m.status === 'active' || m.status === 'idle'); if (isReady) { const readyMessage = allTeammatesOnline ? `Team launched — all ${teamMembers.length} teammates online` : 'Team launched — teammates may still be starting'; return (

{readyMessage}

= 0 ? progressStepIndex : -1} startedAt={progress.startedAt} pid={progress.pid} cliLogsTail={progress.cliLogsTail} assistantOutput={progress.assistantOutput} defaultLiveOutputOpen={false} onCancel={null} />
); } if (isActive) { return (
= 0 ? progressStepIndex : -1} loading startedAt={progress.startedAt} pid={progress.pid} cliLogsTail={progress.cliLogsTail} assistantOutput={progress.assistantOutput} defaultLiveOutputOpen onCancel={ canCancel ? () => { void cancelProvisioning(progress.runId); } : null } />
); } return null; };