KPI Autro Scale
CI / test (push) Successful in 1m3s
Release rolling / release (push) Successful in 7m10s

This commit is contained in:
Raven Scott
2026-07-19 12:30:09 -04:00
parent 3c873c7a98
commit b5b2907496
3 changed files with 93 additions and 2 deletions
+3 -2
View File
@@ -31,6 +31,7 @@ import {
renderFleetCards, renderFleetCards,
} from './ui/fleet.js' } from './ui/fleet.js'
import { createLogsView } from './ui/logs.js' import { createLogsView } from './ui/logs.js'
import { formatMib, formatKilobitsPerSec } from './shared/format.js'
const $ = (id) => document.getElementById(id) const $ = (id) => document.getElementById(id)
@@ -711,11 +712,11 @@ function syncOverviewKpis() {
const cpu = lastSeriesValue('cpu') const cpu = lastSeriesValue('cpu')
if (els.statCpu) els.statCpu.textContent = cpu == null ? '—' : `${cpu.toFixed(1)}%` if (els.statCpu) els.statCpu.textContent = cpu == null ? '—' : `${cpu.toFixed(1)}%`
const ram = lastSeriesValue('ram') const ram = lastSeriesValue('ram')
if (els.statRam) els.statRam.textContent = ram == null ? '—' : `${ram.toFixed(0)} MiB` if (els.statRam) els.statRam.textContent = formatMib(ram)
const load = lastSeriesValue('load') const load = lastSeriesValue('load')
if (els.statLoad) els.statLoad.textContent = load == null ? '—' : load.toFixed(2) if (els.statLoad) els.statLoad.textContent = load == null ? '—' : load.toFixed(2)
const net = lastSeriesValue('net') const net = lastSeriesValue('net')
if (els.statNet) els.statNet.textContent = net == null ? '—' : `${net.toFixed(1)} kb/s` if (els.statNet) els.statNet.textContent = formatKilobitsPerSec(net)
} }
/** Map a queryData row to a values object keyed by dimension id. */ /** Map a queryData row to a values object keyed by dimension id. */
+67
View File
@@ -0,0 +1,67 @@
/**
* Human-readable metric formatting with automatic unit scaling.
*/
/**
* @param {number} n
* @param {number} digits
*/
function trimFixed(n, digits) {
const s = n.toFixed(digits)
if (!s.includes('.')) return s
return s.replace(/0+$/, '').replace(/\.$/, '')
}
/**
* Pick decimal places from magnitude after scaling.
* @param {number} n
*/
function autoDigits(n) {
const a = Math.abs(n)
if (a >= 100) return 0
if (a >= 10) return 1
return 2
}
/**
* Scale a magnitude through a unit ladder.
* @param {number} value absolute magnitude in base units
* @param {string[]} units
* @param {number} base
* @returns {{ n: number, unit: string }}
*/
function scaleUnit(value, units, base) {
let n = Math.abs(value)
let i = 0
while (n >= base && i < units.length - 1) {
n /= base
i++
}
return { n: value < 0 ? -n : n, unit: units[i] }
}
/**
* Format memory stored as MiB → B / KiB / MiB / GiB / TiB / PiB.
* @param {number|null|undefined} mib
* @returns {string}
*/
export function formatMib(mib) {
if (mib == null || !Number.isFinite(Number(mib))) return '—'
const bytes = Number(mib) * 1024 * 1024
if (bytes === 0) return '0 B'
const { n, unit } = scaleUnit(bytes, ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'], 1024)
return `${trimFixed(n, autoDigits(n))} ${unit}`
}
/**
* Format network rate stored as kilobits/s → b/s / kb/s / Mb/s / Gb/s / Tb/s.
* @param {number|null|undefined} kbps
* @returns {string}
*/
export function formatKilobitsPerSec(kbps) {
if (kbps == null || !Number.isFinite(Number(kbps))) return '—'
const bps = Number(kbps) * 1000
if (bps === 0) return '0 b/s'
const { n, unit } = scaleUnit(bps, ['b/s', 'kb/s', 'Mb/s', 'Gb/s', 'Tb/s'], 1000)
return `${trimFixed(n, autoDigits(n))} ${unit}`
}
+23
View File
@@ -0,0 +1,23 @@
import test from 'brittle'
import { formatMib, formatKilobitsPerSec } from '../shared/format.js'
test('formatMib scales through binary units', async (t) => {
t.is(formatMib(null), '—')
t.is(formatMib(NaN), '—')
t.is(formatMib(0), '0 B')
t.is(formatMib(0.5), '512 KiB')
t.is(formatMib(256), '256 MiB')
t.is(formatMib(1024), '1 GiB')
t.is(formatMib(1536), '1.5 GiB')
t.is(formatMib(1024 * 1024), '1 TiB')
})
test('formatKilobitsPerSec scales through SI bit rates', async (t) => {
t.is(formatKilobitsPerSec(null), '—')
t.is(formatKilobitsPerSec(0), '0 b/s')
t.is(formatKilobitsPerSec(0.5), '500 b/s')
t.is(formatKilobitsPerSec(12.5), '12.5 kb/s')
t.is(formatKilobitsPerSec(1500), '1.5 Mb/s')
t.is(formatKilobitsPerSec(2_500_000), '2.5 Gb/s')
t.is(formatKilobitsPerSec(3_000_000_000), '3 Tb/s')
})