feat(panel): add back up now and recent operations to the backups page

The backups page could list and restore archives but not create one,
and nothing surfaced backup/restore Job outcomes — a failed 202 was
visible only through kubectl. Add a Back up now action (enabled only on
a stopped server, the backend's own gate; a raced 409 is surfaced in
its words) and a Recent operations card fed by GET /servers/{name}/jobs
that shows running/succeeded/failed with the Job's failure message,
re-reads on an interval while a Job is running, and persists across
reloads. Wire-shape tests pin both endpoints.
This commit is contained in:
Lemon-miaow committed 2026-09-23 06:20:16 +08:00
1 parent 2010961d32
commit 97a64c8a33
6 files changed
+255 -12

No files matched your search

+20
View File
@@ -17,6 +17,7 @@ import type {
PlayersResult,
QuotaInput,
QuotaView,
ServerJob,
ServerInfo,
SessionView,
UserDetail,
@@ -339,6 +340,25 @@ export const api = {
backupId ? { backup_id: backupId } : undefined,
),
// backupNow enqueues a manual backup (spec §7 POST backup). Preconditions are
// enforced server-side and surfaced as codes: owner-or-admin (403) and the
// server MUST be fully stopped (409 not_stopped — the world volume is RWO), so
// callers gate the action on phase === "Stopped". The reply is 202
// {name, status:"backing_up"}: the Job is enqueued, not done — watch
// serverJobs for the outcome.
backupNow: (name: string) =>
request<{ name: string; status: string }>("POST", `/servers/${name}/backup`),
// serverJobs lists the newest backup/restore Jobs of one server, newest first
// (GET /servers/{name}/jobs). Owner-or-admin gated server-side; a Job's
// failure text rides `message`. The backend answers 503 until the job-status
// reader is wired, so callers should tolerate that error.
serverJobs: (name: string) =>
request<{ server: string; jobs: ServerJob[] }>(
"GET",
`/servers/${name}/jobs`,
).then((r) => r.jobs ?? []),
// Account linking (spec §10). Both are POST: start reports status from the
// session principal (no body, side-effect-free), verify consumes a code the
// player was shown in-game. The panel can never mint a code — that is the