feat(#118): add confirmation dialog for stop and suspend commands
Some checks failed
CI / cleanup-branch (push) Has been skipped
CI / build (push) Failing after 35s
CI / docker (push) Has been skipped
CI / deploy (push) Has been skipped
CI / deploy-feature (push) Has been skipped

Stop and suspend route commands now show a ConfirmDialog requiring
typed confirmation before dispatch. Start and resume execute
immediately without confirmation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-02 18:54:23 +02:00
parent d21d8b2c48
commit f39f07e7bf

View File

@@ -1,6 +1,6 @@
import { useState } from 'react'; import { useState, useCallback } from 'react';
import { Play, Square, Pause, PlayCircle, RotateCcw, Loader2 } from 'lucide-react'; import { Play, Square, Pause, PlayCircle, RotateCcw, Loader2 } from 'lucide-react';
import { useToast } from '@cameleer/design-system'; import { useToast, ConfirmDialog } from '@cameleer/design-system';
import { useSendRouteCommand, useReplayExchange } from '../../api/queries/commands'; import { useSendRouteCommand, useReplayExchange } from '../../api/queries/commands';
import styles from './RouteControlBar.module.css'; import styles from './RouteControlBar.module.css';
@@ -30,8 +30,18 @@ export function RouteControlBar({ application, routeId, hasRouteControl, hasRepl
const replayExchange = useReplayExchange(); const replayExchange = useReplayExchange();
const [sendingAction, setSendingAction] = useState<string | null>(null); const [sendingAction, setSendingAction] = useState<string | null>(null);
const [pendingConfirm, setPendingConfirm] = useState<RouteAction | null>(null);
const busy = sendingAction !== null; const busy = sendingAction !== null;
const handleRouteClick = useCallback((action: RouteAction) => {
if (action === 'stop' || action === 'suspend') {
setPendingConfirm(action);
} else {
handleRouteAction(action);
}
}, []);
function handleRouteAction(action: RouteAction) { function handleRouteAction(action: RouteAction) {
setSendingAction(action); setSendingAction(action);
sendRouteCommand.mutate( sendRouteCommand.mutate(
@@ -83,7 +93,7 @@ export function RouteControlBar({ application, routeId, hasRouteControl, hasRepl
key={action} key={action}
className={`${styles.segment} ${colorClass}`} className={`${styles.segment} ${colorClass}`}
disabled={busy} disabled={busy}
onClick={() => handleRouteAction(action)} onClick={() => handleRouteClick(action)}
title={`${label} route ${routeId}`} title={`${label} route ${routeId}`}
> >
{sendingAction === action {sendingAction === action
@@ -110,6 +120,20 @@ export function RouteControlBar({ application, routeId, hasRouteControl, hasRepl
</button> </button>
</div> </div>
)} )}
<ConfirmDialog
open={pendingConfirm !== null}
onClose={() => setPendingConfirm(null)}
onConfirm={() => {
if (pendingConfirm) handleRouteAction(pendingConfirm);
setPendingConfirm(null);
}}
title={`${pendingConfirm === 'stop' ? 'Stop' : 'Suspend'} route?`}
message={`This will ${pendingConfirm} route "${routeId}" on ${application}. This affects all live agents.`}
confirmText={pendingConfirm ?? ''}
confirmLabel={pendingConfirm === 'stop' ? 'Stop Route' : 'Suspend Route'}
variant={pendingConfirm === 'stop' ? 'danger' : 'warning'}
loading={busy}
/>
</div> </div>
); );
} }