Batch 1 — Bug fixes: - #51: Pass group+routeId to stats/timeseries API for route-scoped data - #55: Propagate processor FAILED status to diagram error node highlighting Batch 2 — Visual polish: - #56: Brighter canvas background with amber/cyan radial gradients - #57: Stronger glow filters (stdDeviation 3→6, opacity 0.4→0.6) - #58: Uniform 200×40px leaf nodes with label truncation at 22 chars - #59: Diagram legend (node types, edge types, overlay indicators) - #64: SVG <title> tooltips on all nodes showing type, status, duration Batch 3 — Interactive features: - #60: Draggable minimap viewport (click-to-center, drag-to-pan) - #62: CSS View Transitions slide animation, back arrow, Backspace key Batch 4 — Advanced features: - #50: Execution picker dropdown scoped to group+routeId - #49: Iteration count badge (×N) on compound nodes - #63: Route header stats (Executions Today, Success Rate, Avg, P99) Closes #49 #50 #51 #55 #56 #57 #58 #59 #60 #62 #63 #64 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
74 lines
2.3 KiB
TypeScript
74 lines
2.3 KiB
TypeScript
import styles from './diagram.module.css';
|
|
|
|
interface LegendItem {
|
|
label: string;
|
|
color: string;
|
|
dashed?: boolean;
|
|
shape?: 'circle' | 'line';
|
|
}
|
|
|
|
const NODE_TYPES: LegendItem[] = [
|
|
{ label: 'Endpoint', color: '#58a6ff', shape: 'circle' },
|
|
{ label: 'EIP Pattern', color: '#b87aff', shape: 'circle' },
|
|
{ label: 'Processor', color: '#3fb950', shape: 'circle' },
|
|
{ label: 'Error Handler', color: '#f85149', shape: 'circle' },
|
|
{ label: 'Cross-route', color: '#39d2e0', shape: 'circle', dashed: true },
|
|
];
|
|
|
|
const EDGE_TYPES: LegendItem[] = [
|
|
{ label: 'Flow', color: '#4a5e7a', shape: 'line' },
|
|
{ label: 'Error', color: '#f85149', shape: 'line', dashed: true },
|
|
{ label: 'Cross-route', color: '#39d2e0', shape: 'line', dashed: true },
|
|
];
|
|
|
|
const OVERLAY_TYPES: LegendItem[] = [
|
|
{ label: 'Executed', color: '#3fb950', shape: 'circle' },
|
|
{ label: 'Execution path', color: '#3fb950', shape: 'line' },
|
|
{ label: 'Not executed', color: '#4a5e7a', shape: 'circle' },
|
|
];
|
|
|
|
function LegendRow({ item }: { item: LegendItem }) {
|
|
return (
|
|
<div className={styles.legendRow}>
|
|
{item.shape === 'circle' ? (
|
|
<span
|
|
className={styles.legendDot}
|
|
style={{
|
|
background: item.color,
|
|
border: item.dashed ? `1px dashed ${item.color}` : undefined,
|
|
opacity: item.label === 'Not executed' ? 0.3 : 1,
|
|
}}
|
|
/>
|
|
) : (
|
|
<span
|
|
className={styles.legendLine}
|
|
style={{
|
|
background: item.color,
|
|
borderStyle: item.dashed ? 'dashed' : 'solid',
|
|
}}
|
|
/>
|
|
)}
|
|
<span className={styles.legendLabel}>{item.label}</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function DiagramLegend() {
|
|
return (
|
|
<div className={styles.legend}>
|
|
<div className={styles.legendSection}>
|
|
<span className={styles.legendTitle}>Nodes</span>
|
|
{NODE_TYPES.map((t) => <LegendRow key={t.label} item={t} />)}
|
|
</div>
|
|
<div className={styles.legendSection}>
|
|
<span className={styles.legendTitle}>Edges</span>
|
|
{EDGE_TYPES.map((t) => <LegendRow key={t.label} item={t} />)}
|
|
</div>
|
|
<div className={styles.legendSection}>
|
|
<span className={styles.legendTitle}>Overlay</span>
|
|
{OVERLAY_TYPES.map((t) => <LegendRow key={t.label} item={t} />)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|