From a75b97c4c0f72c08f557b16cbe89cfabeb2984ec Mon Sep 17 00:00:00 2001 From: Peter van Arkel Date: Thu, 21 May 2026 01:51:13 +0200 Subject: [PATCH] (ui) Add dashboard operational status summary Make queued, running, warning, and failed run states more visible at the top of the dashboard with contextual status summaries and highlighted summary metrics. Also show an all-clear message when configured hosts have no active or problematic runs. --- .../templates/pobsync_backend/base.html | 21 +++++++++ .../templates/pobsync_backend/dashboard.html | 44 +++++++++++++++++-- src/pobsync_backend/tests/test_views.py | 16 +++++++ 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/pobsync_backend/templates/pobsync_backend/base.html b/src/pobsync_backend/templates/pobsync_backend/base.html index ba29361..7177a6e 100644 --- a/src/pobsync_backend/templates/pobsync_backend/base.html +++ b/src/pobsync_backend/templates/pobsync_backend/base.html @@ -61,6 +61,10 @@ .metric { padding: 14px; } .metric .label { color: var(--muted); font-size: 12px; text-transform: uppercase; } .metric .value { font-size: 26px; font-weight: 650; margin-top: 4px; } + .metric.failed { border-color: #e8b4b4; background: #fff7f7; } + .metric.warning { border-color: #e7cf8a; background: #fffaf0; } + .metric.running { border-color: #e7cf8a; background: #fffaf0; } + .metric.queued { border-color: #b5cdea; background: #eef6ff; } .panel { padding: 16px; margin-bottom: 18px; overflow: auto; } .panel.highlight { border-left: 4px solid var(--border); } .panel.highlight.failed { border-left-color: var(--failed); background: #fff7f7; } @@ -118,6 +122,23 @@ cursor: not-allowed; } .inline-form { margin: 0; } + .status-overview { + display: grid; + gap: 8px; + } + .status-summary { + align-items: center; + border: 1px solid var(--border); + border-radius: 6px; + display: flex; + flex-wrap: wrap; + gap: 8px; + padding: 10px; + } + .status-summary.failed { border-color: #e8b4b4; background: #fff7f7; color: var(--failed); } + .status-summary.warning, + .status-summary.running { border-color: #e7cf8a; background: #fffaf0; color: var(--running); } + .status-summary.queued { border-color: #b5cdea; background: #eef6ff; color: var(--link); } .operator-state { align-items: center; display: flex; diff --git a/src/pobsync_backend/templates/pobsync_backend/dashboard.html b/src/pobsync_backend/templates/pobsync_backend/dashboard.html index e0299ce..b595b34 100644 --- a/src/pobsync_backend/templates/pobsync_backend/dashboard.html +++ b/src/pobsync_backend/templates/pobsync_backend/dashboard.html @@ -32,10 +32,46 @@
Schedules
{{ counts.enabled_schedules }}/{{ counts.schedules }}
Snapshots
{{ counts.snapshots }}
Runs
{{ counts.runs }}
-
Queued
{{ counts.queued_runs }}
-
Running
{{ counts.running_runs }}
-
Warnings
{{ counts.warning_runs }}
-
Failed
{{ counts.failed_runs }}
+
Queued
{{ counts.queued_runs }}
+
Running
{{ counts.running_runs }}
+
Warnings
{{ counts.warning_runs }}
+
Failed
{{ counts.failed_runs }}
+ + +
+

Operational Status

+ {% if counts.failed_runs or counts.warning_runs or counts.running_runs or counts.queued_runs %} +
+ {% if counts.failed_runs %} +
+ failed + {{ counts.failed_runs }} failed run{{ counts.failed_runs|pluralize }} need{{ counts.failed_runs|pluralize:"s," }} review. +
+ {% endif %} + {% if counts.warning_runs %} +
+ warning + {{ counts.warning_runs }} run{{ counts.warning_runs|pluralize }} completed with warnings. +
+ {% endif %} + {% if counts.running_runs %} +
+ running + {{ counts.running_runs }} backup run{{ counts.running_runs|pluralize }} in progress. +
+ {% endif %} + {% if counts.queued_runs %} +
+ queued + {{ counts.queued_runs }} backup run{{ counts.queued_runs|pluralize }} waiting for the worker. +
+ {% endif %} +
+ {% elif counts.hosts %} +

ok No queued, running, warning, or failed runs.

+ {% else %} +

Add a host to start tracking backup status here.

+ {% endif %}
diff --git a/src/pobsync_backend/tests/test_views.py b/src/pobsync_backend/tests/test_views.py index 64c79f1..5fcaa29 100644 --- a/src/pobsync_backend/tests/test_views.py +++ b/src/pobsync_backend/tests/test_views.py @@ -84,6 +84,11 @@ class ViewTests(TestCase): self.assertContains(response, "running 1") self.assertContains(response, "warning 1") self.assertContains(response, "failed 1") + self.assertContains(response, "Operational Status") + self.assertContains(response, "1 failed run needs review.") + self.assertContains(response, "1 run completed with warnings.") + self.assertContains(response, "1 backup run in progress.") + self.assertContains(response, "1 backup run waiting for the worker.") def test_dashboard_renders_backup_trend_summary(self) -> None: self.client.force_login(self.staff_user) @@ -148,6 +153,17 @@ class ViewTests(TestCase): self.assertContains(response, "No completed backup runs with stats yet.") self.assertContains(response, "growth estimates") + def test_dashboard_shows_all_clear_operational_status(self) -> None: + self.client.force_login(self.staff_user) + GlobalConfig.objects.create(name="default", backup_root="/opt/pobsync/backups") + HostConfig.objects.create(host="web-01", address="web-01.example.test") + + response = self.client.get(reverse("dashboard")) + + self.assertEqual(response.status_code, 200) + self.assertContains(response, "Operational Status") + self.assertContains(response, "No queued, running, warning, or failed runs.") + def test_dashboard_surfaces_retention_warnings(self) -> None: self.client.force_login(self.staff_user) host = HostConfig.objects.create(