Files
system_update/server/routes/machines.ts
T
gilles fa73ab07b0 feat(events): timeline d'événements machine (tâche 5 backlog)
- listMachineEvents (machine_events, 30 derniers, desc) + route GET /machines/:id/events
- api machineEvents ; section repliable « Timeline » dans le panneau détail
  (badge sévérité + horodatage), exploite les events déjà enregistrés par recordEvent

tsc 0 · 118 tests · build OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 19:36:06 +02:00

114 lines
3.8 KiB
TypeScript

// server/routes/machines.ts
import { Hono } from "hono";
import {
listMachines, createMachine, deleteMachine, updateMachine, getMachineRow, getCreds, testConnection,
getMachineHardware,
type CreateMachineInput, type UpdateMachineInput,
} from "../services/machines.js";
import { refreshMachine, getLatestSnapshot } from "../services/refresh.js";
import { runProbe } from "../services/machineProbe.js";
import { collectMetrics, getLatestMetrics } from "../services/machineMetrics.js";
import { analyzeMachineRepositories } from "../services/aptRepositories.js";
import { listImportantMessages, acknowledgeMessage } from "../services/importantMessages.js";
import { listMachineEvents } from "../services/machineState.js";
export const machinesRoutes = new Hono();
machinesRoutes.get("/", (c) => c.json(listMachines()));
machinesRoutes.post("/", async (c) => {
const body = (await c.req.json()) as CreateMachineInput;
try {
const m = await createMachine(body);
return c.json(m, 201);
} catch (err) {
return c.json({ error: `Connexion échouée: ${(err as Error).message}` }, 400);
}
});
machinesRoutes.post("/:id/test-connection", async (c) => {
const m = getMachineRow(c.req.param("id"));
if (!m) return c.json({ error: "Machine introuvable" }, 404);
try {
return c.json(await testConnection(getCreds(m)));
} catch (err) {
return c.json({ error: (err as Error).message }, 400);
}
});
machinesRoutes.get("/:id/snapshot", (c) => {
const snap = getLatestSnapshot(c.req.param("id"));
return snap ? c.json(snap) : c.json({ error: "Aucun snapshot" }, 404);
});
machinesRoutes.post("/:id/refresh", async (c) => {
try {
return c.json(await refreshMachine(c.req.param("id")));
} catch (err) {
return c.json({ error: (err as Error).message }, 400);
}
});
machinesRoutes.patch("/:id", async (c) => {
const body = (await c.req.json()) as UpdateMachineInput;
try {
return c.json(updateMachine(c.req.param("id"), body));
} catch (err) {
return c.json({ error: (err as Error).message }, 400);
}
});
// Dernières métriques stockées (sans SSH).
machinesRoutes.get("/:id/metrics", (c) => c.json(getLatestMetrics(c.req.param("id"))));
// Collecte fraîche (SSH léger, non destructif).
machinesRoutes.post("/:id/metrics/collect", async (c) => {
try {
return c.json(await collectMetrics(c.req.param("id")));
} catch (err) {
return c.json({ error: (err as Error).message }, 400);
}
});
// Analyse des dépôts APT (lecture seule).
machinesRoutes.post("/:id/apt-repositories", async (c) => {
try {
return c.json(await analyzeMachineRepositories(c.req.param("id")));
} catch (err) {
return c.json({ error: (err as Error).message }, 400);
}
});
// Timeline d'événements machine.
machinesRoutes.get("/:id/events", (c) => c.json(listMachineEvents(c.req.param("id"))));
// Messages importants (warnings/erreurs/évolutions) extraits des sorties.
machinesRoutes.get("/:id/messages", (c) => c.json(listImportantMessages(c.req.param("id"))));
machinesRoutes.post("/:id/messages/:msgId/ack", (c) => {
acknowledgeMessage(c.req.param("msgId"));
return c.json({ ok: true });
});
machinesRoutes.get("/:id/hardware", (c) => {
try {
return c.json(getMachineHardware(c.req.param("id")));
} catch (err) {
return c.json({ error: (err as Error).message }, 404);
}
});
// Sonde synchrone (lecture seule) : renvoie faits + proposition de correction.
machinesRoutes.post("/:id/probe", async (c) => {
try {
const o = await runProbe(c.req.param("id"));
return c.json({ probe: o.probe, proposal: o.proposal, recommendations: o.recommendations, changes: o.changes });
} catch (err) {
return c.json({ error: (err as Error).message }, 400);
}
});
machinesRoutes.delete("/:id", (c) => {
deleteMachine(c.req.param("id"));
return c.json({ ok: true });
});