136e1a1d8f
Five hi-fi screens completing the Phase 1 surface, all in v1's dark
operator-console register.
v1-login Sparse centred card. Sign-in + first-error variant.
No marketing chrome; build version sits in footer
so a returning operator can spot agent drift.
v1-add-host Focused two-column page (form left, contextual
"what happens next" right) — not a modal. Two
states: form (state A) and minted-token result
with install command (state B). Backed by
POST /api/enrollment-tokens (P1-32).
v1-host-detail Persistent header (status dot, mono name, tags,
primary CTAs, vitals strip) over four sub-tabs
(Snapshots / Jobs / Repo / Settings). Snapshots
is the default — the thing 90% of operators
want when they click a host name. Right rail
holds Recent activity, run-now stack, and a
danger-zone panel.
v1-job-log WS-streamed log view. Three states: running (live
progress bar + auto-scroll cursor), succeeded
(summary stats + final lines), failed (error
panel + tail). Backed by WS /api/jobs/{id}/stream
(P1-21 remainder).
v1-components The load-bearing reference. 14 sections covering
tokens (colour + type scale), status, buttons,
form fields, tags, tabs, host row, log viewer,
progress bar, stat tile, modal, toast, install
snippet, empty-state pattern. Every CSS class is
real and copy-able into the Go template build.
This locks the visual register before P1-23 onwards. Each Phase 1
template gets a {{define}} matching a section in v1-components.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
414 lines
27 KiB
HTML
414 lines
27 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>restic-manager · v1 Job log</title>
|
||
<script src="https://cdn.tailwindcss.com"></script>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root {
|
||
--bg: oklch(0.17 0.006 250); --panel: oklch(0.20 0.007 250); --panel-hi: oklch(0.23 0.008 250);
|
||
--line: oklch(0.27 0.010 250); --line-soft: oklch(0.23 0.008 250);
|
||
--ink: oklch(0.96 0.005 250); --ink-mid: oklch(0.78 0.005 250);
|
||
--ink-mute: oklch(0.58 0.006 250); --ink-fade: oklch(0.42 0.006 250);
|
||
--ok: oklch(0.78 0.14 155); --warn: oklch(0.82 0.13 80); --bad: oklch(0.70 0.20 25);
|
||
--accent: oklch(0.82 0.12 195);
|
||
}
|
||
html, body { background: var(--bg); color: var(--ink); }
|
||
body { font-family: 'Inter', system-ui, sans-serif; }
|
||
.mono { font-family: 'JetBrains Mono', monospace; font-variant-numeric: tabular-nums; }
|
||
.text-pretty { text-wrap: pretty; }
|
||
::selection { background: color-mix(in oklch, var(--accent), transparent 70%); }
|
||
|
||
.panel { background: var(--panel); border: 1px solid var(--line-soft); }
|
||
.hairline { box-shadow: inset 0 -1px 0 var(--line-soft); }
|
||
|
||
.btn {
|
||
font-size: 12px; font-weight: 500; padding: 6px 11px; border-radius: 5px;
|
||
background: transparent; border: 1px solid var(--line); color: var(--ink-mid);
|
||
transition: all 120ms ease; cursor: pointer;
|
||
}
|
||
.btn:hover { background: var(--panel-hi); color: var(--ink); }
|
||
.btn-primary { color: oklch(0.18 0.01 195); background: var(--accent); border-color: var(--accent); }
|
||
.btn-primary:hover { filter: brightness(1.08); }
|
||
.btn-ghost { border-color: transparent; }
|
||
.btn-ghost:hover { background: var(--panel-hi); border-color: transparent; }
|
||
.btn-danger { color: var(--bad); border-color: color-mix(in oklch, var(--bad), transparent 70%); }
|
||
|
||
.nav-tab { font-size: 13px; padding: 18px 0; color: var(--ink-mute); border-bottom: 2px solid transparent; margin-right: 28px; cursor: pointer; }
|
||
.nav-tab.active { color: var(--ink); border-color: var(--accent); }
|
||
|
||
.doc { max-width: 1280px; margin: 0 auto; padding: 0 32px; }
|
||
.philosophy { padding: 56px 0 32px; border-bottom: 1px solid var(--line-soft); }
|
||
.philosophy h1 { font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
|
||
.philosophy p { color: var(--ink-mid); max-width: 680px; margin-top: 14px; line-height: 1.65; text-wrap: pretty; }
|
||
.philosophy .meta { color: var(--ink-fade); font-size: 12px; margin-top: 14px; }
|
||
.stage-frame { margin: 48px -32px; border-top: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft); }
|
||
.stage-label { padding: 16px 32px 0; font-size: 11px; color: var(--ink-fade); letter-spacing: 0.18em; text-transform: uppercase; }
|
||
|
||
.crumbs { font-size: 12px; color: var(--ink-mute); }
|
||
.crumbs a { color: var(--ink-mute); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--line); }
|
||
.crumbs .sep { color: var(--ink-fade); margin: 0 8px; }
|
||
|
||
/* progress bar */
|
||
.progress-track {
|
||
background: var(--bg); border: 1px solid var(--line-soft);
|
||
height: 6px; border-radius: 9999px; overflow: hidden;
|
||
}
|
||
.progress-fill {
|
||
height: 100%; background: var(--accent);
|
||
border-radius: 9999px;
|
||
transition: width 250ms ease;
|
||
}
|
||
|
||
/* log viewer */
|
||
.log {
|
||
background: var(--bg);
|
||
border: 1px solid var(--line-soft);
|
||
border-radius: 7px;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-size: 12px; line-height: 1.7;
|
||
overflow: hidden;
|
||
}
|
||
.log-line {
|
||
display: grid;
|
||
grid-template-columns: 14ch 8ch 1fr;
|
||
column-gap: 14px;
|
||
padding: 1px 16px;
|
||
align-items: baseline;
|
||
}
|
||
.log-line:first-child { padding-top: 14px; }
|
||
.log-line.ts { color: var(--ink-fade); }
|
||
.log-stream-stdout { color: var(--ink-mid); }
|
||
.log-stream-stderr { color: oklch(0.78 0.13 50); }
|
||
.log-stream-event { color: var(--accent); }
|
||
.log-stream-tag { font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-fade); }
|
||
.log-payload-ok { color: var(--ink); }
|
||
.log-payload-warn { color: var(--warn); }
|
||
.log-payload-err { color: var(--bad); }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="doc">
|
||
|
||
<header class="philosophy">
|
||
<div class="text-xs uppercase tracking-[0.18em] text-[color:var(--ink-fade)] mb-3">v1 · Live job log</div>
|
||
<h1>Watching restic chug.</h1>
|
||
<p>
|
||
The screen an operator stares at when something is in flight. Header
|
||
identifies the job (kind · host · status). A live progress bar shows the
|
||
bytes-to-go signal restic emits. The log itself is the focus: monospace,
|
||
tight line-height, color reserved for the few lines that matter — events
|
||
and stderr.
|
||
</p>
|
||
<p class="meta">
|
||
Backed by <span class="mono" style="color: var(--ink-mid);">WS /api/jobs/{id}/stream</span>
|
||
(P1-21 remainder). Auto-scrolls until the operator scrolls away; a
|
||
“follow” pill appears when they’ve scrolled up so they can re-attach.
|
||
</p>
|
||
</header>
|
||
|
||
<!-- Stage 1: running -->
|
||
<div class="stage-label">State A · running</div>
|
||
<div class="stage-frame">
|
||
<div style="background: var(--bg);">
|
||
|
||
<!-- chrome -->
|
||
<div class="hairline" style="background: var(--bg);">
|
||
<div class="doc flex items-center justify-between" style="padding: 16px 0;">
|
||
<div class="flex items-center gap-3">
|
||
<div class="mono" style="font-size:13px; color: var(--ink); font-weight:500;">restic-manager</div>
|
||
<div class="mono" style="font-size:11px; color: var(--ink-fade);">v0.1.0-alpha</div>
|
||
</div>
|
||
<div class="flex items-center gap-5">
|
||
<div class="mono" style="font-size:12px; color: var(--ink-mute);">steve@dcglab</div>
|
||
<button class="btn btn-ghost">Sign out</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="hairline" style="background: var(--bg);">
|
||
<div class="doc flex items-end">
|
||
<nav class="flex items-end">
|
||
<div class="nav-tab active">Dashboard</div>
|
||
<div class="nav-tab">Repos</div>
|
||
<div class="nav-tab">Alerts <span class="mono ml-1.5" style="font-size:11px; color: var(--bad);">5</span></div>
|
||
<div class="nav-tab">Audit</div>
|
||
<div class="nav-tab">Settings</div>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- job header -->
|
||
<div class="doc" style="padding: 28px 32px 0;">
|
||
<div class="crumbs"><a>Dashboard</a><span class="sep">/</span><a>prod-db-01</a><span class="sep">/</span><span style="color: var(--ink-mid);">job 01KQH…E59B</span></div>
|
||
|
||
<div class="flex items-start justify-between" style="margin-top: 14px;">
|
||
<div>
|
||
<div class="flex items-center gap-3">
|
||
<span style="width: 9px; height: 9px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 4px color-mix(in oklch, var(--accent), transparent 80%); animation: pulse 2.4s ease-in-out infinite;"></span>
|
||
<h1 style="font-size: 22px; font-weight: 500; letter-spacing: -0.01em;">backup <span style="color: var(--ink-fade);">·</span> <span class="mono" style="color: var(--ink); font-weight: 500;">prod-db-01</span></h1>
|
||
<span class="mono" style="font-size: 11px; padding: 3px 8px; background: color-mix(in oklch, var(--accent), transparent 88%); color: var(--accent); border: 1px solid color-mix(in oklch, var(--accent), transparent 70%); border-radius: 3px;">running</span>
|
||
</div>
|
||
<div class="flex items-center gap-3" style="margin-top: 10px; font-size: 12.5px; color: var(--ink-mute);">
|
||
<span>job <span class="mono" style="color: var(--ink-mid);">01KQH7DZJ8M5N3DH277E59B</span></span>
|
||
<span style="color: var(--ink-fade);">·</span>
|
||
<span>started <span class="mono" style="color: var(--ink-mid);">3m 18s ago</span> by <span class="mono" style="color: var(--ink-mid);">steve@dcglab</span></span>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center gap-2">
|
||
<button class="btn">Pin to top</button>
|
||
<button class="btn btn-danger">Cancel job</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- progress bar -->
|
||
<div style="margin-top: 24px; padding-bottom: 24px;">
|
||
<div class="flex items-center justify-between mb-2.5">
|
||
<div class="flex items-center gap-3 text-sm">
|
||
<span class="mono" style="color: var(--ink); font-weight: 500;">38%</span>
|
||
<span style="color: var(--ink-mute);">·</span>
|
||
<span class="mono" style="color: var(--ink-mid);">1.4 GB</span> <span style="color: var(--ink-mute);">of <span class="mono" style="color: var(--ink-mid);">3.7 GB</span></span>
|
||
<span style="color: var(--ink-mute);">·</span>
|
||
<span class="mono" style="color: var(--ink-mid);">8,124 files</span>
|
||
<span style="color: var(--ink-mute);">of <span class="mono" style="color: var(--ink-mid);">21,402</span></span>
|
||
</div>
|
||
<div class="text-sm" style="color: var(--ink-mute);">
|
||
<span class="mono" style="color: var(--ink-mid);">42 MB/s</span> · ETA <span class="mono" style="color: var(--ink-mid);">2m 14s</span>
|
||
</div>
|
||
</div>
|
||
<div class="progress-track">
|
||
<div class="progress-fill" style="width: 38%;"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- log viewer -->
|
||
<div class="doc" style="padding: 0 32px 56px;">
|
||
<div class="flex items-center justify-between" style="margin-bottom: 12px;">
|
||
<div class="flex items-center gap-3">
|
||
<h2 style="font-size: 13px; font-weight: 600; letter-spacing: 0.01em;">Stream</h2>
|
||
<span style="font-size: 11.5px; color: var(--ink-fade);">following · auto-scroll on · 1,247 lines</span>
|
||
</div>
|
||
<div class="flex items-center gap-2">
|
||
<button class="btn">Filter ▾</button>
|
||
<button class="btn">Pause stream</button>
|
||
<button class="btn">Download .log</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="log">
|
||
<div class="log-line"><span class="ts">11:43:21.039</span><span class="log-stream-tag">EVENT</span><span class="log-payload-ok"><span class="log-stream-event">{"message_type":"status","percent_done":0.000,"total_files":21402,"files_done":0,"total_bytes":3958374400,"bytes_done":0}</span></span></div>
|
||
<div class="log-line"><span class="ts">11:43:21.412</span><span class="log-stream-tag">OUT</span><span class="log-stream-stdout">scan finished in 0.371s</span></div>
|
||
<div class="log-line"><span class="ts">11:43:21.504</span><span class="log-stream-tag">EVENT</span><span class="log-stream-event">{"message_type":"status","percent_done":0.001,"total_files":21402,"files_done":12,"bytes_done":1048576}</span></div>
|
||
<div class="log-line"><span class="ts">11:43:22.512</span><span class="log-stream-tag">EVENT</span><span class="log-stream-event">{"message_type":"status","percent_done":0.020,"files_done":418,"bytes_done":81256000}</span></div>
|
||
<div class="log-line"><span class="ts">11:43:23.521</span><span class="log-stream-tag">EVENT</span><span class="log-stream-event">{"message_type":"status","percent_done":0.062,"files_done":1287,"bytes_done":253640000}</span></div>
|
||
<div class="log-line"><span class="ts">11:43:24.530</span><span class="log-stream-tag">EVENT</span><span class="log-stream-event">{"message_type":"status","percent_done":0.108,"files_done":2289,"bytes_done":444121600}</span></div>
|
||
<div class="log-line"><span class="ts">11:43:25.541</span><span class="log-stream-tag">EVENT</span><span class="log-stream-event">{"message_type":"status","percent_done":0.155,"files_done":3267,"bytes_done":637534720}</span></div>
|
||
<div class="log-line"><span class="ts">11:43:25.812</span><span class="log-stream-tag">ERR</span><span class="log-stream-stderr"><span class="log-payload-warn">warn: file changed during read: /var/lib/postgresql/13/main/pg_wal/000000010000007800000042</span></span></div>
|
||
<div class="log-line"><span class="ts">11:43:26.554</span><span class="log-stream-tag">EVENT</span><span class="log-stream-event">{"message_type":"status","percent_done":0.198,"files_done":4187,"bytes_done":815874048}</span></div>
|
||
<div class="log-line"><span class="ts">11:43:27.566</span><span class="log-stream-tag">EVENT</span><span class="log-stream-event">{"message_type":"status","percent_done":0.241,"files_done":5108,"bytes_done":993951744}</span></div>
|
||
<div class="log-line"><span class="ts">11:43:28.580</span><span class="log-stream-tag">EVENT</span><span class="log-stream-event">{"message_type":"status","percent_done":0.284,"files_done":6029,"bytes_done":1172029440}</span></div>
|
||
<div class="log-line"><span class="ts">11:43:29.594</span><span class="log-stream-tag">EVENT</span><span class="log-stream-event">{"message_type":"status","percent_done":0.327,"files_done":6948,"bytes_done":1349838336}</span></div>
|
||
<div class="log-line"><span class="ts">11:43:30.609</span><span class="log-stream-tag">EVENT</span><span class="log-stream-event">{"message_type":"status","percent_done":0.358,"files_done":7596,"bytes_done":1475174400}</span></div>
|
||
<div class="log-line"><span class="ts">11:43:31.625</span><span class="log-stream-tag">EVENT</span><span class="log-stream-event">{"message_type":"status","percent_done":0.380,"files_done":8124,"bytes_done":1503870976}</span></div>
|
||
<div class="log-line" style="padding-bottom: 14px;"><span class="ts" style="color: var(--accent);">11:43:32.122</span><span class="log-stream-tag" style="color: var(--accent);">···</span><span style="color: var(--accent);">▏</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Stage 2: completed (success) -->
|
||
<div class="stage-label">State B · completed (succeeded)</div>
|
||
<div class="stage-frame">
|
||
<div style="background: var(--bg);">
|
||
|
||
<div class="hairline" style="background: var(--bg);">
|
||
<div class="doc flex items-center justify-between" style="padding: 16px 0;">
|
||
<div class="flex items-center gap-3">
|
||
<div class="mono" style="font-size:13px; color: var(--ink); font-weight:500;">restic-manager</div>
|
||
<div class="mono" style="font-size:11px; color: var(--ink-fade);">v0.1.0-alpha</div>
|
||
</div>
|
||
<div class="flex items-center gap-5">
|
||
<div class="mono" style="font-size:12px; color: var(--ink-mute);">steve@dcglab</div>
|
||
<button class="btn btn-ghost">Sign out</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="hairline" style="background: var(--bg);">
|
||
<div class="doc flex items-end">
|
||
<nav class="flex items-end">
|
||
<div class="nav-tab active">Dashboard</div>
|
||
<div class="nav-tab">Repos</div>
|
||
<div class="nav-tab">Alerts <span class="mono ml-1.5" style="font-size:11px; color: var(--bad);">5</span></div>
|
||
<div class="nav-tab">Audit</div>
|
||
<div class="nav-tab">Settings</div>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="doc" style="padding: 28px 32px 0;">
|
||
<div class="crumbs"><a>Dashboard</a><span class="sep">/</span><a>prod-db-01</a><span class="sep">/</span><span style="color: var(--ink-mid);">job 01KQH…E59B</span></div>
|
||
<div class="flex items-start justify-between" style="margin-top: 14px;">
|
||
<div>
|
||
<div class="flex items-center gap-3">
|
||
<span style="width: 9px; height: 9px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 0 4px color-mix(in oklch, var(--ok), transparent 80%);"></span>
|
||
<h1 style="font-size: 22px; font-weight: 500; letter-spacing: -0.01em;">backup <span style="color: var(--ink-fade);">·</span> <span class="mono" style="color: var(--ink); font-weight: 500;">prod-db-01</span></h1>
|
||
<span class="mono" style="font-size: 11px; padding: 3px 8px; background: color-mix(in oklch, var(--ok), transparent 88%); color: var(--ok); border: 1px solid color-mix(in oklch, var(--ok), transparent 70%); border-radius: 3px;">succeeded</span>
|
||
</div>
|
||
<div class="flex items-center gap-3" style="margin-top: 10px; font-size: 12.5px; color: var(--ink-mute);">
|
||
<span>job <span class="mono" style="color: var(--ink-mid);">01KQH7DZJ8M5N3DH277E59B</span></span>
|
||
<span style="color: var(--ink-fade);">·</span>
|
||
<span>finished <span class="mono" style="color: var(--ink-mid);">11:48:42 (5m 21s)</span></span>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center gap-2">
|
||
<button class="btn">Run again</button>
|
||
<button class="btn">Download .log</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- summary stats -->
|
||
<div class="grid grid-cols-12 gap-6" style="margin-top: 24px; padding: 18px 0; border-top: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft);">
|
||
<div class="col-span-3">
|
||
<div style="font-size: 11px; color: var(--ink-fade); text-transform: uppercase; letter-spacing: 0.08em;">Bytes added</div>
|
||
<div class="mono" style="font-size: 18px; color: var(--ink); margin-top: 4px;">142 <span style="font-size: 12px; color: var(--ink-mute);">MB</span></div>
|
||
<div style="font-size: 11.5px; color: var(--ink-mute); margin-top: 2px;">of <span class="mono">3.7 GB</span> processed</div>
|
||
</div>
|
||
<div class="col-span-3">
|
||
<div style="font-size: 11px; color: var(--ink-fade); text-transform: uppercase; letter-spacing: 0.08em;">Files</div>
|
||
<div class="mono" style="font-size: 18px; color: var(--ink); margin-top: 4px;">21,402</div>
|
||
<div style="font-size: 11.5px; color: var(--ink-mute); margin-top: 2px;"><span class="mono">187</span> new · <span class="mono">42</span> changed</div>
|
||
</div>
|
||
<div class="col-span-3">
|
||
<div style="font-size: 11px; color: var(--ink-fade); text-transform: uppercase; letter-spacing: 0.08em;">Throughput</div>
|
||
<div class="mono" style="font-size: 18px; color: var(--ink); margin-top: 4px;">42 <span style="font-size: 12px; color: var(--ink-mute);">MB/s</span></div>
|
||
<div style="font-size: 11.5px; color: var(--ink-mute); margin-top: 2px;">avg over 5m 21s</div>
|
||
</div>
|
||
<div class="col-span-3">
|
||
<div style="font-size: 11px; color: var(--ink-fade); text-transform: uppercase; letter-spacing: 0.08em;">Snapshot</div>
|
||
<div class="mono" style="font-size: 18px; color: var(--ink); margin-top: 4px;">91bbc80d</div>
|
||
<div style="font-size: 11.5px; color: var(--ink-mute); margin-top: 2px;">added to repo</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- log tail (final lines) -->
|
||
<div class="doc" style="padding: 24px 32px 56px;">
|
||
<div class="flex items-center justify-between" style="margin-bottom: 12px;">
|
||
<div class="flex items-center gap-3">
|
||
<h2 style="font-size: 13px; font-weight: 600; letter-spacing: 0.01em;">Stream <span style="font-weight: 400; color: var(--ink-fade);">· complete</span></h2>
|
||
<span style="font-size: 11.5px; color: var(--ink-fade);">2,418 lines</span>
|
||
</div>
|
||
<div class="flex items-center gap-2">
|
||
<button class="btn">Show all lines</button>
|
||
<button class="btn">Filter ▾</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="log">
|
||
<div class="log-line"><span class="ts">11:48:38.044</span><span class="log-stream-tag">EVENT</span><span class="log-stream-event">{"message_type":"status","percent_done":0.987,"files_done":21127,"bytes_done":3905990656}</span></div>
|
||
<div class="log-line"><span class="ts">11:48:39.058</span><span class="log-stream-tag">EVENT</span><span class="log-stream-event">{"message_type":"status","percent_done":0.998,"files_done":21358,"bytes_done":3950182400}</span></div>
|
||
<div class="log-line"><span class="ts">11:48:40.064</span><span class="log-stream-tag">OUT</span><span class="log-stream-stdout">processed 21402 files, 3.689 GiB in 5:19</span></div>
|
||
<div class="log-line"><span class="ts">11:48:41.022</span><span class="log-stream-tag">OUT</span><span class="log-stream-stdout">snapshot 91bbc80d saved</span></div>
|
||
<div class="log-line"><span class="ts">11:48:42.108</span><span class="log-stream-tag">EVENT</span><span class="log-payload-ok"><span class="log-stream-event">{"message_type":"summary","files_new":187,"files_changed":42,"files_unmodified":21173,"data_added":148908544,"total_files_processed":21402,"total_bytes_processed":3958374400,"snapshot_id":"91bbc80d4a17ed718462a26f3e6ad72d0cde7aa9fbf0629efaac1eaa943f5665","total_duration":319.234}</span></span></div>
|
||
<div class="log-line" style="padding-bottom: 14px;"><span class="ts">11:48:42.337</span><span class="log-stream-tag" style="color: var(--ok);">END</span><span style="color: var(--ok);">restic exited 0 · success</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Stage 3: failed -->
|
||
<div class="stage-label">State C · failed</div>
|
||
<div class="stage-frame">
|
||
<div style="background: var(--bg);">
|
||
|
||
<div class="hairline" style="background: var(--bg);">
|
||
<div class="doc flex items-center justify-between" style="padding: 16px 0;">
|
||
<div class="flex items-center gap-3">
|
||
<div class="mono" style="font-size:13px; color: var(--ink); font-weight:500;">restic-manager</div>
|
||
<div class="mono" style="font-size:11px; color: var(--ink-fade);">v0.1.0-alpha</div>
|
||
</div>
|
||
<div class="flex items-center gap-5">
|
||
<div class="mono" style="font-size:12px; color: var(--ink-mute);">steve@dcglab</div>
|
||
<button class="btn btn-ghost">Sign out</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="hairline" style="background: var(--bg);">
|
||
<div class="doc flex items-end">
|
||
<nav class="flex items-end">
|
||
<div class="nav-tab active">Dashboard</div>
|
||
<div class="nav-tab">Repos</div>
|
||
<div class="nav-tab">Alerts <span class="mono ml-1.5" style="font-size:11px; color: var(--bad);">5</span></div>
|
||
<div class="nav-tab">Audit</div>
|
||
<div class="nav-tab">Settings</div>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="doc" style="padding: 28px 32px 0;">
|
||
<div class="crumbs"><a>Dashboard</a><span class="sep">/</span><a>build-runner</a><span class="sep">/</span><span style="color: var(--ink-mid);">job 01KQH…9F8C</span></div>
|
||
|
||
<div class="flex items-start justify-between" style="margin-top: 14px;">
|
||
<div>
|
||
<div class="flex items-center gap-3">
|
||
<span style="width: 9px; height: 9px; border-radius: 50%; background: var(--bad); box-shadow: 0 0 0 4px color-mix(in oklch, var(--bad), transparent 80%);"></span>
|
||
<h1 style="font-size: 22px; font-weight: 500; letter-spacing: -0.01em;">backup <span style="color: var(--ink-fade);">·</span> <span class="mono" style="color: var(--ink); font-weight: 500;">build-runner</span></h1>
|
||
<span class="mono" style="font-size: 11px; padding: 3px 8px; background: color-mix(in oklch, var(--bad), transparent 88%); color: var(--bad); border: 1px solid color-mix(in oklch, var(--bad), transparent 70%); border-radius: 3px;">failed</span>
|
||
</div>
|
||
<div class="flex items-center gap-3" style="margin-top: 10px; font-size: 12.5px; color: var(--ink-mute);">
|
||
<span>job <span class="mono" style="color: var(--ink-mid);">01KQH3FX9F8C…</span></span>
|
||
<span style="color: var(--ink-fade);">·</span>
|
||
<span>finished <span class="mono" style="color: var(--ink-mid);">10:53:18 (1.4s)</span></span>
|
||
<span style="color: var(--ink-fade);">·</span>
|
||
<span>exit code <span class="mono" style="color: var(--bad);">1</span></span>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center gap-2">
|
||
<button class="btn">Retry job</button>
|
||
<button class="btn">Open alert</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- failure summary panel -->
|
||
<div class="panel" style="margin-top: 24px; padding: 16px 18px; border-radius: 7px; border-color: color-mix(in oklch, var(--bad), transparent 60%);">
|
||
<div style="font-size: 11px; color: var(--bad); text-transform: uppercase; letter-spacing: 0.08em; font-weight: 600; margin-bottom: 6px;">Failure</div>
|
||
<p style="font-size: 13.5px; color: var(--ink); line-height: 1.6;" class="text-pretty">
|
||
<span class="mono" style="color: var(--bad);">unable to acquire lock</span> — the repo at <span class="mono" style="color: var(--ink-mid);">rest:https://restic.unraid.lab/build-runner/</span> is locked by another operation.
|
||
</p>
|
||
<div style="font-size: 12px; color: var(--ink-mute); margin-top: 10px; line-height: 1.6;" class="text-pretty">
|
||
Most likely a stale lock from a previous run that didn't clean up. Run <span class="mono" style="color: var(--ink);">unlock</span> on this host's repo, then retry the backup.
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="doc" style="padding: 24px 32px 56px;">
|
||
<div class="log">
|
||
<div class="log-line"><span class="ts">10:53:17.001</span><span class="log-stream-tag">OUT</span><span class="log-stream-stdout">opening repository at rest:https://restic.unraid.lab/build-runner/</span></div>
|
||
<div class="log-line"><span class="ts">10:53:17.388</span><span class="log-stream-tag">OUT</span><span class="log-stream-stdout">repository f4b81ec7 opened</span></div>
|
||
<div class="log-line"><span class="ts">10:53:17.602</span><span class="log-stream-tag">OUT</span><span class="log-stream-stdout">created new cache in /var/lib/restic-manager/cache</span></div>
|
||
<div class="log-line"><span class="ts">10:53:18.211</span><span class="log-stream-tag">ERR</span><span class="log-stream-stderr"><span class="log-payload-err">Fatal: unable to create lock in backend: repository is already locked exclusively by PID 12047 on build-runner by root (UID 0, GID 0) lock was created at 2026-05-01 10:39:14 (14m18s ago) storage ID a4f1b3d8</span></span></div>
|
||
<div class="log-line" style="padding-bottom: 14px;"><span class="ts">10:53:18.298</span><span class="log-stream-tag" style="color: var(--bad);">END</span><span style="color: var(--bad);">restic exited 1 · failed</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<style>
|
||
@keyframes pulse {
|
||
0%, 100% { box-shadow: 0 0 0 4px color-mix(in oklch, var(--accent), transparent 80%); }
|
||
50% { box-shadow: 0 0 0 6px color-mix(in oklch, var(--accent), transparent 92%); }
|
||
}
|
||
</style>
|
||
|
||
</body>
|
||
</html>
|