Fix KPIs on Dash
This commit is contained in:
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user