3b6e005ed8
Adds a Kuma-style "is everything up?" surface that aggregates heterogeneous monitor types via a status-source registry (steward/core/status.py): each type registers an async source(db) -> [StatusEntry]. Core registers ping/DNS; the http plugin registers its own from setup() so core never imports plugin tables. Per entry: current up/down, last-30 heartbeat bar, uptime % (24h/7d/30d), latest latency + response sparkline, and TLS expiry countdown (HTTP). New /status page (live htmx refresh) + a status_overview dashboard widget + nav link. Pure-function unit tests for registry + sparkline. First deliverable of milestone #68 (task #866). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
28 lines
1.8 KiB
HTML
28 lines
1.8 KiB
HTML
{# status/widget.html — compact dashboard summary + problem list #}
|
|
<div style="display:flex;gap:1.25rem;align-items:baseline;margin-bottom:0.6rem;">
|
|
<span><span class="stat-val" style="font-size:1.5rem;color:var(--green);">{{ up }}</span><span class="stat-label">up</span></span>
|
|
<span><span class="stat-val" style="font-size:1.5rem;color:{% if down %}var(--red){% else %}var(--text-dim){% endif %};">{{ down }}</span><span class="stat-label">down</span></span>
|
|
<span><span class="stat-val" style="font-size:1.5rem;color:{% if pending %}var(--yellow){% else %}var(--text-dim){% endif %};">{{ pending }}</span><span class="stat-label">pending</span></span>
|
|
</div>
|
|
|
|
{% set problems = entries | rejectattr("status", "equalto", "up") | list %}
|
|
{% if not entries %}
|
|
<div style="color:var(--text-muted);font-size:0.85rem;padding:0.3rem 0;">No monitors configured.</div>
|
|
{% elif not problems %}
|
|
<div style="color:var(--green);font-size:0.85rem;padding:0.3rem 0;">✓ All {{ up }} monitors are up.</div>
|
|
{% else %}
|
|
<div style="display:grid;gap:1px;">
|
|
{% for e in problems[:8] %}
|
|
<div style="display:flex;align-items:center;gap:0.5rem;padding:0.2rem 0;font-size:0.82rem;">
|
|
<span class="dot {% if e.status == 'down' %}dot-down{% else %}dot-dim{% endif %}"></span>
|
|
<span style="flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">{{ e.name }}</span>
|
|
<span style="color:var(--text-dim);font-size:0.7rem;text-transform:uppercase;">{{ e.kind }}</span>
|
|
<span style="color:{% if e.status == 'down' %}var(--red){% else %}var(--yellow){% endif %};font-size:0.75rem;font-weight:600;">{{ e.status }}</span>
|
|
</div>
|
|
{% endfor %}
|
|
{% if problems|length > 8 %}
|
|
<div style="color:var(--text-dim);font-size:0.75rem;padding-top:0.2rem;">+{{ problems|length - 8 }} more…</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|