The last page of #5214's walk. Settings still described Steward as it was before monitors were unified and SNMP was rebuilt, drew its tabs below the breadcrumb, and showed the report schedule in UTC. - Tabs (#5377): settings/_tabs.html is a settings_tabs() macro called in each page's section_tabs block, above the trail, as Ansible's are. The breadcrumb guard also fails any page that {% include %}s a tab strip. - Report time (#5378): reports.schedule_tz keeps the zone of whoever saved the schedule; check_and_send compares in it (report_due), and the form shows the day and hour on the reader's clock (schedule_in) under their zone's name. "Last sent" uses |when. - Wording (#5379): the report contents list what the report holds (monitors, not ping-enabled hosts); "Ping latency" is "Response time" and says what it grades; plugin detail says enabling loads now and disabling needs a restart; the monitor interval says it applies on the next check (the scheduler reads it every pass); the dead list-config branch is gone. - Traefik (#5380): the 5xx and 4xx cutoffs are settings (traefik.threshold.error_5xx_pct 0.1, error_4xx_pct 1.0) in a "Traefik routers" group on Thresholds while the plugin runs, read by router_state through error_cutoffs(). The Traefik page has a Thresholds button for admins, to /settings/thresholds/#traefik. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
95 lines
5.2 KiB
HTML
95 lines
5.2 KiB
HTML
{# steward/templates/settings/general.html #}
|
|
{% extends "base.html" %}
|
|
{% from "_macros.html" import crumbs %}
|
|
{% block title %}Settings — General — Steward{% endblock %}
|
|
{% from "settings/_tabs.html" import settings_tabs %}
|
|
{% block section_tabs %}{{ settings_tabs("general") }}{% endblock %}
|
|
{% block breadcrumb %}{{ crumbs([("Settings", "/settings/"), ("General", "")]) }}{% endblock %}
|
|
{% block content %}
|
|
|
|
<form method="post" action="/settings/general/">{{ csrf_field() }}
|
|
<div class="card" style="max-width:640px;">
|
|
<h2 class="section-title" style="margin-bottom:1.25rem;">General</h2>
|
|
|
|
<div class="form-group">
|
|
<label>Public base URL</label>
|
|
<input type="text" name="general.public_base_url"
|
|
value="{{ settings['general.public_base_url'] }}"
|
|
placeholder="https://monitor.example.com">
|
|
<div style="font-size:0.78rem;color:var(--text-muted);margin-top:0.25rem;">
|
|
External URL where this Steward instance is reachable from the outside.
|
|
Leave blank to use whatever hostname you're currently browsing via.
|
|
Used by install scripts, share links, and alert notifications.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Trusted reverse proxies</label>
|
|
<input type="number" name="general.trusted_proxy_hops" min="0" max="5"
|
|
value="{{ settings['general.trusted_proxy_hops'] }}" style="max-width:120px;">
|
|
<div style="font-size:0.78rem;color:var(--text-muted);margin-top:0.25rem;">
|
|
How many proxies sit in front of Steward (e.g. 1 for Traefik, 2 for Cloudflare in front of Traefik).
|
|
Steward believes their X-Forwarded-For and X-Forwarded-Proto headers up to that many hops: it marks
|
|
the login cookie Secure and sends HSTS only when they report HTTPS, and throttles logins by the address
|
|
they report. 0 trusts no proxy.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Session lifetime <span style="color:var(--text-muted);font-size:0.8rem;">(hours)</span></label>
|
|
<input type="number" name="session.lifetime_hours" min="1" max="720"
|
|
value="{{ settings['session.lifetime_hours'] }}" style="max-width:120px;">
|
|
<div style="font-size:0.78rem;color:var(--text-muted);margin-top:0.25rem;">A login lasts this long; then Steward asks for the password again.</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Failed logins before a pause</label>
|
|
<div style="display:flex;gap:0.5rem;align-items:center;flex-wrap:wrap;">
|
|
<input type="number" name="login.max_failures" min="1" max="100"
|
|
value="{{ settings['login.max_failures'] }}" style="max-width:90px;">
|
|
<span style="font-size:0.85rem;color:var(--text-muted);">failures from one address pause its logins for</span>
|
|
<input type="number" name="login.lockout_minutes" min="1" max="1440"
|
|
value="{{ settings['login.lockout_minutes'] }}" style="max-width:90px;">
|
|
<span style="font-size:0.85rem;color:var(--text-muted);">minutes</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Data retention <span style="color:var(--text-muted);font-size:0.8rem;">(days)</span></label>
|
|
<input type="number" name="data.retention_days" min="1"
|
|
value="{{ settings['data.retention_days'] }}" style="max-width:120px;">
|
|
<div style="font-size:0.78rem;color:var(--text-muted);margin-top:0.25rem;">Monitor results, Ansible runs and their logs, alert history, and Traefik and UniFi samples older than this are pruned by the hourly cleanup. Host metrics, Docker data and container logs have their own windows under Settings → Thresholds.</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Audit log retention <span style="color:var(--text-muted);font-size:0.8rem;">(days)</span></label>
|
|
<input type="number" name="audit.retention_days" min="1"
|
|
value="{{ settings['audit.retention_days'] }}" style="max-width:120px;">
|
|
<div style="font-size:0.78rem;color:var(--text-muted);margin-top:0.25rem;">Who changed what. Kept longer than operational data; entries older than this are pruned by the hourly cleanup.</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Monitor poll interval <span style="color:var(--text-muted);font-size:0.8rem;">(seconds)</span></label>
|
|
<input type="number" name="monitors.poll_interval_seconds" min="10"
|
|
value="{{ settings['monitors.poll_interval_seconds'] }}" style="max-width:120px;">
|
|
<div style="font-size:0.78rem;color:var(--text-muted);margin-top:0.25rem;">How often each monitor is checked, unless it sets its own. Takes effect on the next check.</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>Log level</label>
|
|
<select name="log.level" style="max-width:160px;">
|
|
{% for level in log_levels %}
|
|
<option value="{{ level }}" {% if settings['log.level'] == level %}selected{% endif %}>{{ level | capitalize }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<div style="font-size:0.78rem;color:var(--text-muted);margin-top:0.25rem;">What reaches the container log. Applies when saved. Warning hides the line logged for each request.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="margin-top:1rem;display:flex;align-items:center;gap:1rem;">
|
|
<button type="submit" class="btn">Save</button>
|
|
<span style="font-size:0.82rem;color:var(--text-muted);">Changes to session lifetime take effect immediately.</span>
|
|
</div>
|
|
</form>
|
|
{% endblock %}
|