// 2D topology — logical network map function Topology({ nodes, onSelect }) { const [hover, setHover] = React.useState(null); // layout: columns by group const layout = React.useMemo(() => { const W = 1600, H = Math.max(800, Math.ceil(Math.max(...window.GROUPS.map(g => nodes.filter(n => n.group === g).length)) / 2) * 70 + 280); const positions = {}; window.GROUPS.forEach((group, gi) => { const list = nodes.filter(n => n.group === group); const colX = 200 + gi * 280; list.forEach((n, i) => { const col = i % 2; const row = Math.floor(i / 2); positions[n.id] = { x: colX + col * 110, y: 200 + row * 62, }; }); }); return { positions, W, H }; }, [nodes]); const statusColor = (s) => s === 'ok' ? 'var(--ok)' : s === 'crit' ? 'var(--crit)' : (s === 'maint' || s === 'warn') ? 'var(--warn)' : 'var(--off)'; return (
{/* group columns */} {window.GROUPS.map((group, gi) => { const list = nodes.filter(n => n.group === group); if (!list.length) return null; const x = 180 + gi * 280; const h = Math.ceil(list.length / 2) * 62 + 70; return ( {group.toUpperCase()} · {list.length} ); })} {/* Viewer (top node) */} WAN monitoring · probes {/* Cloudflare edge */} CF-EDGE cloudflare {/* edges from CF-EDGE to group first node */} {window.GROUPS.map((group, gi) => { const list = nodes.filter(n => n.group === group); const first = list[0]; if (!first) return null; const p = layout.positions[first.id]; return ( ); })} {/* Nodes */} {nodes.map(n => { const p = layout.positions[n.id]; if (!p) return null; const col = statusColor(n.status); const isHover = hover === n.id; const label = n.displayName.length > 18 ? n.displayName.slice(0, 16) + '…' : n.displayName; return ( setHover(n.id)} onMouseLeave={() => setHover(null)} onClick={() => onSelect(n)}> {n.status === 'crit' && ( )} {n.status === 'crit' && } {label} {n.status === 'off' ? 'timeout' : `${n.latency.toFixed(0)}ms · ${n.httpCode}`} {isHover && ( {n.hostname} {n.protocol}:{n.port} · TLS {n.sslDaysLeft}d )} ); })}

Topology · logical

groups{window.GROUPS.length}
endpoints{nodes.length}
probes frommonitoring agent

Legend

up · 200-299
down · 5xx / 4xx
maintenance
timeout
); } Object.assign(window, { Topology });