From 4473cd93b1060fd1c21dea1da94c407260dd3c09 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Thu, 29 Jan 2026 10:50:01 -0800 Subject: [PATCH] Fix network table: add upstream column, get stats from switch port Co-Authored-By: Claude Opus 4.5 --- static/index.html | 112 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 28 deletions(-) diff --git a/static/index.html b/static/index.html index 5d24736..3b5be64 100644 --- a/static/index.html +++ b/static/index.html @@ -2433,37 +2433,93 @@ function renderNetworkTable() { const nodes = tableData.nodes || []; + const links = tableData.links || []; + + const nodesByTypeId = new Map(); + nodes.forEach(node => nodesByTypeId.set(node.id, node)); + + const upstreamConnections = new Map(); + const allSwitches = nodes.filter(n => isSwitch(n)); + const switchIds = new Set(allSwitches.map(s => s.id)); + + links.forEach(link => { + const nodeA = nodesByTypeId.get(link.node_a?.id); + const nodeB = nodesByTypeId.get(link.node_b?.id); + if (!nodeA || !nodeB) return; + + const aIsSwitch = isSwitch(nodeA); + const bIsSwitch = isSwitch(nodeB); + + if (aIsSwitch && !bIsSwitch) { + upstreamConnections.set(nodeB.id, { + switchName: getLabel(nodeA), + port: link.interface_a || '?', + speed: getInterfaceSpeed(link.node_a), + errors: getInterfaceErrors(link.node_a), + rates: getInterfaceRates(link.node_a) + }); + } else if (bIsSwitch && !aIsSwitch) { + upstreamConnections.set(nodeA.id, { + switchName: getLabel(nodeB), + port: link.interface_b || '?', + speed: getInterfaceSpeed(link.node_b), + errors: getInterfaceErrors(link.node_b), + rates: getInterfaceRates(link.node_b) + }); + } else if (aIsSwitch && bIsSwitch) { + if (!upstreamConnections.has(nodeA.id)) { + upstreamConnections.set(nodeA.id, { + switchName: getLabel(nodeB), + port: link.interface_b || '?', + speed: getInterfaceSpeed(link.node_a), + errors: getInterfaceErrors(link.node_a), + rates: getInterfaceRates(link.node_a) + }); + } + if (!upstreamConnections.has(nodeB.id)) { + upstreamConnections.set(nodeB.id, { + switchName: getLabel(nodeA), + port: link.interface_a || '?', + speed: getInterfaceSpeed(link.node_b), + errors: getInterfaceErrors(link.node_b), + rates: getInterfaceRates(link.node_b) + }); + } + } + }); + + const formatMbps = (bytesPerSec) => { + const mbps = (bytesPerSec * 8) / 1000000; + return mbps.toFixed(1); + }; + let rows = nodes.map(node => { const name = getLabel(node); const ips = []; - const macs = []; - let speed = 0; - let inErrors = 0, outErrors = 0; - let inRate = 0, outRate = 0; (node.interfaces || []).forEach(iface => { if (iface.ips) iface.ips.forEach(ip => ips.push(ip)); - if (iface.mac) macs.push(iface.mac); - if (iface.stats) { - speed = Math.max(speed, iface.stats.speed || 0); - inErrors += iface.stats.in_errors || 0; - outErrors += iface.stats.out_errors || 0; - inRate += iface.stats.in_bytes_rate || 0; - outRate += iface.stats.out_bytes_rate || 0; - } }); + + const conn = upstreamConnections.get(node.id); + const upstream = conn ? conn.switchName + ':' + conn.port : ''; + const speed = conn?.speed || 0; + const errors = conn?.errors || { in: 0, out: 0 }; + const rates = conn?.rates || { inBytes: 0, outBytes: 0 }; + const isUnreachable = node.unreachable; - const speedStr = speed >= 1e9 ? (speed/1e9)+'G' : speed >= 1e6 ? (speed/1e6)+'M' : speed > 0 ? speed : ''; + const speedStr = speed >= 1e9 ? (speed/1e9)+'G' : speed >= 1e6 ? (speed/1e6)+'M' : speed > 0 ? speed : '0'; + return { name, ip: ips[0] || '', - mac: macs[0] || '', - speed: speed, + upstream, + speed, speedStr, - inErrors, - outErrors, - inRate: Math.round(inRate), - outRate: Math.round(outRate), - status: isUnreachable ? 'unreachable' : (inErrors + outErrors > 0 ? 'errors' : 'ok') + inErrors: errors.in, + outErrors: errors.out, + inRate: rates.inBytes, + outRate: rates.outBytes, + status: isUnreachable ? 'unreachable' : (errors.in + errors.out > 0 ? 'errors' : 'ok') }; }); @@ -2474,12 +2530,12 @@ let html = ''; html += ''; html += ''; - html += ''; + html += ''; html += ''; html += ''; html += ''; - html += ''; - html += ''; + html += ''; + html += ''; html += ''; html += ''; @@ -2488,12 +2544,12 @@ html += ''; html += ''; html += ''; - html += ''; + html += ''; html += ''; - html += ''; - html += ''; - html += ''; - html += ''; + html += ''; + html += ''; + html += ''; + html += ''; html += ''; html += ''; });
NameIPMACUpstreamSpeedIn ErrOut ErrIn RateOut RateIn Mbit/sOut Mbit/sStatus
' + escapeHtml(r.name) + '' + escapeHtml(r.ip) + '' + escapeHtml(r.mac) + '' + escapeHtml(r.upstream) + '' + r.speedStr + '' + (r.inErrors || '') + '' + (r.outErrors || '') + '' + formatBytes(r.inRate) + '' + formatBytes(r.outRate) + '' + r.inErrors + '' + r.outErrors + '' + formatMbps(r.inRate) + '' + formatMbps(r.outRate) + '' + r.status + '