Files
FabledSteward/steward/templates/alerts/rules_form.html
T
bvandeusen 88ab5b917e chore: rename project Roundtable → Steward
Renames the Python package directory, CLI command, env var prefix,
docker-compose service/container/image, Postgres role/db, and all
visible branding. Marketing form is "Fabled Steward".

Clean break from the previous rebrand: drops the fabledscryer→roundtable
import shim in __init__.py and the FABLEDSCRYER_* env var fallback in
config.py and migrations/env.py. Env vars are now STEWARD_* only.

Heads-up for existing deployments:
- Postgres user/db renamed fabledscryer → steward in docker-compose.yml.
  Existing volumes need the role/db renamed inside Postgres, or override
  POSTGRES_USER/POSTGRES_DB to keep the old names.
- Host-agent systemd unit is now steward-agent.service. Existing agents
  keep running under the old name; reinstall to switch.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 16:20:14 -04:00

139 lines
6.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.
{% extends "base.html" %}
{% block title %}{% if rule %}Edit Rule{% else %}New Alert Rule{% endif %} — Steward{% endblock %}
{% block content %}
<div style="max-width:600px;margin:2rem auto;">
<h1 class="page-title">{% if rule %}Edit Rule{% else %}New Alert Rule{% endif %}</h1>
<div class="card">
<form method="post" action="{% if rule %}/alerts/rules/{{ rule.id }}{% else %}/alerts/rules{% endif %}">
<div class="form-group">
<label>Rule Name</label>
<input type="text" name="name" required autofocus
value="{{ rule.name if rule else '' }}"
placeholder="e.g. Home server down">
</div>
{# ── Source module ───────────────────────────────────────────────────── #}
<div class="form-group">
<label>Source</label>
<select name="source_module" required
hx-get="/alerts/api/rule_fields"
hx-trigger="change"
hx-target="#rule-fields"
hx-include="[name='source_module']">
{% for src in source_modules %}
<option value="{{ src }}" {% if src == initial_source %}selected{% endif %}>
{{ src }}
</option>
{% endfor %}
</select>
</div>
{# ── Dynamic resource + metric ────────────────────────────────────────── #}
<div id="rule-fields">
{# Inline the same partial logic so the page is fully usable without JS #}
<div class="form-group">
<label>Resource Name</label>
{% if resources %}
<select name="resource_name" required>
{% if not (rule and rule.resource_name) %}<option value="" disabled selected>— pick a resource —</option>{% endif %}
{% for r in resources %}
<option value="{{ r }}" {% if rule and r == rule.resource_name %}selected{% endif %}>{{ r }}</option>
{% endfor %}
</select>
{% else %}
<select name="resource_name" required disabled>
<option value="">No data yet — run monitors first</option>
</select>
<p style="font-size:0.78rem;color:var(--text-muted);margin-top:0.25rem;">
Resource names populate from live metric data. Start the scheduler and try again.
</p>
{% endif %}
</div>
<div class="form-group">
<label>Metric Name</label>
<select name="metric_name" required>
{% if not (rule and rule.metric_name) %}<option value="" disabled selected>— pick a metric —</option>{% endif %}
{% for m in metrics %}
<option value="{{ m }}" {% if rule and m == rule.metric_name %}selected{% endif %}>{{ m }}</option>
{% endfor %}
</select>
</div>
</div>
{# ── Condition ───────────────────────────────────────────────────────── #}
<div style="display:grid;grid-template-columns:1fr 1fr;gap:1rem;">
<div class="form-group">
<label>Operator</label>
<select name="operator">
{% for val, label in operators %}
<option value="{{ val }}" {% if rule and rule.operator.value == val %}selected{% endif %}>
{{ label }}
</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label>Threshold</label>
<input type="number" name="threshold" step="any" required
value="{{ rule.threshold if rule else '' }}"
placeholder="0.5">
</div>
</div>
<div class="form-group">
<label>Consecutive failures before FIRING</label>
<input type="number" name="consecutive_failures_required" min="1"
value="{{ rule.consecutive_failures_required if rule else 1 }}">
</div>
{# ── Metric reference ────────────────────────────────────────────────── #}
<details style="margin-bottom:1rem;">
<summary style="cursor:pointer;font-size:0.82rem;color:var(--text-muted);user-select:none;">
Metric reference
</summary>
<div style="margin-top:0.75rem;display:grid;gap:0.5rem;">
{% set descs = {
"ping": [("up", "1.0 = reachable, 0.0 = unreachable"),
("response_time_ms", "round-trip latency in milliseconds")],
"dns": [("resolved", "1.0 = resolved, 0.0 = failed"),
("ip_changed", "1.0 when resolved IP differs from expected")],
"traefik": [("request_rate", "requests/sec for this router"),
("error_rate", "fraction of 5xx responses (01)"),
("latency_p50_ms", "median response time ms"),
("latency_p95_ms", "p95 response time ms"),
("latency_p99_ms", "p99 response time ms"),
("response_bytes_rate", "bytes/sec of responses"),
("cert_expiry_days", "days until TLS cert expires")],
"unifi": [("is_up", "1.0 = WAN up, 0.0 = down"),
("latency_ms", "WAN latency in ms"),
("total_clients", "number of connected clients")],
"docker": [("cpu_pct", "container CPU usage %"),
("mem_pct", "container memory usage %")],
"http": [("is_up", "1.0 = check passed, 0.0 = failed"),
("response_ms", "HTTP response time in ms")],
} %}
{% for src, pairs in descs.items() %}
<div>
<div style="font-size:0.78rem;font-weight:600;color:var(--text-dim);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:0.2rem;">{{ src }}</div>
{% for metric, desc in pairs %}
<div style="display:grid;grid-template-columns:160px 1fr;gap:0.5rem;font-size:0.78rem;padding:0.15rem 0;">
<code>{{ metric }}</code>
<span style="color:var(--text-muted);">{{ desc }}</span>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
</details>
<div style="display:flex;gap:1rem;margin-top:1.5rem;">
<button type="submit" class="btn">{% if rule %}Save Changes{% else %}Create Rule{% endif %}</button>
<a href="/alerts/" class="btn btn-ghost">Cancel</a>
</div>
</form>
</div>
</div>
{% endblock %}