Files
FabledSteward/steward/templates/settings/_plugin_repos.html
T
bvandeusenandClaude Opus 5.5 414c942cbf
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 1m5s
CI / unit (push) Successful in 1m19s
CI / publish (push) Successful in 57s
feat(plugins): Traefik problems first, UniFi/SNMP/fleet on shared shapes, audit names its entities, templates on tokens (#5126)
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>
2026-10-06 18:25:09 -04:00

100 lines
4.7 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{# settings/_plugin_repos.html — HTMX partial for plugin repository management #}
<div id="plugin-repos">
{% if repos %}
<div style="display:grid;gap:0.6rem;margin-bottom:0.6rem;">
{% for repo in repos %}
{% set idx = loop.index0 %}
<div class="card" style="padding:0;overflow:visible;">
{# ── View row ────────────────────────────────────────────────────────── #}
<div id="plugin-repo-view-{{ idx }}"
style="display:flex;align-items:center;gap:0.75rem;padding:0.85rem 1rem;">
<div style="flex:1;min-width:0;">
<div style="font-weight:500;font-size:0.88rem;">{{ repo.name or repo.url }}</div>
<div style="font-size:0.77rem;color:var(--text-muted);margin-top:0.1rem;
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">{{ repo.url }}</div>
</div>
<div style="display:flex;gap:0.4rem;flex-shrink:0;">
<button class="btn btn-ghost btn-sm" style="font-size:0.78rem;"
onclick="toggleRepoEdit({{ idx|int }})">Edit</button>
<button class="btn btn-danger btn-sm" style="font-size:0.78rem;"
hx-post="/settings/plugins/repos/{{ idx }}/remove"
hx-target="#plugin-repos"
hx-swap="outerHTML"
hx-confirm="Remove repository '{{ repo.name or repo.url }}'?">×</button>
</div>
</div>
{# ── Inline edit form ──────────────────────────────────────────────── #}
<div id="plugin-repo-edit-{{ idx }}"
style="display:none;border-top:1px solid var(--border);padding:1rem;">
<form hx-post="/settings/plugins/repos/{{ idx }}/save"
hx-target="#plugin-repos"
hx-swap="outerHTML">
<div style="display:grid;grid-template-columns:1fr 2fr;gap:0.6rem;">
<div class="form-group" style="margin:0;">
<label style="font-size:0.8rem;">Name</label>
<input type="text" name="name" value="{{ repo.name }}" placeholder="My Plugins">
</div>
<div class="form-group" style="margin:0;">
<label style="font-size:0.8rem;">Index URL</label>
<input type="url" name="url" value="{{ repo.url }}"
placeholder="https://example.com/plugins/index.yaml" required>
</div>
</div>
<div style="display:flex;gap:0.5rem;margin-top:0.75rem;">
<button type="submit" class="btn btn-sm">Save</button>
<button type="button" class="btn btn-ghost btn-sm"
onclick="toggleRepoEdit({{ idx|int }})">Cancel</button>
</div>
</form>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="card" style="color:var(--text-muted);font-size:0.88rem;text-align:center;padding:1.5rem;margin-bottom:0.6rem;">
No repositories charted. Add one below.
</div>
{% endif %}
{# ── Add repository ────────────────────────────────────────────────────────── #}
<details class="card" style="padding:0;overflow:hidden;">
<summary style="display:flex;align-items:center;gap:0.75rem;padding:0.85rem 1rem;
cursor:pointer;list-style:none;user-select:none;">
<span style="flex:1;font-weight:500;font-size:0.875rem;color:var(--text);">Add Repository</span>
<span class="btn btn-sm" style="pointer-events:none;">New ▾</span>
</summary>
<form hx-post="/settings/plugins/repos/add"
hx-target="#plugin-repos"
hx-swap="outerHTML"
style="padding:1rem;padding-top:0;border-top:1px solid var(--border);">
<div style="display:grid;grid-template-columns:1fr 2fr;gap:0.6rem;padding-top:1rem;">
<div class="form-group" style="margin:0;">
<label style="font-size:0.8rem;">Name</label>
<input type="text" name="name" placeholder="My Plugins">
</div>
<div class="form-group" style="margin:0;">
<label style="font-size:0.8rem;">Index URL</label>
<input type="url" name="url"
placeholder="https://example.com/plugins/index.yaml" required>
</div>
</div>
<button type="submit" class="btn btn-sm" style="margin-top:0.75rem;width:100%;">
Add Repository
</button>
</form>
</details>
</div>
<script>
function toggleRepoEdit(idx) {
var edit = document.getElementById('plugin-repo-edit-' + idx);
edit.style.display = edit.style.display === 'none' ? 'block' : 'none';
}
</script>