The Monitors list now opens with a count strip (down, up with how many degraded, pending, paused) and sorts down, degraded, pending, up, paused, by name within each. Degraded is up but worth a look: uptime at or below its warning floor, or the latest response past its critical cutoff, both from Settings → Thresholds; a slow-but-tolerable reply is coloured, not sorted. A monitor had no page of its own: every link went to the list. Now /monitors/<id> shows its state and since when, latency, uptime for 24h/7d/ 30d, TLS days, the last checks, recent failures with their errors, and its settings (HTTP header names, never their values). Status links to it, and adding or editing returns to it. Adding is its own page (/monitors/new, form.html shared with edit) behind an "Add monitor" button; a refused add re-renders the form with the error and what was typed instead of a bare 400 text. Row actions are labelled icon buttons, type names read Ping/TCP/DNS/HTTP (|monitor_type), and the heartbeat uses pill-up/pill-down, so HEX_CEILING drops to 56. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
67 lines
3.2 KiB
HTML
67 lines
3.2 KiB
HTML
{% extends "base.html" %}
|
|
{% from "_macros.html" import crumbs, page_header %}
|
|
{% from "monitors/_fields.html" import type_fields, toggle_script %}
|
|
{# Add (monitor is none; `values` holds what was typed) or edit a monitor. #}
|
|
{% block title %}{{ "Edit " ~ monitor.name if monitor else "Add monitor" }} — Steward{% endblock %}
|
|
{% block breadcrumb %}
|
|
{%- if monitor -%}
|
|
{{ crumbs([("Monitors", "/monitors/"), (monitor.name, "/monitors/" ~ monitor.id), ("Edit", "")]) }}
|
|
{%- else -%}
|
|
{{ crumbs([("Monitors", "/monitors/"), ("Add monitor", "")]) }}
|
|
{%- endif -%}
|
|
{% endblock %}
|
|
{% block content %}
|
|
{% set v = values or {} %}
|
|
{{ page_header("Edit monitor" if monitor else "Add monitor") }}
|
|
|
|
<div class="card" style="max-width:760px;">
|
|
{% if error %}<p class="field-error" role="alert">{{ error }}</p>{% endif %}
|
|
<form method="post" action="{{ '/monitors/' ~ monitor.id ~ '/edit' if monitor else '/monitors/add' }}" style="display:grid;gap:0.6rem;">{{ csrf_field() }}
|
|
{% if not monitor and v.host_id %}<input type="hidden" name="host_id" value="{{ v.host_id }}">{% endif %}
|
|
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:0.6rem;align-items:end;">
|
|
<div>
|
|
<label class="field-label" for="mtype">Type</label>
|
|
{% if monitor %}
|
|
<input type="text" id="mtype" value="{{ monitor.type|monitor_type }}" disabled class="input">
|
|
{% else %}
|
|
<select name="type" id="mtype" class="input">
|
|
{% for t in types %}
|
|
<option value="{{ t.value }}" {% if t.value == mtype %}selected{% endif %}>{{ t.value|monitor_type }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
{% endif %}
|
|
</div>
|
|
<div>
|
|
<label class="field-label" for="m-name">Name</label>
|
|
<input type="text" id="m-name" name="name" value="{{ monitor.name if monitor else v.name }}" placeholder="optional" autocomplete="off" class="input">
|
|
</div>
|
|
<div>
|
|
<label class="field-label" for="m-target">Target <span class="tone-crit" aria-hidden="true">*</span></label>
|
|
<input type="text" id="m-target" name="target" value="{{ monitor.target if monitor else v.target }}" placeholder="host, IP, or URL" autocomplete="off" required class="input">
|
|
</div>
|
|
<div>
|
|
<label class="field-label" for="m-interval">Interval (s, 0 = global)</label>
|
|
<input type="number" id="m-interval" name="check_interval_seconds" value="{{ monitor.check_interval_seconds if monitor else (v.check_interval_seconds or 0) }}" min="0" class="input">
|
|
</div>
|
|
{{ type_fields(config) }}
|
|
</div>
|
|
{% if monitor and monitor.host_id %}
|
|
<p class="field-hint">Linked to <a href="/hosts/{{ monitor.host_id }}">its host</a>.</p>
|
|
{% endif %}
|
|
<div style="display:flex;gap:0.5rem;">
|
|
<button type="submit" class="btn btn-sm">{{ "Save" if monitor else "Add monitor" }}</button>
|
|
<a href="{{ '/monitors/' ~ monitor.id if monitor else '/monitors/' }}" class="btn btn-sm btn-ghost">Cancel</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
{{ toggle_script() }}
|
|
<script>
|
|
(function () {
|
|
var sel = document.getElementById('mtype');
|
|
mtoggle({{ mtype|tojson }});
|
|
if (sel.tagName === 'SELECT') sel.addEventListener('change', function () { mtoggle(sel.value); });
|
|
})();
|
|
</script>
|
|
{% endblock %}
|