feat(prometheus): the Prometheus dashboard widget, target + template (#5691)
#5691 "Generic Prometheus dashboard widget: pick a target and a template", step 3 of milestone 508 "Prometheus widget templates". - /plugins/prometheus/widget draws one target with one template in widget shape: the verdict (led by "isn't answering" when the target is down), then each block with problems first, figures beside a share bar or the last 24h of bars, and the healthy rest folding to "+N more healthy" past six. A missing target or template, or one that no longer checks, says so. - library.py: bundled templates from plugins/prometheus/widgets/*.yaml, the picker's target and template lists, and the default title. - widgets/fabled_archives.yaml: the first bundled template, against the series Archives reports (refined in #5693). - Dashboard: a widget setting may take `options_from` (read when the picker opens) with an `empty` sentence; `default_title`; a Details link may name settings ("/plugins/prometheus/targets/{target}"). Prometheus is grouped with the integrations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
{# prometheus/widget.html — the Prometheus dashboard widget (#5691): one
|
||||
target drawn by one template (template_view.render). A verdict naming the
|
||||
worst thing, then each block: its problems first with why, figures in their
|
||||
units beside a bar or the last day's bars, and the healthy rest packed after,
|
||||
past REST rows as "+N more healthy". #}
|
||||
{% from "_macros.html" import status_dot %}
|
||||
{% set REST = 6 %}
|
||||
{% set dot = {"crit": "crit", "warn": "warn", "ok": "ok", "dim": "paused"} %}
|
||||
{% set tone = {"crit": "tone-crit", "warn": "tone-warn", "ok": "tone-ok", "dim": "tone-dim"} %}
|
||||
{% macro shown(v) -%}
|
||||
{%- if v.moment %}{{ v.moment|ago }}{% elif v.text %}{{ v.text }}{% else %}—{% endif -%}
|
||||
{%- endmacro %}
|
||||
{% if problem %}
|
||||
<div class="w-verdict tone-warn">{{ problem }}</div>
|
||||
{% else %}
|
||||
{% set down = target.reach in ("down", "stale") %}
|
||||
<div class="w-verdict {{ 'tone-crit' if target.reach == 'down' else tone[view.tone] }}">
|
||||
{%- if target.reach == "down" %}{{ target.name }} isn't answering{% elif down %}{{ target.name }} isn't being scraped{% endif %}
|
||||
{%- if down %}{% if target.ok_at %}; these values are from {{ target.ok_at|ago }}{% endif %}. {% endif -%}
|
||||
{{ view.verdict }}
|
||||
</div>
|
||||
{% for b in view.blocks %}
|
||||
<div class="w-section">{{ b.title }}</div>
|
||||
{% if b.note %}
|
||||
<div class="w-note tone-warn">{{ b.note }}</div>
|
||||
{% elif b.kind == "info" %}
|
||||
<div class="w-note">{% for r in b.rows %}{{ r.name }}{% if not loop.last %}; {% endif %}{% endfor %}</div>
|
||||
{% elif b.kind == "table" %}
|
||||
<table class="w-table">
|
||||
<thead><tr><th></th>{% for c in b.columns %}<th>{{ c }}</th>{% endfor %}</tr></thead>
|
||||
<tbody>
|
||||
{% for r in b.rows %}
|
||||
<tr><td class="w-name" title="{{ r.name }}">{{ r.name }}</td>{% for c in r.cells %}<td>{{ shown(c) }}</td>{% endfor %}</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
{% set problems = b.rows | selectattr("tone", "in", ["crit", "warn"]) | list %}
|
||||
{% set rest = b.rows | rejectattr("tone", "in", ["crit", "warn"]) | list %}
|
||||
{% set listed = problems + rest[:REST] %}
|
||||
<table class="w-table">
|
||||
{% if b.columns %}<thead><tr><th></th><th>Now</th>{% for c in b.columns %}<th class="w-wide-only">{{ c }}</th>{% endfor %}</tr></thead>{% endif %}
|
||||
<tbody>
|
||||
{% for r in listed %}
|
||||
<tr>
|
||||
<td class="w-name" title="{{ r.name }}">
|
||||
{{- status_dot(dot[r.tone]) -}}
|
||||
{{ r.name }}
|
||||
{%- if r.why %}<span class="w-sub {{ tone[r.tone] }}">{{ r.why }}</span>{% endif %}
|
||||
</td>
|
||||
<td class="{{ tone[r.tone] if r.tone in ('crit', 'warn') }}">
|
||||
{%- if r.history %}<span class="w-bars w-wide-only" aria-hidden="true" title="The last {{ spark_hours }}h, scaled to its own peak">
|
||||
{%- for h in r.history %}<i style="height:{{ [h, 4]|max }}%"></i>{% endfor -%}
|
||||
</span>{% endif -%}
|
||||
{{ shown(r) }}
|
||||
{%- if r.bar is not none %}<div class="meter w-wide-only" title="{{ (r.bar * 100)|round|int }}%"><div class="meter-fill meter-{{ r.tone if r.tone in ('crit', 'warn') else 'ok' }}" style="width:{{ (r.bar * 100)|round(1) }}%"></div></div>{% endif -%}
|
||||
</td>
|
||||
{% for c in r.cells %}<td class="w-wide-only">{{ shown(c) }}</td>{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if rest|length > REST %}<div class="w-more">+{{ rest|length - REST }} more healthy</div>{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<div class="w-note">
|
||||
{%- if session.user_id %}<a href="/plugins/prometheus/targets/{{ target.id }}">{{ target.name }}</a>{% else %}{{ target.name }}{% endif %}
|
||||
{%- if target.scraped_at %}, scraped {{ target.scraped_at|ago }}{% endif %}.
|
||||
</div>
|
||||
{% endif %}
|
||||
Reference in New Issue
Block a user