From 0ca6b1f74493ea873ef789d2dfdd21248d1aff28 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Sat, 14 Mar 2026 21:48:40 -0400 Subject: [PATCH] feat: link health summary, recently resolved panel, event duration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dashboard: pass recent_resolved (last 24h, limit 10) to index template; render "Recently Resolved" section showing type, target, resolved time, and calculated duration (first_seen → resolved_at) - dashboard: event-age spans now also update via setInterval; duration shown for resolved events (e.g. "2h 15m") - links page: link health summary panel shows server iface count, error/flap counts, switch port up/down, PoE total draw/capacity bar; only shows problematic stats if non-zero; shows "All OK ✔" when clean - style.css: new classes for summary panel, resolved row/badge Co-Authored-By: Claude Sonnet 4.6 --- app.py | 2 ++ static/style.css | 70 ++++++++++++++++++++++++++++++++++++++++++++ templates/index.html | 54 ++++++++++++++++++++++++++++++++++ templates/links.html | 69 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 195 insertions(+) diff --git a/app.py b/app.py index a4036ad..d52f600 100644 --- a/app.py +++ b/app.py @@ -130,6 +130,7 @@ def index(): last_check = db.get_state('last_check', 'Never') snapshot = json.loads(snapshot_raw) if snapshot_raw else {} suppressions = db.get_active_suppressions() + recent_resolved = db.get_recent_resolved(hours=24, limit=10) return render_template( 'index.html', user=user, @@ -138,6 +139,7 @@ def index(): snapshot=snapshot, last_check=last_check, suppressions=suppressions, + recent_resolved=recent_resolved, ) diff --git a/static/style.css b/static/style.css index 9735f8e..65d5662 100644 --- a/static/style.css +++ b/static/style.css @@ -1524,3 +1524,73 @@ a:hover { text-decoration: underline; text-shadow: var(--glow-amber); } border-radius: 2px; font-size: .88em; } + +/* ── Link health summary panel ────────────────────────────────────── */ +.link-summary-panel { + background: var(--bg2); + border: 1px solid var(--border); + border-radius: 2px; + padding: 12px 16px; + margin-bottom: 12px; +} + +.link-summary-panel.link-summary-has-alerts { + border-color: var(--amber); +} + +.link-summary-grid { + display: flex; + flex-wrap: wrap; + gap: 20px; + align-items: flex-end; +} + +.link-summary-stat { + min-width: 80px; +} + +.link-summary-stat.lss-alert .lss-label { + color: var(--amber); +} + +.lss-label { + display: block; + font-size: .62em; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: .05em; + margin-bottom: 2px; +} + +.lss-value { + font-size: 1.2em; + font-weight: bold; + color: var(--text); +} + +.lss-sub { + font-size: .7em; + color: var(--text-muted); + font-weight: normal; +} + +/* ── Recently resolved table ──────────────────────────────────────── */ +.row-resolved td { + opacity: 0.75; +} + +.badge-resolved { + background: var(--bg3); + color: var(--text-muted); + border-color: var(--border); + text-decoration: line-through; +} + +.section-badge-resolved { + background: var(--bg3); + color: var(--text-muted); + border: 1px solid var(--border); + font-size: .65em; + padding: 2px 7px; + border-radius: 10px; +} diff --git a/templates/index.html b/templates/index.html index 3f8ce62..49d9eb1 100644 --- a/templates/index.html +++ b/templates/index.html @@ -250,6 +250,44 @@ + +{% if recent_resolved %} +
+
+

Recently Resolved

+ {{ recent_resolved | length }} in last 24h +
+
+ + + + + + + + + + + + + {% for e in recent_resolved %} + + + + + + + + + {% endfor %} + +
SevTypeTargetDetailResolvedDuration
{{ e.severity }}{{ e.event_type | replace('_', ' ') }}{{ e.target_name }}{{ e.target_detail or '–' }} + {{ e.resolved_at }} +
+
+
+{% endif %} +