dashboard: distinct "gave up" badge for a crash-looped container
Frontend half of the two-PR split on the systemd restart-bound work
(clause 2): once a container's unit hits systemd's bounded restart
limit and stops on its own, that read exactly like a deliberate stop
("not running") — no way to tell "gave up" from "off on purpose".
Renders ContainerView.failed as a distinct red "gave up" badge on the
container row, in place of the muted "not running" badge. Both states
have running: false; failed is the new orthogonal fact that tells them
apart, same "independent flags, no state machine" shape as
paused/needs_update/needs_login. An older backend without the field
serves failed: undefined, which reads falsy, so this degrades cleanly
to the existing single "not running" badge.
Frontend-only — no Rust changes. Safe to merge in either order
relative to the backend PR carrying ContainerView.failed itself.
This commit is contained in:
parent
d3ac4de8fb
commit
b785f96d30
2 changed files with 34 additions and 10 deletions
|
|
@ -892,12 +892,22 @@ fetch entirely.
|
|||
**When the container is stopped** (`ContainerView.running = false`),
|
||||
the async `dashboard-state` fetch is skipped entirely (the agent
|
||||
web server is down), so the badge chain is replaced by a single
|
||||
muted `■ not running` badge, the nav strip is empty, and status
|
||||
text / rate-limited / ctx badges are suppressed. The agent icon
|
||||
goes straight to the dimmed `/favicon.svg` fallback instead of
|
||||
attempting a doomed load from the container's URL. Static fields
|
||||
— `needs_update`, `deployed_sha`, `pending_reminders`, `parent`,
|
||||
`config` link — remain visible regardless of run state.
|
||||
badge, the nav strip is empty, and status text / rate-limited / ctx
|
||||
badges are suppressed. The agent icon goes straight to the dimmed
|
||||
`/favicon.svg` fallback instead of attempting a doomed load from the
|
||||
container's URL. Static fields — `needs_update`, `deployed_sha`,
|
||||
`pending_reminders`, `parent`, `config` link — remain visible
|
||||
regardless of run state.
|
||||
**Which single badge (hyperhive#3139):** `ContainerView.failed`
|
||||
(systemd `ActiveState=failed` — the unit exhausted its bounded
|
||||
restarts and gave up on its own) draws a red `✖ gave up` badge;
|
||||
otherwise a plain muted `■ not running` — a container an operator
|
||||
stopped deliberately. Both states read `running: false`; `failed` is
|
||||
the orthogonal fact (a fifth one alongside `paused`/`needs_update`/
|
||||
`needs_login`, same "independent flags, no state machine" shape —
|
||||
see `ContainerView`'s own doc comment) that tells them apart. An
|
||||
older backend without the field serves `failed: undefined`, which
|
||||
reads falsy — degrades cleanly to the single `not running` badge.
|
||||
When the container is running, status badges follow — `⊘ rate
|
||||
limited` (red, while the harness is parked after a 429), `needs
|
||||
login`, `needs update` — plus **one `◐ pending-state…` pill per
|
||||
|
|
|
|||
|
|
@ -302,6 +302,7 @@ function containerRowFingerprint(c, node, pending, opRunning, selected,
|
|||
askerCount, targetCount, gatewayLinks, hostname) {
|
||||
return JSON.stringify({
|
||||
running: c.running,
|
||||
failed: c.failed,
|
||||
paused: c.paused,
|
||||
needs_login: c.needs_login,
|
||||
needs_update: c.needs_update,
|
||||
|
|
@ -495,10 +496,15 @@ function buildContainerLi(c, node, opts) {
|
|||
}
|
||||
// Status / runtime badges. Pending transients always win
|
||||
// (start / stop / restart / rebuild is in progress). Otherwise,
|
||||
// when the container is stopped, surface a single `■ not running`
|
||||
// badge. `needs_login` is still c0re-owned (reads auth sentinel
|
||||
// files on the host). rate_limited / ctx / status_text are
|
||||
// agent-owned and rendered by the async dashboard-state fetch above.
|
||||
// when the container is stopped, surface a single badge — `✖ gave
|
||||
// up` (red) when systemd's restart bound was hit (`c.failed`), else
|
||||
// the plain muted `■ not running`. Both read `running: false`;
|
||||
// `failed` is what tells "gave up" apart from "stopped on purpose"
|
||||
// (an absent `failed` — an older backend — is `undefined`, falsy,
|
||||
// so this degrades to the old single badge). `needs_login` is still
|
||||
// c0re-owned (reads auth sentinel files on the host). rate_limited /
|
||||
// ctx / status_text are agent-owned and rendered by the async
|
||||
// dashboard-state fetch above.
|
||||
if (pending.length) {
|
||||
// One badge per pill — an agent can carry several transients at
|
||||
// once now (see docs/web-ui.md::Container row), each rendered
|
||||
|
|
@ -507,6 +513,14 @@ function buildContainerLi(c, node, opts) {
|
|||
head.append(el('span', { class: 'pending-state' },
|
||||
el('span', { class: 'spinner' }, '◐'), ' ', label + '…'));
|
||||
}
|
||||
} else if (!c.running && c.failed) {
|
||||
head.append(el('span',
|
||||
{
|
||||
class: 'badge badge-fail',
|
||||
title: 'container gave up — its unit hit systemd\'s bounded restart limit and stopped '
|
||||
+ 'on its own, not on operator request; start it to bring the harness back up',
|
||||
},
|
||||
'✖ gave up'));
|
||||
} else if (!c.running) {
|
||||
head.append(el('span',
|
||||
{ class: 'badge badge-muted', title: 'container is shut down — start it to bring the harness back up' },
|
||||
|
|
|
|||
Loading…
Reference in a new issue