v5 drawers offered 1h/6h/12h history zoom; the v6 shared range list
started at 24 hours, so an operator investigating a spike from the last
hour got a day-wide chart. The backend chart range parser and the
HistoryTimeRange type already support the shorter windows; only the
shared HISTORY_CHART_RANGES list and the drawer labels were missing
them. StoragePoolDetail keeps its own narrower range list and is
unaffected. Flagged by the Machines page v5 parity audit; applies to
every drawer History tab.
The Machines page v5 parity audit (same lens as #1471 on the disks
table) found the rebuilt table dropped every threshold-aware signal v5
Hosts had, and the rebuild mislabeled one datum outright.
- Temperature cells render through the canonical TemperatureGauge
(muted / amber >=70 / red >=80) like the Proxmox nodes table; v6 had
been rendering plain neutral text, so a hot machine never stood out.
- CPU, memory, and disk bars receive per-resource alert thresholds via
hostOverrideIdCandidates + alertsActivation, mirroring the
Infrastructure host table; custom thresholds were ignored here.
- Network interface tooltips show cumulative RX/TX counters as bytes;
they were formatted as rates (a 16-day total read as 1.46 GB/s).
- Temperature tooltip sections cap at six rows with a visible +N more
marker instead of silently dropping readings (worst-first sort keeps
the alarming ones); the section title flattening skips empty values.
- The memory bar passes the agent-reported reclaimable cache through,
completing the used | cache | free split for machines.
f62f35e24 restored the v5 used | cache | free memory split for Proxmox
nodes and guests, but standalone host agents still reported a flat
used/free pair, so the Machines page memory bar could not show the
reclaimable segment. Flagged by the Machines page v5 parity audit.
- Host agent reports cacheBytes (gopsutil Available minus Free); the
ZFS ARC adjustment recomputes free so used + cache + free still
covers the total.
- ApplyHostReport maps the field into models.Memory.Cache and clamps
inconsistent or older-agent reports so used + cache never exceeds
total.
- AgentMemoryMeta carries cache onto unified resources so the frontend
agent payload exposes it.
- Mock generic hosts split a third of non-used pages as cache, and the
node-linked host conversion now holds the invariant instead of
stacking the node's cache on top of a recomputed free.
- Contracts: monitoring, unified-resources, and storage-recovery now
document the split (also covering the f62f35e24 node/guest surface,
which landed without contract deltas).
OpenCode syntax-highlights code in the transcript; Pulse rendered
fenced blocks as flat text. Assistant answers are full of shell
commands, configs, and query output, so add highlight.js with an
infra grammar set (bash, json, yaml, ini, sql, dockerfile, nginx):
- Lazy-loaded into its own vendor-highlight chunk; the entry chunk
stays clean and the chunk only downloads with the rest of the
preloaded app shell.
- Highlighting runs over the sanitized DOM after the turn settles, so
generated spans never pass through DOMPurify, streaming morphs are
never fought, and the class allowlist stays closed to the model. The
single carve-out is marked's fence-language hint, pattern-pinned to
language-x on <code> only.
- Token palette maps hljs classes to theme colors readable on the
dark prose-pre background both app themes share.
Per-block copy is intentionally not added: OpenCode has none, and the
answer-level copy already exists.
Assistant turns on slow routes run one to two-and-a-half minutes, and
operators tab away; OpenCode raises a desktop notification when a turn
completes, errors, asks a question, or waits on permission while the
terminal is blurred. Pulse now does the equivalent through the browser
Notification API behind an opt-in bell toggle in the drawer header:
enabling requests permission, a denial keeps the toggle off with
guidance, and the preference persists per browser.
Notifications fire only when the tab is hidden or unfocused, carry
fixed generic copy (OS notification centers persist text, so answers,
commands, and resource names never travel through them), coalesce per
kind, and click-to-focus. Dispatched once per stream event at the top
of processEvent, never inside store updaters.
v5 had 'Update All (N)' and per-host 'Check updates' one click away in
the Docker filter bar. The v6 rebuild moved those actions into the
generic resource drawer's docker-host section, but no surface in the
current IA mounts that drawer for a docker-host: the Docker page hosts
table uses DockerHostDrawer (counts only) and the Machines page does
not list container hosts. The actions were orphaned; the only way to
update containers was one row at a time.
Wire the existing useResourceDetailDrawerDockerActionsState hook into
the host drawer's Containers card: Check updates, Update all (N) with
confirm-click, queued-command status, and an updates-last-checked row.
Update all hides when the server disables Docker update actions and
disables while a host command is in flight or no updates are known.
The resource drawer gated its History tab on type === 'agent', hiding
per-container CPU/memory/disk/IO charts even though the metrics store
records them and the charts API maps app-container to the
dockerContainer/docker store keys end-to-end (metrics_targets.go hands
out the raw container ID precisely so those records resolve). v5
charted every container; v6 charted none.
- Gate the History tab on a resolvable metrics target instead of the
agent type. Resources without a target (images, volumes, networks)
keep no tab.
- Return current-value fallback metrics for any resource, not just
agents, so charts have a hint while the store fills.
- Add a Container section to the table-row summary: image, restart
count (red above the v5 crash-loop threshold), created-at, compose
project/service, and the full label set. All of it ships in the
payload; none of it rendered anywhere after the v5 drawer was
retired.
The v6 Docker page regressed against its v5 ancestor (same disease as
the physical disks table, #1471): container CPU/memory flowed all the
way into the unified payload but no column rendered them, so a container
pegged at 75% CPU looked identical to an idle one. Labels (compose
project/service, traefik rules) and the Swarm stack name shipped in the
payload but were unrendered and unsearchable.
- Add always-visible CPU and Memory metric-bar columns to the containers
table (ResponsiveMetricCell / StackedMemoryBar, same primitives as the
hosts table above it).
- Flag crash-loopers: restart counts above 5 render red, matching the
v5 threshold.
- Demote the Runtime column to mixed-runtime fleets only; it repeated
host-level data on every container row (the #1471 Source-badge
pattern) and the Host column sits right next to it.
- Add a Stack column to the Swarm services table, derived from the
serialized stack field's canonical com.docker.stack.namespace label.
- Make container/service labels and stack names searchable via the
Docker search haystack (v5 searched labels).
- Render volume Created as relative time with the absolute timestamp in
the tooltip instead of a raw ISO 8601 string.