From 0f0de5dc30b85fbff776c9eea1eb0b5bda25ec00 Mon Sep 17 00:00:00 2001 From: Peter van Arkel Date: Thu, 21 May 2026 14:22:11 +0200 Subject: [PATCH] (ui) Standardize list filter actions Give run, snapshot, schedule, purged snapshot, and log filters the same responsive form layout with consistent Apply/Clear actions. Refs #25 --- .../templates/pobsync_backend/base.html | 14 ++++++++++++++ .../templates/pobsync_backend/logs.html | 5 +++-- .../pobsync_backend/purged_snapshots.html | 4 ++-- .../templates/pobsync_backend/runs_list.html | 4 ++-- .../templates/pobsync_backend/schedules_list.html | 4 ++-- .../templates/pobsync_backend/snapshots_list.html | 4 ++-- src/pobsync_backend/tests/test_views.py | 15 +++++++++++++++ 7 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/pobsync_backend/templates/pobsync_backend/base.html b/src/pobsync_backend/templates/pobsync_backend/base.html index 3d3cd22..7a343fe 100644 --- a/src/pobsync_backend/templates/pobsync_backend/base.html +++ b/src/pobsync_backend/templates/pobsync_backend/base.html @@ -690,6 +690,13 @@ .message.error { border-color: #e8b4b4; background: #fff0f0; color: var(--failed); } .message.warning { border-color: #e7cf8a; background: #fff8df; color: var(--running); } .form-grid { display: grid; gap: 15px; max-width: 720px; } + .filter-form { + align-items: end; + display: grid; + gap: 15px; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + max-width: none; + } .form-actions { align-items: center; border-top: 1px solid var(--border); @@ -700,6 +707,13 @@ padding-top: 15px; } .form-actions .button-link.secondary { margin-left: auto; } + .filter-form .form-actions { + border-top: 0; + justify-content: flex-end; + margin-top: 0; + padding-top: 0; + } + .filter-form .form-actions .button-link.secondary { margin-left: 0; } .field { display: grid; gap: 6px; } .field label { font-weight: 700; } .field input[type="text"], .field input[type="number"], .field select, .field textarea { diff --git a/src/pobsync_backend/templates/pobsync_backend/logs.html b/src/pobsync_backend/templates/pobsync_backend/logs.html index 8eb57d2..f917473 100644 --- a/src/pobsync_backend/templates/pobsync_backend/logs.html +++ b/src/pobsync_backend/templates/pobsync_backend/logs.html @@ -16,7 +16,7 @@

Filter

-
+
-
+
+ Clear
diff --git a/src/pobsync_backend/templates/pobsync_backend/purged_snapshots.html b/src/pobsync_backend/templates/pobsync_backend/purged_snapshots.html index d6ed8ce..f623dd7 100644 --- a/src/pobsync_backend/templates/pobsync_backend/purged_snapshots.html +++ b/src/pobsync_backend/templates/pobsync_backend/purged_snapshots.html @@ -16,7 +16,7 @@

Filters

-
+
-
+
Clear
diff --git a/src/pobsync_backend/templates/pobsync_backend/runs_list.html b/src/pobsync_backend/templates/pobsync_backend/runs_list.html index 9be3a57..f366fb4 100644 --- a/src/pobsync_backend/templates/pobsync_backend/runs_list.html +++ b/src/pobsync_backend/templates/pobsync_backend/runs_list.html @@ -16,7 +16,7 @@

Filters

- +
-
+
Clear
diff --git a/src/pobsync_backend/templates/pobsync_backend/schedules_list.html b/src/pobsync_backend/templates/pobsync_backend/schedules_list.html index ada648b..9600b22 100644 --- a/src/pobsync_backend/templates/pobsync_backend/schedules_list.html +++ b/src/pobsync_backend/templates/pobsync_backend/schedules_list.html @@ -16,7 +16,7 @@

Filters

- +
-
+
Clear
diff --git a/src/pobsync_backend/templates/pobsync_backend/snapshots_list.html b/src/pobsync_backend/templates/pobsync_backend/snapshots_list.html index a6d8e7c..7676452 100644 --- a/src/pobsync_backend/templates/pobsync_backend/snapshots_list.html +++ b/src/pobsync_backend/templates/pobsync_backend/snapshots_list.html @@ -16,7 +16,7 @@

Filters

- +
-
+
Clear
diff --git a/src/pobsync_backend/tests/test_views.py b/src/pobsync_backend/tests/test_views.py index 5099734..4ac4bb4 100644 --- a/src/pobsync_backend/tests/test_views.py +++ b/src/pobsync_backend/tests/test_views.py @@ -233,6 +233,9 @@ class ViewTests(TestCase): self.assertEqual(response.status_code, 200) self.assertContains(response, "Runs") self.assertContains(response, "Review queued, running, completed") + self.assertContains(response, "Apply filters") + self.assertContains(response, reverse("runs_list")) + self.assertContains(response, "Clear") self.assertContains(response, f"Run {failed.id}") self.assertContains(response, "web-01") self.assertContains(response, "needed") @@ -275,6 +278,9 @@ class ViewTests(TestCase): self.assertEqual(response.status_code, 200) self.assertContains(response, "Snapshots") self.assertContains(response, "Browse discovered scheduled, manual, and incomplete snapshots") + self.assertContains(response, "Apply filters") + self.assertContains(response, reverse("snapshots_list")) + self.assertContains(response, "Clear") self.assertContains(response, manual.dirname) self.assertContains(response, "web-01") self.assertNotContains(response, scheduled.dirname) @@ -291,6 +297,9 @@ class ViewTests(TestCase): self.assertEqual(response.status_code, 200) self.assertContains(response, "Schedules") self.assertContains(response, "Review configured backup schedules") + self.assertContains(response, "Apply filters") + self.assertContains(response, reverse("schedules_list")) + self.assertContains(response, "Clear") self.assertContains(response, "web-01") self.assertContains(response, "15 2 * * *") self.assertContains(response, "success") @@ -428,6 +437,9 @@ class ViewTests(TestCase): self.assertEqual(response.status_code, 200) self.assertContains(response, "Logs") self.assertContains(response, "Filter pobsync service logs") + self.assertContains(response, "Filter logs") + self.assertContains(response, reverse("logs")) + self.assertContains(response, "Clear") self.assertContains(response, "web-01 failed backup run 12") self.assertNotContains(response, "web-02 failed backup run 12") self.assertNotContains(response, "started") @@ -458,6 +470,9 @@ class ViewTests(TestCase): self.assertEqual(response.status_code, 200) self.assertContains(response, "Purged Snapshots") self.assertContains(response, "Audit trail for snapshots removed") + self.assertContains(response, "Apply filters") + self.assertContains(response, reverse("purged_snapshots")) + self.assertContains(response, "Clear") self.assertContains(response, "20260518-021500Z__OLDSNAP") self.assertContains(response, "outside retention policy") self.assertContains(response, "Scheduled")