diff --git a/ui/src/components/ExecutionDiagram/types.ts b/ui/src/components/ExecutionDiagram/types.ts new file mode 100644 index 00000000..5837fbd3 --- /dev/null +++ b/ui/src/components/ExecutionDiagram/types.ts @@ -0,0 +1,24 @@ +import type { components } from '../../api/schema'; + +export type ExecutionDetail = components['schemas']['ExecutionDetail']; +export type ProcessorNode = components['schemas']['ProcessorNode']; + +export interface NodeExecutionState { + status: 'COMPLETED' | 'FAILED'; + durationMs: number; + /** True if this node's target sub-route failed (DIRECT/SEDA) */ + subRouteFailed?: boolean; + /** True if trace data is available for this processor */ + hasTraceData?: boolean; +} + +export interface IterationInfo { + /** Current iteration index (0-based) */ + current: number; + /** Total number of iterations */ + total: number; + /** Type of iteration (determines label) */ + type: 'loop' | 'split' | 'multicast'; +} + +export type DetailTab = 'info' | 'headers' | 'input' | 'output' | 'error' | 'config' | 'timeline'; diff --git a/ui/src/components/ProcessDiagram/ProcessDiagram.tsx b/ui/src/components/ProcessDiagram/ProcessDiagram.tsx index 7269c262..d9c6bdbc 100644 --- a/ui/src/components/ProcessDiagram/ProcessDiagram.tsx +++ b/ui/src/components/ProcessDiagram/ProcessDiagram.tsx @@ -52,6 +52,7 @@ export function ProcessDiagram({ nodeConfigs, knownRouteIds, className, + diagramLayout, }: ProcessDiagramProps) { // Route stack for drill-down navigation const [routeStack, setRouteStack] = useState([routeId]); @@ -64,7 +65,7 @@ export function ProcessDiagram({ const currentRouteId = routeStack[routeStack.length - 1]; const { sections, totalWidth, totalHeight, isLoading, error } = useDiagramData( - application, currentRouteId, direction, + application, currentRouteId, direction, diagramLayout, ); const zoom = useZoomPan(); diff --git a/ui/src/components/ProcessDiagram/types.ts b/ui/src/components/ProcessDiagram/types.ts index 41e153e0..01d3776d 100644 --- a/ui/src/components/ProcessDiagram/types.ts +++ b/ui/src/components/ProcessDiagram/types.ts @@ -1,4 +1,5 @@ -import type { DiagramNode, DiagramEdge } from '../../api/queries/diagrams'; +import type { DiagramNode, DiagramEdge, DiagramLayout } from '../../api/queries/diagrams'; +import type { NodeExecutionState, IterationInfo } from '../ExecutionDiagram/types'; export type NodeAction = 'inspect' | 'toggle-trace' | 'configure-tap' | 'copy-id'; @@ -26,4 +27,12 @@ export interface ProcessDiagramProps { /** Known route IDs for this application (enables drill-down resolution) */ knownRouteIds?: Set; className?: string; + /** Pre-fetched diagram layout (bypasses internal fetch by application/routeId) */ + diagramLayout?: DiagramLayout; + /** Execution overlay: maps diagram node ID → execution state */ + executionOverlay?: Map; + /** Per-compound iteration info: maps compound node ID → iteration info */ + iterationState?: Map; + /** Called when user changes iteration on a compound stepper */ + onIterationChange?: (compoundNodeId: string, iterationIndex: number) => void; } diff --git a/ui/src/components/ProcessDiagram/useDiagramData.ts b/ui/src/components/ProcessDiagram/useDiagramData.ts index c23fa56b..fbf6a3f9 100644 --- a/ui/src/components/ProcessDiagram/useDiagramData.ts +++ b/ui/src/components/ProcessDiagram/useDiagramData.ts @@ -1,6 +1,6 @@ import { useMemo } from 'react'; import { useDiagramByRoute } from '../../api/queries/diagrams'; -import type { DiagramNode, DiagramEdge } from '../../api/queries/diagrams'; +import type { DiagramNode, DiagramEdge, DiagramLayout } from '../../api/queries/diagrams'; import type { DiagramSection } from './types'; import { isErrorCompoundType, isCompletionCompoundType } from './node-colors'; @@ -10,8 +10,14 @@ export function useDiagramData( application: string, routeId: string, direction: 'LR' | 'TB' = 'LR', + preloadedLayout?: DiagramLayout, ) { - const { data: layout, isLoading, error } = useDiagramByRoute(application, routeId, direction); + // When a preloaded layout is provided, disable the internal fetch + const fetchApp = preloadedLayout ? undefined : application; + const fetchRoute = preloadedLayout ? undefined : routeId; + const { data: fetchedLayout, isLoading, error } = useDiagramByRoute(fetchApp, fetchRoute, direction); + + const layout = preloadedLayout ?? fetchedLayout; const result = useMemo(() => { if (!layout?.nodes) { @@ -106,7 +112,11 @@ export function useDiagramData( return { sections, totalWidth, totalHeight }; }, [layout]); - return { ...result, isLoading, error }; + return { + ...result, + isLoading: preloadedLayout ? false : isLoading, + error: preloadedLayout ? null : error, + }; } /** Shift all node coordinates by subtracting an offset, recursively. */