Top wears the skin; the refresh rate reaches every machine; bug bash 4

The process table's columns fit the box they are in, the rate control saves, curves are
timed on the viewer's clock and keep to the stride, the power icon is drawn, and a young
history draws in from the right instead of being stretched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-21 10:12:45 -07:00
co-authored by Claude Fable 5.1
parent ef3dbdf543
commit 668e716601
13 changed files with 394 additions and 107 deletions
+9 -4
View File
@@ -2,7 +2,7 @@ import { ReactNode, useCallback, useEffect, useRef, useState } from 'react'
import { api, DashPrefs, Sample, Series, Temp } from './api'
import Sparkline from './Sparkline'
import { Loading, Spinner, askYes, toast } from './ui'
import { fmtMs, fmtWindowSec, strideMs, useHistorySec, useRefreshMs } from './prefs'
import { fmtMs, fmtWindowSec, nextPoint, strideMs, useHistorySec, useRefreshMs } from './prefs'
import { fetchCatalog, fetchHistories, useSensorStream } from './sensors'
import { Catalog, MONITOR_HISTORY, MONITOR_SHAPE, Values, mergeValues, sampleOf, seriesOf, stale } from './sampleAdapter'
import { Widget, WidgetData, WidgetSpec, shapeOf } from './widgets'
@@ -314,11 +314,13 @@ export default function Dashboard() {
const catalog = useRef<Catalog>(new Map())
const refetching = useRef(false)
const binN = useRef(1) // values averaged into the point currently being built
const lastPush = useRef(0) // when that point was started, by this browser's clock
const stock = useSensorStream<unknown[]>(MONITOR_SHAPE, { full: false, everyMs: refreshMs })
const seed = useCallback(async () => {
try {
catalog.current = new Map((await fetchCatalog()).map((x) => [x.id, x]))
hist.current = seriesOf(await fetchHistories(MONITOR_HISTORY), catalog.current)
lastPush.current = Date.now(); binN.current = 1
setErr('')
} catch (e) { setErr(e instanceof Error ? e.message : 'failed') }
}, [])
@@ -333,9 +335,12 @@ export default function Dashboard() {
const s = sampleOf(v, catalog.current)
const h = hist.current
if (h) {
// the point being built keeps the time it started at, so the next one is a whole stride later
const last = h.t[h.t.length - 1] ?? 0
const fresh = h.t.length === 0 || s.t - last >= strideMs(historySec, refreshMs)
// The stride is timed on this clock alone (lastPush), never against the history's own
// timestamps: those are the machine's, and a viewer whose clock runs minutes slow would
// otherwise wait those minutes before its curves gained a point.
const np = nextPoint(s.t, h.t.length === 0 ? 0 : lastPush.current, strideMs(historySec, refreshMs), refreshMs)
const fresh = np.fresh
lastPush.current = np.start
binN.current = fresh ? 1 : binN.current + 1
if (fresh) pushPoint(h.t, s.t, true, 1)
const n = h.t.length