Add historical sparklines to host cards
CI / web (push) Successful in 17s
CI / api (push) Successful in 24s

24h of snapshots were already being retained but never read. Adds a
windowed query (last ~40 samples/host, one query total via
ROW_NUMBER() OVER PARTITION BY, not N+1) embedded in the existing
/api/hosts response, rendered as small hand-rolled SVG sparklines
(cpu/mem/disk overlaid) -- no charting library needed at this scale.

Closes #10.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-12 21:32:36 -06:00
parent ce232c5a53
commit f3ee4c2424
6 changed files with 102 additions and 3 deletions
+9 -1
View File
@@ -1,6 +1,6 @@
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import type Database from "better-sqlite3";
import { getLatestSnapshots } from "../db/index.js";
import { getLatestSnapshots, getRecentHistory } from "../db/index.js";
async function requireAuth(req: FastifyRequest, reply: FastifyReply) {
if (!req.session.username) {
@@ -11,6 +11,13 @@ async function requireAuth(req: FastifyRequest, reply: FastifyReply) {
export function registerHostRoutes(app: FastifyInstance, db: Database.Database): void {
app.get("/api/hosts", { preHandler: requireAuth }, async () => {
const rows = getLatestSnapshots(db);
const history = new Map<string, { ts: string; cpuPct: number | null; memPct: number | null; diskPct: number | null }[]>();
for (const h of getRecentHistory(db)) {
if (!history.has(h.host_id)) history.set(h.host_id, []);
history.get(h.host_id)!.push({ ts: h.ts, cpuPct: h.cpu_pct, memPct: h.mem_pct, diskPct: h.disk_pct });
}
return {
hosts: rows.map((r) => ({
hostId: r.host_id,
@@ -24,6 +31,7 @@ export function registerHostRoutes(app: FastifyInstance, db: Database.Database):
cpuPressurePct: r.cpu_pressure_pct,
uptimeSec: r.uptime_sec,
lastSeen: r.ts,
history: history.get(r.host_id) ?? [],
})),
};
});