Files
FabledSteward/plugins/prometheus/templates/prometheus/template.html
T
bvandeusenandClaude Opus 5.5 4195b9171a
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 1m16s
CI / unit (push) Successful in 1m30s
CI / publish (push) Successful in 22s
docs(prometheus): writing a widget template, every block, and the format reference (#5694)
docs/plugins/prometheus-widgets.md covers:
- where templates live and how to copy one in, duplicate, export and share;
- a first template, walked through;
- each block (states with its deadlines, values, times, table, info) with an
  example;
- the format reference: keys, units, spans, limits, what the checker refuses;
- the Fabled Archives template, block by block, with what it leaves out and
  why.

Linked from the README, the plugin guide, the editor and template_format.
tests/plugins/prometheus/test_widget_guide.py checks every YAML example in the
guide against the checker, so the guide can't drift from the format.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 09:51:56 -04:00

93 lines
5.0 KiB
HTML

{# plugins/prometheus/templates/prometheus/template.html — one widget
template (#5692): its YAML beside a live preview over a chosen target,
drawn as the dashboard widget draws it. An admin edits their own here,
or starts one by pasting or uploading; a built-in one is read-only and
can be duplicated. The preview saves nothing. #}
{% extends "base.html" %}
{% from "_macros.html" import crumbs, page_header %}
{% from "prometheus/_tabs.html" import prometheus_tabs %}
{% block title %}{{ title }} — Widget templates — Steward{% endblock %}
{% block section_tabs %}{{ prometheus_tabs("templates") }}{% endblock %}
{% block breadcrumb %}{{ crumbs([("Prometheus", "/plugins/prometheus/"), ("Widget templates", "/plugins/prometheus/templates/"), (title, "")]) }}{% endblock %}
{% block content %}
{% set admin = session.user_role == 'admin' %}
{% call page_header(title, ("Built in, read-only" if entry.bundled else "Your own") if entry else none) %}
{% if entry %}
<a class="btn btn-sm btn-ghost" href="/plugins/prometheus/templates/{{ entry.key }}/export">Export</a>
{% if admin %}<a class="btn btn-sm btn-ghost" href="/plugins/prometheus/templates/new?from={{ entry.key|urlencode }}">Duplicate</a>{% endif %}
{% endif %}
{% endcall %}
{% if problems %}
<div class="field-error" role="alert">
{{ "Not saved. " if saving }}{{ problems|length }} problem{{ "s" if problems|length != 1 }} to fix:
<ul class="tpl-problems">{% for p in problems %}<li>{{ p }}</li>{% endfor %}</ul>
</div>
{% endif %}
{% if note %}<p class="field-hint">{{ note }}</p>{% endif %}
{% if entry and entry.bundled %}
<p class="field-hint">Ships with Steward and changes with it. To change it, duplicate it and edit the copy.</p>
{% endif %}
{% if used %}<p class="field-hint">{{ used }} dashboard widget{{ "s draw" if used != 1 else " draws" }} with it{{ "; saving changes them too" if editable }}.</p>{% endif %}
<div class="tpl-editor">
<form method="post" id="tpl-form"
action="{{ '/plugins/prometheus/templates/custom:' ~ entry.id ~ '/edit' if entry else '/plugins/prometheus/templates/new' }}">{{ csrf_field() }}
<label class="field-label" for="tpl-text">YAML</label>
<textarea class="input mono tpl-text" id="tpl-text" name="text" spellcheck="false" wrap="off"
{%- if not editable %} readonly{% endif %}
placeholder="Paste a template here, or write one: name, version and blocks. The guide is docs/plugins/prometheus-widgets.md.">{{ text }}</textarea>
{% if editable %}
<div class="form-actions">
<button type="submit" class="btn">{{ "Save" if entry else "Save template" }}</button>
<a href="{{ '/plugins/prometheus/templates/' ~ entry.key if entry else '/plugins/prometheus/templates/' }}" class="btn btn-ghost">Cancel</a>
</div>
{% endif %}
</form>
<section class="card" aria-labelledby="tpl-preview-title">
<div class="tpl-preview-head">
<h2 id="tpl-preview-title" class="section-title">Preview</h2>
{% if targets %}
<label class="sr-only" for="tpl-target">Target</label>
<select class="input" id="tpl-target" name="target">
{% for t in targets %}<option value="{{ t.value }}">{{ t.label }}</option>{% endfor %}
</select>
{% endif %}
</div>
<div id="tpl-preview" class="dash-cell-body" aria-live="polite"
hx-post="/plugins/prometheus/templates/preview"
hx-trigger="load, input changed delay:600ms from:#tpl-text, change from:#tpl-target"
hx-include="#tpl-text, #tpl-target">
<p class="field-hint">Loading…</p>
</div>
</section>
</div>
{% if editable and not entry %}
<section class="card form-section" aria-labelledby="tpl-upload">
<h2 id="tpl-upload" class="section-title">Or upload a file</h2>
<form method="post" action="/plugins/prometheus/templates/upload" enctype="multipart/form-data"
style="display:flex;gap:0.75rem;align-items:center;flex-wrap:wrap;">{{ csrf_field() }}
<label class="sr-only" for="tpl-file">Template file</label>
<input id="tpl-file" type="file" name="file" accept=".yaml,.yml,text/yaml,application/yaml">
<button type="submit" class="btn btn-sm btn-ghost">Read file</button>
<span class="field-hint">Opens it here to look over; nothing is saved until you press Save.</span>
</form>
</section>
{% endif %}
{% if editable and entry %}
<section class="card danger-zone" aria-labelledby="tpl-delete">
<div>
<h2 id="tpl-delete" class="section-title">Delete this template</h2>
<p class="field-hint">{% if used %}{{ used }} widget{{ "s" if used != 1 }} using it will say the template is gone.{% else %}No widget uses it.{% endif %} Export it first to keep a copy.</p>
</div>
<form method="post" action="/plugins/prometheus/templates/custom:{{ entry.id }}/delete"
data-confirm="Delete widget template {{ entry.name }}?{% if used %} {{ used }} widget{{ 's' if used != 1 }} use it.{% endif %}">{{ csrf_field() }}
<button class="btn btn-danger" type="submit">Delete template</button>
</form>
</section>
{% endif %}
{% endblock %}