diff --git a/ui/src/components/ProcessDiagram/DiagramNode.tsx b/ui/src/components/ProcessDiagram/DiagramNode.tsx index 45905135..6175cbc3 100644 --- a/ui/src/components/ProcessDiagram/DiagramNode.tsx +++ b/ui/src/components/ProcessDiagram/DiagramNode.tsx @@ -1,8 +1,8 @@ +import React from 'react'; import type { DiagramNode as DiagramNodeType } from '../../api/queries/diagrams'; import type { NodeConfig, LatencyHeatmapEntry } from './types'; import type { NodeExecutionState } from '../ExecutionDiagram/types'; import { colorForType, iconForType, type IconElement } from './node-colors'; -import { ConfigBadge } from './ConfigBadge'; const TOP_BAR_HEIGHT = 6; const TEXT_LEFT = 32; @@ -176,38 +176,92 @@ export function DiagramNode({ )} - {/* Config badges */} - {(config || executionState?.hasTraceData) && ( - - )} + {/* Inline badges row: hasTrace, hasTap, status — inside card, top-right */} + {(() => { + const BADGE_R = 6; + const BADGE_D = BADGE_R * 2; + const BADGE_GAP = 3; + const cy = TOP_BAR_HEIGHT + BADGE_R + 2; + const showTrace = config?.traceEnabled || executionState?.hasTraceData; + const showTap = !!config?.tapExpression; + if (!showTrace && !showTap && !isCompleted && !isFailed) return null; + const badges: React.ReactNode[] = []; + let slot = 0; - {/* Execution overlay: status badge inside card, top-right corner */} - {isCompleted && ( - <> - - - - )} - {isFailed && ( - <> - - - - - - - - - - - - )} + // Status badge (rightmost, only during overlay) + const statusCx = w - BADGE_R - 4; + if (isCompleted) { + badges.push( + + + + + ); + slot++; + } else if (isFailed) { + badges.push( + + + + + + + + + + + + + ); + slot++; + } + + // Tap badge (before status) + if (showTap) { + const tapCx = statusCx - slot * (BADGE_D + BADGE_GAP); + badges.push( + + + + + + + ); + slot++; + } + + // Trace badge (leftmost) + if (showTrace) { + const traceCx = statusCx - slot * (BADGE_D + BADGE_GAP); + const tracePulse = overlayActive && executionState?.hasTraceData; + const traceHasData = executionState?.hasTraceData; + badges.push( + + {tracePulse && ( + <> + + + + + + + + + + )} + + + + + + + + + ); + } + + return <>{badges}; + })()} {/* Execution overlay: duration text at bottom-right */} {executionState && statusColor && ( diff --git a/ui/src/pages/Exchanges/ExchangesPage.tsx b/ui/src/pages/Exchanges/ExchangesPage.tsx index 9985d790..31531a63 100644 --- a/ui/src/pages/Exchanges/ExchangesPage.tsx +++ b/ui/src/pages/Exchanges/ExchangesPage.tsx @@ -152,13 +152,12 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS return map; }, [catalog]); - // Build nodeConfigs from tracing store + app config (for TRACE/TAP badges) + // Build nodeConfigs from app config (for TRACE/TAP badges) const { data: appConfig } = useApplicationConfig(appId); - const tracedMap = useTracingStore((s) => s.tracedProcessors[appId]); const nodeConfigs = useMemo(() => { const map = new Map(); - if (tracedMap) { - for (const pid of Object.keys(tracedMap)) { + if (appConfig?.tracedProcessors) { + for (const pid of Object.keys(appConfig.tracedProcessors)) { map.set(pid, { traceEnabled: true }); } } @@ -171,7 +170,7 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS } } return map; - }, [tracedMap, appConfig]); + }, [appConfig]); // Processor options for tap modal dropdown const processorOptions = useMemo(() => {