feat: latency heatmap overlay on process diagram (#94)
Some checks failed
CI / cleanup-branch (push) Has been skipped
CI / build (push) Failing after 29s
CI / docker (push) Has been skipped
CI / deploy (push) Has been skipped
CI / deploy-feature (push) Has been skipped
SonarQube / sonarqube (push) Failing after 1m10s

Add latencyHeatmap prop to ProcessDiagram that colors nodes green→yellow→red
based on their relative contribution to route latency (pctOfRoute). Shows avg
duration label on each node. Threaded through CompoundNode for nested EIP
patterns. Heatmap is active only when no execution overlay is present.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-29 23:32:42 +02:00
parent 213aa86c47
commit b5c19b6774
4 changed files with 55 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
import type { DiagramNode as DiagramNodeType, DiagramEdge as DiagramEdgeType } from '../../api/queries/diagrams';
import type { NodeConfig } from './types';
import type { NodeConfig, LatencyHeatmapEntry } from './types';
import type { NodeExecutionState, IterationInfo } from '../ExecutionDiagram/types';
import { colorForType, isCompoundType, iconForType, type IconElement } from './node-colors';
import { DiagramNode } from './DiagramNode';
@@ -27,6 +27,7 @@ interface CompoundNodeProps {
iterationState?: Map<string, IterationInfo>;
/** Called when user changes iteration on a compound stepper */
onIterationChange?: (compoundNodeId: string, iterationIndex: number) => void;
latencyHeatmap?: Map<string, LatencyHeatmapEntry>;
onNodeClick: (nodeId: string) => void;
onNodeDoubleClick?: (nodeId: string) => void;
onNodeEnter: (nodeId: string) => void;
@@ -36,7 +37,7 @@ interface CompoundNodeProps {
export function CompoundNode({
node, edges, parentX = 0, parentY = 0,
selectedNodeId, hoveredNodeId, nodeConfigs, executionOverlay,
overlayActive, iterationState, onIterationChange,
overlayActive, iterationState, onIterationChange, latencyHeatmap,
onNodeClick, onNodeDoubleClick, onNodeEnter, onNodeLeave,
}: CompoundNodeProps) {
const x = (node.x ?? 0) - parentX;
@@ -61,7 +62,7 @@ export function CompoundNode({
const childProps = {
edges, selectedNodeId, hoveredNodeId, nodeConfigs, executionOverlay,
overlayActive, iterationState, onIterationChange,
overlayActive, iterationState, onIterationChange, latencyHeatmap,
onNodeClick, onNodeDoubleClick, onNodeEnter, onNodeLeave,
};
@@ -243,6 +244,7 @@ function renderChildren(
config={child.id ? props.nodeConfigs?.get(child.id) : undefined}
executionState={props.executionOverlay?.get(child.id ?? '')}
overlayActive={props.overlayActive}
heatmapEntry={child.id ? props.latencyHeatmap?.get(child.id) : undefined}
onClick={() => child.id && props.onNodeClick(child.id)}
onDoubleClick={() => child.id && props.onNodeDoubleClick?.(child.id)}
onMouseEnter={() => child.id && props.onNodeEnter(child.id)}