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(() => {