feat(prometheus): the widget template library: list, edit with live preview, paste in, upload, export, duplicate (#5692)
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 1m16s
CI / unit (push) Failing after 1m29s
CI / publish (push) Skipped

Prometheus gains a "Widget templates" tab beside Targets. It lists the
built-in templates and an admin's own, any that no longer pass the checker
first. A template opens as its YAML beside a live preview drawn over a
chosen target exactly as the dashboard widget draws it (routes.draw, now
shared by both). An admin writes or pastes a new one, reads a .yaml upload
into the editor to look over, duplicates any template under a free name,
edits and deletes their own; anyone can export the YAML. Built-in
templates are read-only.

Custom templates are rows in prometheus_widget_templates (migration
prometheus_002_templates), kept in backups, keyed "custom:<id>" so a
rename keeps its widgets. Saving needs a template that passes the checker
and a name no other template has. Create, update and delete are audited
and link to the template.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 09:22:31 -04:00
co-authored by Claude Opus 5.5
parent 5ca13f9278
commit bd762307e0
18 changed files with 849 additions and 28 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ KEPT: frozenset[str] = frozenset({
"alert_rules", "alert_states", "maintenance_windows",
"ansible_targets", "ansible_groups", "ansible_target_groups", "ansible_schedules",
"dashboards", "dashboard_widgets", "dashboard_share_tokens",
"snmp_devices", "prometheus_targets",
"snmp_devices", "prometheus_targets", "prometheus_widget_templates",
# Names given to network clients by hand (UniFi's alias column).
"unifi_known_clients",
# History kept by the ruling.
+10
View File
@@ -624,3 +624,13 @@ body.dash-editing .widget-drawer { transform:translateY(0); }
.range-btn { background:none; border:1px solid var(--border-control); border-radius:4px; color:var(--text-muted); padding:0.18rem 0.5rem; cursor:pointer; font-size:0.75rem; font-family:inherit; transition:background .1s,color .1s,border-color .1s; }
.range-btn:hover { background:var(--bg-elevated); color:var(--text); border-color:var(--accent); }
.range-btn.active { background:var(--accent); border-color:var(--accent); color:var(--fs-surface-page); }
/* The Prometheus widget template editor (#5692): the YAML beside its live
preview, which is drawn at about a dashboard cell's width; stacked on a
narrow screen. */
.tpl-editor { display:grid; grid-template-columns:minmax(0,1fr) 24rem; gap:1rem; align-items:start; margin-bottom:1rem; }
@media (max-width: 900px) { .tpl-editor { grid-template-columns:1fr; } }
.tpl-text { width:100%; min-height:28rem; font-size:0.8rem; line-height:1.45; tab-size:2; white-space:pre; resize:vertical; }
.tpl-problems { margin:0.3rem 0 0; padding-left:1.1rem; font-size:0.82rem; }
.tpl-preview-head { display:flex; align-items:center; gap:0.75rem; margin-bottom:0.5rem; }
.tpl-preview-head .section-title { margin:0; }
.tpl-preview-head select { margin-left:auto; max-width:12rem; }