feat(#117): agent-count toasts and persistent error toast dismiss
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@ import { useExecutionDetail } from '../../api/queries/executions';
|
||||
import { useDiagramByRoute } from '../../api/queries/diagrams';
|
||||
import { useRouteCatalog } from '../../api/queries/catalog';
|
||||
import { useApplicationConfig, useUpdateApplicationConfig } from '../../api/queries/commands';
|
||||
import type { TapDefinition } from '../../api/queries/commands';
|
||||
import type { TapDefinition, ConfigUpdateResponse } from '../../api/queries/commands';
|
||||
import { useTracingStore } from '../../stores/tracing-store';
|
||||
import type { NodeAction, NodeConfig } from '../../components/ProcessDiagram/types';
|
||||
import { TapConfigModal } from '../../components/TapConfigModal';
|
||||
@@ -215,11 +215,16 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS
|
||||
const handleTapSave = useCallback((updatedConfig: typeof appConfig) => {
|
||||
if (!updatedConfig) return;
|
||||
updateConfig.mutate(updatedConfig, {
|
||||
onSuccess: (saved) => {
|
||||
toast({ title: 'Tap configuration saved', description: `Pushed to agents (v${saved.config.version})`, variant: 'success' });
|
||||
onSuccess: (saved: ConfigUpdateResponse) => {
|
||||
if (saved.pushResult.success) {
|
||||
toast({ title: 'Tap configuration saved', description: `Pushed to ${saved.pushResult.total}/${saved.pushResult.total} agents (v${saved.config.version})`, variant: 'success' });
|
||||
} else {
|
||||
const failed = [...saved.pushResult.responses.filter(r => r.status !== 'SUCCESS').map(r => r.agentId), ...saved.pushResult.timedOut];
|
||||
toast({ title: 'Tap configuration saved — partial push failure', description: `${saved.pushResult.responded}/${saved.pushResult.total} responded. Failed: ${failed.join(', ')}`, variant: 'warning', duration: 86_400_000 });
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
toast({ title: 'Tap update failed', description: 'Could not save configuration', variant: 'error' });
|
||||
toast({ title: 'Tap update failed', description: 'Could not save configuration', variant: 'error', duration: 86_400_000 });
|
||||
},
|
||||
});
|
||||
}, [updateConfig, toast]);
|
||||
@@ -228,11 +233,16 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS
|
||||
if (!appConfig) return;
|
||||
const taps = appConfig.taps.filter(t => t.tapId !== tap.tapId);
|
||||
updateConfig.mutate({ ...appConfig, taps }, {
|
||||
onSuccess: (saved) => {
|
||||
toast({ title: 'Tap deleted', description: `${tap.attributeName} removed (v${saved.config.version})`, variant: 'success' });
|
||||
onSuccess: (saved: ConfigUpdateResponse) => {
|
||||
if (saved.pushResult.success) {
|
||||
toast({ title: 'Tap deleted', description: `${tap.attributeName} removed — pushed to ${saved.pushResult.total}/${saved.pushResult.total} agents (v${saved.config.version})`, variant: 'success' });
|
||||
} else {
|
||||
const failed = [...saved.pushResult.responses.filter(r => r.status !== 'SUCCESS').map(r => r.agentId), ...saved.pushResult.timedOut];
|
||||
toast({ title: 'Tap deleted — partial push failure', description: `${saved.pushResult.responded}/${saved.pushResult.total} responded. Failed: ${failed.join(', ')}`, variant: 'warning', duration: 86_400_000 });
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
toast({ title: 'Tap delete failed', description: 'Could not save configuration', variant: 'error' });
|
||||
toast({ title: 'Tap delete failed', description: 'Could not save configuration', variant: 'error', duration: 86_400_000 });
|
||||
},
|
||||
});
|
||||
}, [appConfig, updateConfig, toast]);
|
||||
@@ -255,12 +265,17 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS
|
||||
...appConfig,
|
||||
tracedProcessors,
|
||||
}, {
|
||||
onSuccess: (saved) => {
|
||||
toast({ title: `Tracing ${enabled ? 'enabled' : 'disabled'}`, description: `${nodeId} — pushed to agents (v${saved.config.version})`, variant: 'success' });
|
||||
onSuccess: (saved: ConfigUpdateResponse) => {
|
||||
if (saved.pushResult.success) {
|
||||
toast({ title: `Tracing ${enabled ? 'enabled' : 'disabled'}`, description: `${nodeId} — pushed to ${saved.pushResult.total}/${saved.pushResult.total} agents (v${saved.config.version})`, variant: 'success' });
|
||||
} else {
|
||||
const failed = [...saved.pushResult.responses.filter(r => r.status !== 'SUCCESS').map(r => r.agentId), ...saved.pushResult.timedOut];
|
||||
toast({ title: `Tracing update — partial push failure`, description: `${saved.pushResult.responded}/${saved.pushResult.total} responded. Failed: ${failed.join(', ')}`, variant: 'warning', duration: 86_400_000 });
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
useTracingStore.getState().toggleProcessor(appId, nodeId);
|
||||
toast({ title: 'Tracing update failed', description: 'Could not save configuration', variant: 'error' });
|
||||
toast({ title: 'Tracing update failed', description: 'Could not save configuration', variant: 'error', duration: 86_400_000 });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useState, useCallback } from 'react';
|
||||
import { Play, Square, Pause, PlayCircle, RotateCcw, Loader2 } from 'lucide-react';
|
||||
import { useToast, ConfirmDialog } from '@cameleer/design-system';
|
||||
import { useSendRouteCommand, useReplayExchange } from '../../api/queries/commands';
|
||||
import type { CommandGroupResponse } from '../../api/queries/commands';
|
||||
import styles from './RouteControlBar.module.css';
|
||||
|
||||
interface RouteControlBarProps {
|
||||
@@ -47,12 +48,17 @@ export function RouteControlBar({ application, routeId, hasRouteControl, hasRepl
|
||||
sendRouteCommand.mutate(
|
||||
{ application, action, routeId },
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast({ title: `Route ${action} sent`, description: `${routeId} on ${application}`, variant: 'success' });
|
||||
onSuccess: (result: CommandGroupResponse) => {
|
||||
if (result.success) {
|
||||
toast({ title: `Route ${action} sent`, description: `${routeId} — ${result.total}/${result.total} agents responded`, variant: 'success' });
|
||||
} else {
|
||||
const failedAgents = [...result.responses.filter(r => r.status !== 'SUCCESS').map(r => r.agentId), ...result.timedOut];
|
||||
toast({ title: `Route ${action} — partial failure`, description: `${result.responded}/${result.total} responded. Failed: ${failedAgents.join(', ')}`, variant: 'warning', duration: 86_400_000 });
|
||||
}
|
||||
setSendingAction(null);
|
||||
},
|
||||
onError: (err) => {
|
||||
toast({ title: `Route ${action} failed`, description: err.message, variant: 'error' });
|
||||
toast({ title: `Route ${action} failed`, description: err.message, variant: 'error', duration: 86_400_000 });
|
||||
setSendingAction(null);
|
||||
},
|
||||
},
|
||||
@@ -71,12 +77,12 @@ export function RouteControlBar({ application, routeId, hasRouteControl, hasRepl
|
||||
if (result.status === 'SUCCESS') {
|
||||
toast({ title: 'Replay completed', description: result.message ?? `${routeId} on ${agentId}`, variant: 'success' });
|
||||
} else {
|
||||
toast({ title: 'Replay failed', description: result.message ?? 'Agent reported failure', variant: 'error' });
|
||||
toast({ title: 'Replay failed', description: result.message ?? 'Agent reported failure', variant: 'error', duration: 86_400_000 });
|
||||
}
|
||||
setSendingAction(null);
|
||||
},
|
||||
onError: (err) => {
|
||||
toast({ title: 'Replay failed', description: err.message, variant: 'error' });
|
||||
toast({ title: 'Replay failed', description: err.message, variant: 'error', duration: 86_400_000 });
|
||||
setSendingAction(null);
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user