feat: show route control bar on topology diagram
When no exchange is selected, the topology-only diagram now shows the RouteControlBar above it (if the agent supports routeControl or replay and the user has OPERATOR/ADMIN role). This fixes a gap where suspended routes with no recent exchanges had no way to be resumed from the UI. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,12 +4,15 @@ import { useGlobalFilters, useToast } from '@cameleer/design-system';
|
||||
import { useExecutionDetail } from '../../api/queries/executions';
|
||||
import { useDiagramByRoute } from '../../api/queries/diagrams';
|
||||
import { useRouteCatalog } from '../../api/queries/catalog';
|
||||
import { useAgents } from '../../api/queries/agents';
|
||||
import { useApplicationConfig, useUpdateApplicationConfig } from '../../api/queries/commands';
|
||||
import type { TapDefinition, ConfigUpdateResponse } from '../../api/queries/commands';
|
||||
import { useAuthStore } from '../../auth/auth-store';
|
||||
import { useTracingStore } from '../../stores/tracing-store';
|
||||
import type { NodeAction, NodeConfig } from '../../components/ProcessDiagram/types';
|
||||
import { TapConfigModal } from '../../components/TapConfigModal';
|
||||
import { ExchangeHeader } from './ExchangeHeader';
|
||||
import { RouteControlBar } from './RouteControlBar';
|
||||
import { ExecutionDiagram } from '../../components/ExecutionDiagram/ExecutionDiagram';
|
||||
import { ProcessDiagram } from '../../components/ProcessDiagram';
|
||||
import styles from './ExchangesPage.module.css';
|
||||
@@ -148,6 +151,30 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS
|
||||
const diagramQuery = useDiagramByRoute(appId, routeId);
|
||||
|
||||
const { data: catalog } = useRouteCatalog(timeFrom, timeTo);
|
||||
|
||||
// Route state + capabilities for topology-only control bar
|
||||
const { data: agents } = useAgents(undefined, appId);
|
||||
const roles = useAuthStore((s) => s.roles);
|
||||
const canControl = roles.some(r => r === 'OPERATOR' || r === 'ADMIN');
|
||||
const { hasRouteControl, hasReplay } = useMemo(() => {
|
||||
if (!agents) return { hasRouteControl: false, hasReplay: false };
|
||||
const agentList = agents as any[];
|
||||
return {
|
||||
hasRouteControl: agentList.some((a: any) => a.capabilities?.routeControl === true),
|
||||
hasReplay: agentList.some((a: any) => a.capabilities?.replay === true),
|
||||
};
|
||||
}, [agents]);
|
||||
const routeState = useMemo(() => {
|
||||
if (!catalog) return undefined;
|
||||
for (const app of catalog as any[]) {
|
||||
if (app.applicationId !== appId) continue;
|
||||
for (const r of app.routes || []) {
|
||||
if (r.routeId === routeId) return (r.routeState ?? 'started') as 'started' | 'stopped' | 'suspended';
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}, [catalog, appId, routeId]);
|
||||
|
||||
const knownRouteIds = useMemo(() => {
|
||||
const ids = new Set<string>();
|
||||
if (catalog) {
|
||||
@@ -313,10 +340,19 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS
|
||||
);
|
||||
}
|
||||
|
||||
// No exchange selected: show topology-only diagram
|
||||
// No exchange selected: show topology-only diagram with route control bar
|
||||
if (diagramQuery.data) {
|
||||
return (
|
||||
<>
|
||||
{canControl && (hasRouteControl || hasReplay) && (
|
||||
<RouteControlBar
|
||||
application={appId}
|
||||
routeId={routeId}
|
||||
routeState={routeState}
|
||||
hasRouteControl={hasRouteControl}
|
||||
hasReplay={hasReplay}
|
||||
/>
|
||||
)}
|
||||
<ProcessDiagram
|
||||
application={appId}
|
||||
routeId={routeId}
|
||||
|
||||
Reference in New Issue
Block a user