diff --git a/ui/src/components/ProcessDiagram/DiagramNode.tsx b/ui/src/components/ProcessDiagram/DiagramNode.tsx index bc8d6ece..7539677f 100644 --- a/ui/src/components/ProcessDiagram/DiagramNode.tsx +++ b/ui/src/components/ProcessDiagram/DiagramNode.tsx @@ -102,18 +102,6 @@ export function DiagramNode({ style={{ cursor: 'pointer' }} opacity={isSkipped ? 0.35 : undefined} > - {/* Processor metrics tooltip */} - {heatmapEntry && ( - {[ - `${node.id}${heatmapEntry.processorType ? ` (${heatmapEntry.processorType})` : ''}`, - `Avg: ${heatmapEntry.avgDurationMs.toLocaleString(undefined, { maximumFractionDigits: 3 })}ms`, - `P99: ${heatmapEntry.p99DurationMs.toLocaleString(undefined, { maximumFractionDigits: 3 })}ms`, - `Time: ${heatmapEntry.pctOfRoute.toFixed(1)}%`, - heatmapEntry.totalCount != null ? `Invocations: ${heatmapEntry.totalCount.toLocaleString()}` : '', - heatmapEntry.errorRate != null ? `Errors: ${(heatmapEntry.errorRate * 100).toFixed(2)}%` : '', - ].filter(Boolean).join('\n')} - )} - {/* Selection ring */} {isSelected && ( { + const hNode = findNodeById(sections, toolbar.hoveredNodeId!); + const entry = hNode ? latencyHeatmap.get(hNode.id) : undefined; + if (!hNode || !entry) return null; + const nodeCenter = (hNode.x ?? 0) + (hNode.width ?? 160) / 2; + const nodeBottom = (hNode.y ?? 0) + (hNode.height ?? 40); + const screenX = nodeCenter * zoom.state.scale + zoom.state.translateX; + const screenY = nodeBottom * zoom.state.scale + zoom.state.translateY; + const fmtMs = (v: number) => v.toLocaleString(undefined, { maximumFractionDigits: 3 }); + return ( +
+
+ {hNode.id}{entry.processorType ? ` (${entry.processorType})` : ''} +
+
+ Avg + {fmtMs(entry.avgDurationMs)}ms + P99 + {fmtMs(entry.p99DurationMs)}ms + % Time + {entry.pctOfRoute.toFixed(1)}% + {entry.totalCount != null && (<> + Invocations + {entry.totalCount.toLocaleString()} + )} + {entry.errorRate != null && (<> + Error Rate + {(entry.errorRate * 100).toFixed(2)}% + )} +
+
+ ); + })()} +