Traefik: routers are graded from their latest scrape (router_state: crit on any real 5xx share, warn on p95 past the latency critical cutoff or a high 4xx share). Failing and slow routers lead as cards that say why; healthy ones fold into one table that stays open or shut across polls. Proxy counts are stat tiles; certificates are graded by Settings -> Thresholds (tls_days). UniFi: WAN health is a stat strip (latency graded by the thresholds), devices carry status dots, event categories and firewall actions are badges, the alarm count reuses .count-badge (renamed from .nav-count). SNMP: each device wears a status badge and its readings are stat tiles. Agent fleet: the table comes first, with a Status column (Reporting / Silent / Never reported, by the host page's stale_after_seconds), silent agents first, hosts linked, last seen as |ago. Audit: entries name their entity (one query per type, steward/audit/ service.py) and link it; something deleted since keeps the name its entry recorded and says "(deleted)". Tokens: charts read colours through chart-colors.js (stewardColor resolves a token to the rgb the browser computed; Chart.js defaults take the page's text and border colours), so host, history, Traefik and SNMP charts drop their hex. Template hex colours reach 0 (HEX_CEILING = 0), the last rgba pills go, and heavy weights (600/700/bold, 60 of them) become 500, the house pair being 400/500; a guard keeps templates there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
41 lines
1.6 KiB
HTML
41 lines
1.6 KiB
HTML
{# plugins/snmp/templates/snmp/index.html #}
|
|
{% extends "base.html" %}
|
|
{% from "_macros.html" import page_header, status_badge, stat_tile, empty_state %}
|
|
{% block title %}SNMP — Steward{% endblock %}
|
|
{% block content %}
|
|
{{ page_header("SNMP devices", devices|length ~ " device" ~ ("s" if devices|length != 1 else "") ~ " configured") }}
|
|
|
|
{% if not devices %}
|
|
<div class="card">{{ empty_state("No SNMP devices configured. Add them to the snmp plugin's plugin.yaml.") }}</div>
|
|
{% else %}
|
|
|
|
{% for device in devices %}
|
|
<section class="card" aria-labelledby="snmp-{{ loop.index }}">
|
|
<div class="host-health-head">
|
|
{{ status_badge('up', 'Reachable') if device.readings else status_badge('pending', 'No data yet') }}
|
|
<h2 id="snmp-{{ loop.index }}" class="section-title" style="margin:0;">{{ device.name }}</h2>
|
|
<span class="field-hint mono">{{ device.host }}</span>
|
|
<a href="/plugins/snmp/device/{{ device.name }}" class="btn btn-sm btn-ghost" style="margin-left:auto;">History</a>
|
|
</div>
|
|
|
|
{% if device.readings %}
|
|
<div class="stat-strip" style="margin-bottom:0;">
|
|
{% for oid_cfg in device.oids %}
|
|
{% set label = oid_cfg.label if oid_cfg.label else oid_cfg.oid %}
|
|
{% set val = device.readings.get(label) %}
|
|
{{ stat_tile(label,
|
|
"—" if val is none else
|
|
("%.2fM"|format(val / 1000000)) if val >= 1000000 else
|
|
("%.1fK"|format(val / 1000)) if val >= 1000 else
|
|
"%.4g"|format(val)) }}
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<p class="field-hint">No readings yet; waiting for the next poll.</p>
|
|
{% endif %}
|
|
</section>
|
|
{% endfor %}
|
|
|
|
{% endif %}
|
|
{% endblock %}
|