Fix KPIs on Dash
CI / test (push) Successful in 1m7s
Release rolling / release (push) Successful in 7m16s

This commit is contained in:
Raven Scott
2026-07-19 12:12:05 -04:00
parent 64512e6358
commit 3c873c7a98
+62 -21
View File
@@ -490,6 +490,7 @@ function redrawCpu() {
function redrawAll() { function redrawAll() {
applyAnomalyHighlights() applyAnomalyHighlights()
syncOverviewKpis()
redrawCpu() redrawCpu()
const ramChart = anomalyByChart.has('mem.available') ? 'mem.available' : 'system.ram' const ramChart = anomalyByChart.has('mem.available') ? 'mem.available' : 'system.ram'
paint( paint(
@@ -691,6 +692,43 @@ function exploreValue(chart, values) {
function clearHostSeries() { function clearHostSeries() {
for (const key of Object.keys(series)) series[key] = [] for (const key of Object.keys(series)) series[key] = []
metricsDashboard.resetData() metricsDashboard.resetData()
syncOverviewKpis()
}
/** Latest finite value in an overview series, or null. */
function lastSeriesValue(key) {
const arr = series[key]
if (!arr?.length) return null
const v = arr[arr.length - 1]
return typeof v === 'number' && Number.isFinite(v) ? v : null
}
/**
* Sync Overview KPI labels from series (history seed + live).
* Charts are filled by seedHistory; KPI text used to update only on live pushes.
*/
function syncOverviewKpis() {
const cpu = lastSeriesValue('cpu')
if (els.statCpu) els.statCpu.textContent = cpu == null ? '—' : `${cpu.toFixed(1)}%`
const ram = lastSeriesValue('ram')
if (els.statRam) els.statRam.textContent = ram == null ? '—' : `${ram.toFixed(0)} MiB`
const load = lastSeriesValue('load')
if (els.statLoad) els.statLoad.textContent = load == null ? '—' : load.toFixed(2)
const net = lastSeriesValue('net')
if (els.statNet) els.statNet.textContent = net == null ? '—' : `${net.toFixed(1)} kb/s`
}
/** Map a queryData row to a values object keyed by dimension id. */
function rowToValues(labels, row) {
/** @type {Record<string, number|null>} */
const values = {}
if (!labels?.length || !row) return values
for (let i = 0; i < labels.length; i++) {
const name = labels[i]
if (!name || name === 'time') continue
values[name] = row[i] ?? null
}
return values
} }
/** /**
@@ -755,43 +793,38 @@ async function dialPeer(input, opts = {}) {
} }
function onSamples(samples, conn) { function onSamples(samples, conn) {
const peerId = conn?.publicKeyHex || manager.active?.publicKeyHex || 'active' const peerId = String(conn?.publicKeyHex || manager.active?.publicKeyHex || 'active').toLowerCase()
const isActive = Boolean(manager.active && manager.active.publicKeyHex === peerId) const activeId = String(manager.active?.publicKeyHex || '').toLowerCase()
const isActive = Boolean(activeId && activeId === peerId)
for (const s of samples || []) { for (const s of samples || []) {
if (s.chart === 'system.cpu') { if (s.chart === 'system.cpu') {
const used = 100 - (s.values.idle ?? 100) const used = 100 - (s.values?.idle ?? 100)
pushPeerCpu(peerId, used) pushPeerCpu(peerId, used)
if (isActive) { if (isActive) {
pushPoint('cpu', used) pushPoint('cpu', used)
if (s.values.user != null) pushPoint('cpuUser', s.values.user) if (s.values?.user != null) pushPoint('cpuUser', s.values.user)
if (s.values.system != null) pushPoint('cpuSystem', s.values.system) if (s.values?.system != null) pushPoint('cpuSystem', s.values.system)
if (s.values.iowait != null) pushPoint('cpuIowait', s.values.iowait) if (s.values?.iowait != null) pushPoint('cpuIowait', s.values.iowait)
els.statCpu.textContent = `${used.toFixed(1)}%`
} }
} }
if (!isActive) continue if (!isActive) continue
if (s.chart === 'system.ram') { if (s.chart === 'system.ram') {
const used = s.values.used ?? 0 pushPoint('ram', s.values?.used ?? 0)
pushPoint('ram', used)
els.statRam.textContent = `${used.toFixed(0)} MiB`
} }
if (s.chart === 'system.load') { if (s.chart === 'system.load') {
const load1 = s.values.load1 ?? 0 pushPoint('load', s.values?.load1 ?? 0)
pushPoint('load', load1)
els.statLoad.textContent = load1.toFixed(2)
} }
if (s.chart === 'system.net') { if (s.chart === 'system.net') {
const rx = s.values.received ?? 0 const rx = s.values?.received ?? 0
const tx = s.values.sent ?? s.values.transmitted ?? 0 const tx = s.values?.sent ?? s.values?.transmitted ?? 0
pushPoint('net', rx) pushPoint('net', rx)
pushPoint('netTx', tx) pushPoint('netTx', tx)
els.statNet.textContent = `${rx.toFixed(1)} kb/s`
} }
if (s.chart === 'system.io') { if (s.chart === 'system.io') {
pushPoint('io', s.values.reads ?? s.values.in ?? 0) pushPoint('io', s.values?.reads ?? s.values?.in ?? 0)
pushPoint('ioWrite', s.values.writes ?? s.values.out ?? 0) pushPoint('ioWrite', s.values?.writes ?? s.values?.out ?? 0)
} }
if (s.chart === exploreChartId) { if (s.chart === exploreChartId) {
pushPoint('explore', exploreValue(exploreChartId, s.values)) pushPoint('explore', exploreValue(exploreChartId, s.values))
@@ -1044,15 +1077,20 @@ async function seedHistory() {
points: max, points: max,
}) })
series[key] = [] series[key] = []
if (chart === 'system.cpu') { if (key === 'cpu') {
series.cpuUser = [] series.cpuUser = []
series.cpuSystem = [] series.cpuSystem = []
series.cpuIowait = [] series.cpuIowait = []
} }
if (chart === 'system.net') series.netTx = [] if (key === 'net') series.netTx = []
if (chart === 'system.io') series.ioWrite = [] if (key === 'io') series.ioWrite = []
for (const row of q.data || []) { for (const row of q.data || []) {
// Spotlight must always land in series.explore, even when chart is system.io/cpu/…
if (key === 'explore') {
pushPoint('explore', exploreValue(chart, rowToValues(q.labels, row)))
continue
}
if (chart === 'system.cpu') { if (chart === 'system.cpu') {
const idleIdx = q.labels?.indexOf('idle') ?? -1 const idleIdx = q.labels?.indexOf('idle') ?? -1
const userIdx = q.labels?.indexOf('user') ?? -1 const userIdx = q.labels?.indexOf('user') ?? -1
@@ -1063,6 +1101,9 @@ async function seedHistory() {
if (userIdx >= 0) pushPoint('cpuUser', row[userIdx] ?? 0) if (userIdx >= 0) pushPoint('cpuUser', row[userIdx] ?? 0)
if (sysIdx >= 0) pushPoint('cpuSystem', row[sysIdx] ?? 0) if (sysIdx >= 0) pushPoint('cpuSystem', row[sysIdx] ?? 0)
if (ioIdx >= 0) pushPoint('cpuIowait', row[ioIdx] ?? 0) if (ioIdx >= 0) pushPoint('cpuIowait', row[ioIdx] ?? 0)
} else if (chart === 'system.ram') {
const usedIdx = q.labels?.indexOf('used') ?? -1
pushPoint('ram', usedIdx >= 0 ? row[usedIdx] ?? 0 : row[2] ?? 0)
} else if (chart === 'system.net') { } else if (chart === 'system.net') {
const rxIdx = q.labels?.indexOf('received') ?? 1 const rxIdx = q.labels?.indexOf('received') ?? 1
const txIdx = q.labels?.indexOf('sent') ?? q.labels?.indexOf('transmitted') ?? -1 const txIdx = q.labels?.indexOf('sent') ?? q.labels?.indexOf('transmitted') ?? -1