feat: maintenance windows, reports, uptime widget, alert improvements

- Add maintenance window scheduling to suppress alerts during planned
  downtime (model, routes, templates)
- Add weekly email/webhook reports with host summary (core/reports.py,
  Settings → Reports tab)
- Add host uptime history widget with per-check sparkline view
- Expand alert rules: dynamic metric catalog for plugin sources,
  per-rule HTMX field loading, maintenance window awareness
- Register additional dashboard widgets (uptime, SNMP, UniFi, UPS)
- Add Settings → Reports tab configuration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-23 08:15:30 -04:00
parent 3c70ac56b3
commit ced1eebe1d
17 changed files with 1286 additions and 84 deletions
+17 -1
View File
@@ -49,7 +49,7 @@ def create_app(
if not testing:
from .core.settings import (
load_settings_sync, to_smtp_cfg, to_webhook_cfg,
to_ansible_cfg, to_plugins_cfg,
to_ansible_cfg, to_plugins_cfg, to_oidc_cfg, to_ldap_cfg,
)
_settings = load_settings_sync(app.config["DATABASE_URL"])
app.config.update(
@@ -60,6 +60,8 @@ def create_app(
WEBHOOK=to_webhook_cfg(_settings),
ANSIBLE=to_ansible_cfg(_settings),
PLUGINS=to_plugins_cfg(_settings),
OIDC=to_oidc_cfg(_settings),
LDAP=to_ldap_cfg(_settings),
)
else:
app.config.update(
@@ -70,6 +72,8 @@ def create_app(
WEBHOOK={},
ANSIBLE={},
PLUGINS={},
OIDC={"enabled": False},
LDAP={"enabled": False},
)
# ── 5. Plugin migrations ───────────────────────────────────────────────────
@@ -95,6 +99,7 @@ def create_app(
from .alerts.routes import alerts_bp
from .ansible.routes import ansible_bp
from .settings.routes import settings_bp
from .audit.routes import audit_bp
app.register_blueprint(auth_bp)
app.register_blueprint(dashboard_bp)
@@ -104,6 +109,7 @@ def create_app(
app.register_blueprint(alerts_bp)
app.register_blueprint(ansible_bp)
app.register_blueprint(settings_bp)
app.register_blueprint(audit_bp)
# ── 8. Build task registry ─────────────────────────────────────────────────
app._task_registry = []
@@ -199,7 +205,17 @@ def _register_core_tasks(app: Quart) -> None:
from .core.cleanup import run_cleanup as _cleanup
await _cleanup(app)
async def run_report_check():
from .core.reports import check_and_send
await check_and_send(app)
app._task_registry.extend([
ScheduledTask(
name="weekly_report_check",
coro_factory=run_report_check,
interval_seconds=3600,
run_on_startup=False,
),
ScheduledTask(
name="ping_monitor",
coro_factory=run_ping_monitors,