Skip to content

Commit 264b107

Browse files
authored
Merge pull request microsoft#475 from microsoft/macae-v3-fr-dev-92
Add plan execution spinner to PlanChat flow
2 parents 6eb905a + 98389c4 commit 264b107

File tree

3 files changed

+52
-6
lines changed

3 files changed

+52
-6
lines changed

src/frontend/src/components/content/PlanChat.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { AgentMessageData, WebsocketMessageType } from "@/models";
2828
import getUserPlan from "./streaming/StreamingUserPlan";
2929
import renderUserPlanMessage from "./streaming/StreamingUserPlanMessage";
3030
import renderPlanResponse from "./streaming/StreamingPlanResponse";
31-
import renderThinkingState from "./streaming/StreamingPlanState";
31+
import { renderPlanExecutionMessage, renderThinkingState } from "./streaming/StreamingPlanState";
3232
import ContentNotFound from "../NotFound/ContentNotFound";
3333
import PlanChatBody from "./PlanChatBody";
3434
import renderBufferMessage from "./streaming/StreamingBufferMessage";
@@ -42,6 +42,8 @@ interface SimplifiedPlanChatProps extends PlanChatProps {
4242
messagesContainerRef: React.RefObject<HTMLDivElement>;
4343
streamingMessageBuffer: string;
4444
agentMessages: AgentMessageData[];
45+
showProcessingPlanSpinner: boolean;
46+
setShowProcessingPlanSpinner: (show: boolean) => void;
4547
}
4648

4749
const PlanChat: React.FC<SimplifiedPlanChatProps> = ({
@@ -57,7 +59,9 @@ const PlanChat: React.FC<SimplifiedPlanChatProps> = ({
5759
waitingForPlan,
5860
messagesContainerRef,
5961
streamingMessageBuffer,
60-
agentMessages
62+
agentMessages,
63+
showProcessingPlanSpinner,
64+
setShowProcessingPlanSpinner
6165

6266
}) => {
6367
const navigate = useNavigate();
@@ -91,6 +95,7 @@ const PlanChat: React.FC<SimplifiedPlanChatProps> = ({
9195

9296
dismissToast(id);
9397
onPlanApproval?.(true);
98+
setShowProcessingPlanSpinner?.(true);
9499
setShowApprovalButtons(false);
95100

96101
} catch (error) {
@@ -100,7 +105,7 @@ const PlanChat: React.FC<SimplifiedPlanChatProps> = ({
100105
} finally {
101106
setProcessingApproval(false);
102107
}
103-
}, [planApprovalRequest, planData, onPlanApproval]);
108+
}, [planApprovalRequest, planData, onPlanApproval, setShowProcessingPlanSpinner]);
104109

105110
// Handle plan rejection
106111
const handleRejectPlan = useCallback(async () => {
@@ -164,9 +169,10 @@ const PlanChat: React.FC<SimplifiedPlanChatProps> = ({
164169
{renderPlanResponse(planApprovalRequest, handleApprovePlan, handleRejectPlan, processingApproval, showApprovalButtons)}
165170
{renderAgentMessages(agentMessages)}
166171

167-
172+
{showProcessingPlanSpinner && renderPlanExecutionMessage()}
168173
{/* Streaming plan updates */}
169174
{renderBufferMessage(streamingMessageBuffer)}
175+
170176
</div>
171177

172178
{/* Chat Input - only show if no plan is waiting for approval */}

src/frontend/src/components/content/streaming/StreamingPlanState.tsx

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Spinner } from "@fluentui/react-components";
1+
import { Spinner, tokens } from "@fluentui/react-components";
22
import { BotRegular } from "@fluentui/react-icons";
33

44
// Render AI thinking/planning state
@@ -44,4 +44,35 @@ const renderThinkingState = (waitingForPlan: boolean) => {
4444
</div>
4545
);
4646
};
47-
export default renderThinkingState;
47+
48+
49+
// Simple message to show while executing the plan
50+
51+
const renderPlanExecutionMessage = () => {
52+
return (
53+
<div style={{
54+
maxWidth: '800px',
55+
margin: '0 auto',
56+
padding: `${tokens.spacingVerticalXL} ${tokens.spacingHorizontalXL}`,
57+
display: 'flex',
58+
alignItems: 'center',
59+
gap: tokens.spacingHorizontalM,
60+
backgroundColor: tokens.colorNeutralBackground2,
61+
borderRadius: tokens.borderRadiusMedium,
62+
border: `1px solid ${tokens.colorNeutralStroke1}`,
63+
marginBottom: tokens.spacingVerticalXL
64+
}}>
65+
<Spinner size="small" />
66+
<span style={{
67+
fontSize: '14px',
68+
color: tokens.colorNeutralForeground1,
69+
fontWeight: tokens.fontWeightSemibold
70+
}}>
71+
Processing your plan and coordinating with AI agents...
72+
</span>
73+
</div>
74+
);
75+
};
76+
77+
78+
export { renderPlanExecutionMessage, renderThinkingState };

src/frontend/src/pages/PlanPage.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ const PlanPage: React.FC = () => {
4949
const [planApprovalRequest, setPlanApprovalRequest] = useState<MPlanData | null>(null);
5050
const [reloadLeftList, setReloadLeftList] = useState(true);
5151
const [waitingForPlan, setWaitingForPlan] = useState(true);
52+
const [showProcessingPlanSpinner, setShowProcessingPlanSpinner] = useState<boolean>(false);
5253
// WebSocket connection state
5354
const [wsConnected, setWsConnected] = useState(false);
5455
const [streamingMessages, setStreamingMessages] = useState<StreamingPlanUpdate[]>([]);
@@ -111,6 +112,7 @@ const PlanPage: React.FC = () => {
111112
console.log('✅ Parsed plan data:', mPlanData);
112113
setPlanApprovalRequest(mPlanData);
113114
setWaitingForPlan(false);
115+
setShowProcessingPlanSpinner(false);
114116
// onPlanReceived?.(mPlanData);
115117
scrollToBottom();
116118
} else {
@@ -151,6 +153,7 @@ const PlanPage: React.FC = () => {
151153
setClarificationMessage(clarificationMessage.data as ParsedUserClarification | null);
152154
setAgentMessages(prev => [...prev, agentMessageData]);
153155
setStreamingMessageBuffer("");
156+
setShowProcessingPlanSpinner(false);
154157
setSubmittingChatDisableInput(false);
155158
scrollToBottom();
156159

@@ -185,6 +188,7 @@ const PlanPage: React.FC = () => {
185188
} as AgentMessageData;
186189
console.log('✅ Parsed final result message:', agentMessageData);
187190
setStreamingMessageBuffer("");
191+
setShowProcessingPlanSpinner(false);
188192
setAgentMessages(prev => [...prev, agentMessageData]);
189193
scrollToBottom();
190194

@@ -200,6 +204,7 @@ const PlanPage: React.FC = () => {
200204
console.log('📋 Agent Message', agentMessage);
201205
const agentMessageData = agentMessage.data as AgentMessageData;
202206
setAgentMessages(prev => [...prev, agentMessageData]);
207+
setShowProcessingPlanSpinner(true);
203208
scrollToBottom();
204209
});
205210

@@ -396,9 +401,11 @@ const PlanPage: React.FC = () => {
396401

397402
setAgentMessages(prev => [...prev, agentMessageData]);
398403
setSubmittingChatDisableInput(true);
404+
setShowProcessingPlanSpinner(true);
399405
scrollToBottom();
400406

401407
} catch (error: any) {
408+
setShowProcessingPlanSpinner(false);
402409
dismissToast(id);
403410
setSubmittingChatDisableInput(false);
404411
showToast(
@@ -511,11 +518,13 @@ const PlanPage: React.FC = () => {
511518
streamingMessages={streamingMessages}
512519
wsConnected={wsConnected}
513520
onPlanApproval={(approved) => setPlanApproved(approved)}
521+
onPlanProcessing={(showProcessingPlanSpinner) => setShowProcessingPlanSpinner(showProcessingPlanSpinner)}
514522
planApprovalRequest={planApprovalRequest}
515523
waitingForPlan={waitingForPlan}
516524
messagesContainerRef={messagesContainerRef}
517525
streamingMessageBuffer={streamingMessageBuffer}
518526
agentMessages={agentMessages}
527+
showProcessingPlanSpinner={showProcessingPlanSpinner}
519528

520529
/>
521530
</>

0 commit comments

Comments
 (0)