Skip to content

Commit f8b21ab

Browse files
Add Popup for timeout
1 parent 87bd074 commit f8b21ab

4 files changed

Lines changed: 94 additions & 0 deletions

File tree

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import React from 'react';
2+
import {
3+
Dialog,
4+
DialogSurface,
5+
DialogTitle,
6+
DialogContent,
7+
DialogBody,
8+
DialogActions,
9+
Button,
10+
} from '@fluentui/react-components';
11+
import { Clock20Regular } from '@fluentui/react-icons';
12+
import "../../styles/Panel.css";
13+
14+
interface SessionTimeoutDialogProps {
15+
isOpen: boolean;
16+
onGoHome: () => void;
17+
}
18+
19+
/**
20+
* Non-dismissible dialog shown when the backend plan approval session times out.
21+
* No close button, no outside click dismiss, no escape key dismiss.
22+
*/
23+
const SessionTimeoutDialog: React.FC<SessionTimeoutDialogProps> = ({
24+
isOpen,
25+
onGoHome,
26+
}) => {
27+
return (
28+
<Dialog
29+
open={isOpen}
30+
modalType="alert"
31+
onOpenChange={() => {
32+
// Prevent any dismiss action (escape key, outside click)
33+
}}
34+
>
35+
<DialogSurface>
36+
<DialogBody>
37+
<DialogTitle
38+
action={null}
39+
>
40+
<div className="plan-cancellation-dialog-title">
41+
<Clock20Regular className="plan-cancellation-warning-icon" />
42+
Session Timed Out
43+
</div>
44+
</DialogTitle>
45+
<DialogContent>
46+
Session timed out. Please go back to the home page.
47+
</DialogContent>
48+
<DialogActions>
49+
<Button
50+
appearance="primary"
51+
onClick={onGoHome}
52+
>
53+
Go To Home
54+
</Button>
55+
</DialogActions>
56+
</DialogBody>
57+
</DialogSurface>
58+
</Dialog>
59+
);
60+
};
61+
62+
export default SessionTimeoutDialog;

src/frontend/src/models/enums.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ export enum WebsocketMessageType {
253253
USER_CLARIFICATION_REQUEST = "user_clarification_request",
254254
USER_CLARIFICATION_RESPONSE = "user_clarification_response",
255255
FINAL_RESULT_MESSAGE = "final_result_message",
256+
TIMEOUT_NOTIFICATION = "timeout_notification",
256257
ERROR_MESSAGE = 'error_message'
257258
}
258259

src/frontend/src/pages/PlanPage.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { APIService } from "../api/apiService";
2020
import { StreamMessage, StreamingPlanUpdate } from "../models";
2121
import { usePlanCancellationAlert } from "../hooks/usePlanCancellationAlert";
2222
import PlanCancellationDialog from "../components/common/PlanCancellationDialog";
23+
import SessionTimeoutDialog from "../components/common/SessionTimeoutDialog";
2324
import "../styles/PlanPage.css"
2425

2526
// Create API service instance
@@ -75,6 +76,9 @@ const PlanPage: React.FC = () => {
7576
const [pendingNavigation, setPendingNavigation] = useState<(() => void) | null>(null);
7677
const [cancellingPlan, setCancellingPlan] = useState<boolean>(false);
7778

79+
// Session timeout dialog state
80+
const [showSessionTimeoutDialog, setShowSessionTimeoutDialog] = useState<boolean>(false);
81+
7882
const [loadingMessage, setLoadingMessage] = useState<string>(loadingMessages[0]);
7983

8084
// Plan cancellation alert hook
@@ -443,6 +447,19 @@ const PlanPage: React.FC = () => {
443447
return () => unsubscribe();
444448
}, [scrollToBottom, showToast, formatErrorMessage]);
445449

450+
// WebsocketMessageType.TIMEOUT_NOTIFICATION
451+
useEffect(() => {
452+
const unsubscribe = webSocketService.on(WebsocketMessageType.TIMEOUT_NOTIFICATION, (timeoutMessage: any) => {
453+
console.log('⏰ Timeout notification received:', timeoutMessage);
454+
setShowSessionTimeoutDialog(true);
455+
setShowProcessingPlanSpinner(false);
456+
setShowBufferingText(false);
457+
webSocketService.disconnect();
458+
});
459+
460+
return () => unsubscribe();
461+
}, []);
462+
446463
//WebsocketMessageType.AGENT_MESSAGE
447464
useEffect(() => {
448465
const unsubscribe = webSocketService.on(WebsocketMessageType.AGENT_MESSAGE, (agentMessage: any) => {
@@ -838,6 +855,15 @@ const PlanPage: React.FC = () => {
838855
onCancel={handleCancelDialog}
839856
loading={cancellingPlan}
840857
/>
858+
859+
{/* Session Timeout Dialog */}
860+
<SessionTimeoutDialog
861+
isOpen={showSessionTimeoutDialog}
862+
onGoHome={() => {
863+
setShowSessionTimeoutDialog(false);
864+
navigate('/');
865+
}}
866+
/>
841867
</CoralShellColumn>
842868
);
843869
};

src/frontend/src/services/WebSocketService.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,11 @@ class WebSocketService {
247247
this.emit(WebsocketMessageType.ERROR_MESSAGE, message.data); // Emit the data
248248
break;
249249
}
250+
case WebsocketMessageType.TIMEOUT_NOTIFICATION: {
251+
console.log("Received TIMEOUT_NOTIFICATION:", message);
252+
this.emit(WebsocketMessageType.TIMEOUT_NOTIFICATION, message);
253+
break;
254+
}
250255
case WebsocketMessageType.USER_CLARIFICATION_RESPONSE:
251256
case WebsocketMessageType.REPLAN_APPROVAL_REQUEST:
252257
case WebsocketMessageType.REPLAN_APPROVAL_RESPONSE:

0 commit comments

Comments
 (0)