feat(docker): the service and container pages say each fact once (#5310)
CI / lint (push) Successful in 4s
CI / integration (push) Successful in 1m33s
CI / unit (push) Failing after 1m59s
CI / publish (push) Skipped

Service page:
- The header carries the verdict, mode, stack, image and when it was reported.
  'In trouble since' shows only while the service is in trouble; once recovered,
  'Last failed X ago · its logs'.
- The failure card shows only while the service is down, degraded or crash-looping.
- The tile strip and the kv card are gone.
- One Tasks table: running tasks first with CPU, memory and since when, then
  Swarm's record. The node is named as its Steward host throughout, and
  'N failed in 24h' sits in the caption.

Container page:
- Same shape: header verdict, a 'Last exit' card only while it is stopped
  after a failing exit, set-up and I/O in one kv card, and lifecycle as a table.
- A swarm task's breadcrumb goes through its service.

Both pages:
- Resource history is the one fragment (_usage_history.html): now and peak in
  cores and bytes, drawn with a floor of 1 core / 1 GiB (sparkline_svg floor=),
  so idle noise draws flat.
- The container page's old % sparklines, its private _sparkline and the unused
  bucket()/container_history() helpers are removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 21:33:25 -04:00
co-authored by Claude Opus 5.5
parent 6c486d2f9c
commit 29be9e3590
12 changed files with 408 additions and 315 deletions
@@ -116,8 +116,13 @@ def test_a_service_page_reads_every_task(app):
status, page = got["page"]
assert status == 200
assert "nginx:1.27" in page and f"node-{tag}" in page and "1 of 1 running" in page
assert "nginx:1.27" in page and "1 of 1 running" in page
assert "task: non-zero exit (1)" in page # Swarm's task record
# One table (#5310): the node reads as the Steward host on it, on the running
# task and the failed one alike; the running task links its container.
assert page.count(f'<a href="/hosts/{hid}">dock-{tag}</a>') == 2 and f"node-{tag}" not in page
assert f'href="/plugins/docker/container/{hid}/{live}"' in page
assert "in trouble" not in page and "Last failed task" not in page # it is healthy again
assert f'<option value="{live_task}">1 · {live_task[:10]}</option>' in page
assert f'<option value="{dead_task}">1 · {dead_task[:10]}</option>' in page
assert f'href="/plugins/docker/?stack=it{tag}"' in page