From 16bb2c0b638101ad2b4fc037bd835022c6863ee8 Mon Sep 17 00:00:00 2001 From: iliya Date: Tue, 3 Mar 2026 16:14:05 +0200 Subject: [PATCH] feat: enhance ProvisioningProgressBlock with live output toggle and default state - Added a new prop `defaultLiveOutputOpen` to control the initial state of the live output section in the ProvisioningProgressBlock component. - Implemented state management for the live output visibility, allowing it to be expanded or collapsed based on user interaction. - Updated the UI to display a message when no output is captured, improving user feedback during provisioning processes. - Adjusted the TeamProvisioningBanner to utilize the new live output feature, enhancing the user experience during team provisioning. Made-with: Cursor --- .../team/ProvisioningProgressBlock.tsx | 56 ++++++++++++------- .../team/TeamProvisioningBanner.tsx | 6 ++ .../components/team/activity/ActivityItem.tsx | 24 ++++++-- .../team/dialogs/CreateTeamDialog.tsx | 24 +++++++- .../team/dialogs/LaunchTeamDialog.tsx | 24 +++++++- 5 files changed, 103 insertions(+), 31 deletions(-) diff --git a/src/renderer/components/team/ProvisioningProgressBlock.tsx b/src/renderer/components/team/ProvisioningProgressBlock.tsx index 8540b91c..29c7e229 100644 --- a/src/renderer/components/team/ProvisioningProgressBlock.tsx +++ b/src/renderer/components/team/ProvisioningProgressBlock.tsx @@ -19,6 +19,8 @@ export interface ProvisioningProgressBlockProps { message?: string | null; /** Visual tone (e.g. highlight errors) */ tone?: 'default' | 'error'; + /** Whether Live output is expanded by default */ + defaultLiveOutputOpen?: boolean; /** Index of the current step in STEP_ORDER (0-based), or -1 if unknown */ currentStepIndex: number; /** Show spinner next to title */ @@ -69,6 +71,7 @@ export const ProvisioningProgressBlock = ({ title, message, tone = 'default', + defaultLiveOutputOpen = true, currentStepIndex, loading = false, onCancel, @@ -80,16 +83,21 @@ export const ProvisioningProgressBlock = ({ }: ProvisioningProgressBlockProps): React.JSX.Element => { const elapsed = useElapsedTimer(startedAt); const [logsOpen, setLogsOpen] = useState(false); + const [liveOutputOpen, setLiveOutputOpen] = useState(defaultLiveOutputOpen); const outputScrollRef = useRef(null); const isError = tone === 'error'; - const hasAnyOutput = !!assistantOutput || !!cliLogsTail; // Auto-scroll assistant output useEffect(() => { - if (outputScrollRef.current) { + if (liveOutputOpen && outputScrollRef.current) { outputScrollRef.current.scrollTop = outputScrollRef.current.scrollHeight; } - }, [assistantOutput]); + }, [assistantOutput, liveOutputOpen]); + + // If parent changes the default (e.g. transitioning to "ready"), respect it. + useEffect(() => { + setLiveOutputOpen(defaultLiveOutputOpen); + }, [defaultLiveOutputOpen]); return (
- {assistantOutput ? ( -
-

Live output

+
+ + {liveOutputOpen ? (
- + {assistantOutput ? ( + + ) : ( +

+ No output captured yet. +

+ )}
-
- ) : null} + ) : null} +
{cliLogsTail ? (
) : null} - {!hasAnyOutput ? ( -

- No output captured yet. -

- ) : null}
); }; diff --git a/src/renderer/components/team/TeamProvisioningBanner.tsx b/src/renderer/components/team/TeamProvisioningBanner.tsx index 9cce9a3a..bb0177ba 100644 --- a/src/renderer/components/team/TeamProvisioningBanner.tsx +++ b/src/renderer/components/team/TeamProvisioningBanner.tsx @@ -111,6 +111,7 @@ export const TeamProvisioningBanner = ({ @@ -157,6 +159,7 @@ export const TeamProvisioningBanner = ({ = 0 ? progressStepIndex : -1} @@ -164,6 +167,7 @@ export const TeamProvisioningBanner = ({ pid={progress.pid} cliLogsTail={progress.cliLogsTail} assistantOutput={progress.assistantOutput} + defaultLiveOutputOpen={false} onCancel={null} /> @@ -174,6 +178,7 @@ export const TeamProvisioningBanner = ({ return (
= 0 ? progressStepIndex : -1} @@ -182,6 +187,7 @@ export const TeamProvisioningBanner = ({ pid={progress.pid} cliLogsTail={progress.cliLogsTail} assistantOutput={progress.assistantOutput} + defaultLiveOutputOpen onCancel={ canCancel ? () => { diff --git a/src/renderer/components/team/activity/ActivityItem.tsx b/src/renderer/components/team/activity/ActivityItem.tsx index 219a1a3b..9e18b173 100644 --- a/src/renderer/components/team/activity/ActivityItem.tsx +++ b/src/renderer/components/team/activity/ActivityItem.tsx @@ -176,6 +176,8 @@ export const ActivityItem = ({ const structured = parseStructuredAgentMessage(message.text); // Only flag agent messages as rate-limited, not user's own quotes const rateLimited = message.from !== 'user' && isRateLimitMessage(message.text); + // Highlight messages containing API errors + const isApiError = message.text.includes('API Error'); // Never collapse rate limit messages as noise — they must be visible const noiseLabel = structured && !rateLimited ? getNoiseLabel(structured) : null; @@ -225,11 +227,15 @@ export const ActivityItem = ({
{/* Header — div with role=button (cannot use