diff --git a/public/js/app.js b/public/js/app.js index 7c572fe..53ac5da 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -970,6 +970,25 @@
+ ${m.key === 'networkTrend' ? ` + ` : ''} `).join(''); @@ -1073,12 +1092,62 @@ data.series = null; // This tells MetricChart to draw a single line instead of stacked area } + if (metricKey === 'networkTrend') { + const stats = calculateHistoryStats(data); + const summaryDiv = document.getElementById(`summary-${metricKey}`); + if (summaryDiv) { + summaryDiv.style.display = 'flex'; + const rxEl = document.getElementById(`stat-${metricKey}-rx`); + const txEl = document.getElementById(`stat-${metricKey}-tx`); + const p95El = document.getElementById(`stat-${metricKey}-p95`); + const totalEl = document.getElementById(`stat-${metricKey}-total`); + + if (rxEl) rxEl.textContent = formatBytes(stats.rxTotal); + if (txEl) txEl.textContent = formatBytes(stats.txTotal); + if (p95El) p95El.textContent = formatBandwidth(stats.p95); + if (totalEl) totalEl.textContent = formatBytes(stats.total); + } + } + chart.setData(data); } catch (err) { console.error(`Error loading history for ${metricKey}:`, err); } }; + function calculateHistoryStats(data) { + if (!data.timestamps || data.timestamps.length < 2) { + return { rxTotal: 0, txTotal: 0, p95: 0, total: 0 }; + } + + const tx = data.tx || []; + const rx = data.rx || []; + const ts = data.timestamps; + + let rxTotal = 0; + let txTotal = 0; + + for (let i = 0; i < ts.length - 1; i++) { + // Find interval in seconds + const duration = (ts[i+1] - ts[i]) / 1000; + // Bandwidth (B/s) * time (s) = Bytes + rxTotal += (rx[i] || 0) * duration; + txTotal += (tx[i] || 0) * duration; + } + + // P95 calculation for TX (consistent with AreaChart) + const sortedTx = [...tx].sort((a, b) => a - b); + const p95Idx = Math.floor(sortedTx.length * 0.95); + const p95 = sortedTx.length > 0 ? sortedTx[p95Idx] : 0; + + return { + rxTotal, + txTotal, + p95, + total: rxTotal + txTotal + }; + } + window.loadCustomMetricHistory = async function (metricKey, event) { if (event) event.stopPropagation();