feat(ui): alerts, monitors, hosts, schedules and maintenance lists put problems first, with since-times (#5210)
#5210 "Problems first, with since-time, across every list" (milestone 477), first batch. - Alerts: the Active list reads firing, no data, acknowledged, pending, the longest-running first, and re-polls itself. An acknowledged alert says how long it has been breaching (from the alert's events; acknowledging moves last_transition_at) and, apart from that, who acknowledged it and when. Rules show what each is doing now; disabled rules sort last. The current value reads the latest-value table (#5208) instead of plugin_metrics. - Monitors: a down monitor says "Down 12m · connection refused" in the list. - Hosts: sorted down, agent gone quiet, pending, healthy. The agent column shows "—" for a missing reading (was 0%) and a Stale badge with its age. agent_metrics_by_host is gone; the list reads agent_overview_by_host. - Schedules: failing first (failed or interrupted run, or a firing that could not start one), then running, then the rest, paused last; status badge from the shared states. - Maintenance windows: active (ending soonest), then upcoming (starting soonest), with expired folded away; each says when it ends/starts/ended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
"""The Monitors page leads with what needs looking at (#5121): a count strip,
|
||||
problems first, each monitor on a page of its own, adding behind a button."""
|
||||
import re
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from types import SimpleNamespace
|
||||
|
||||
@@ -115,3 +116,24 @@ async def test_adding_is_its_own_page_and_keeps_what_was_typed(app):
|
||||
assert '<a href="/monitors/">Monitors</a>' in page and 'action="/monitors/add"' in page
|
||||
assert '<p class="field-error" role="alert">port must be between 1 and 65535, got 0.</p>' in page
|
||||
assert 'value="db"' in page and 'value="10.0.0.9"' in page and 'value="30"' in page
|
||||
|
||||
|
||||
def test_down_reason_says_why_in_a_few_words():
|
||||
from steward.monitors.service import down_reason
|
||||
assert down_reason(_check(False)) == "503 Service Unavailable" # the probe's own error first
|
||||
assert down_reason(SimpleNamespace(error_msg=None, status_code=502, content_matched=None)) == "HTTP 502"
|
||||
assert down_reason(SimpleNamespace(error_msg=None, status_code=None, content_matched=False)) == \
|
||||
"expected content not found"
|
||||
assert down_reason(None) is None
|
||||
|
||||
|
||||
async def test_a_down_monitor_says_since_when_and_why_in_the_list(app):
|
||||
row = _row(_mon("api", mid="m2"), "down", _check(False), 90.0)
|
||||
row.update(down_since=datetime.now(timezone.utc) - timedelta(minutes=12),
|
||||
down_reason="connection refused")
|
||||
async with app.test_request_context("/monitors/rows"):
|
||||
page = await render_template("monitors/rows.html", monitor_data=[row],
|
||||
counts={"up": 0, "degraded": 0, "down": 1, "pending": 0, "paused": 0},
|
||||
range_key="24h")
|
||||
page = " ".join(page.split())
|
||||
assert re.search(r'Down <time [^>]*>12m</time> · connection refused', page), page
|
||||
|
||||
Reference in New Issue
Block a user