From 6035c547aeb3a5bc555c762c62de81ba225b9ed0 Mon Sep 17 00:00:00 2001 From: Peter van Arkel Date: Thu, 21 May 2026 14:56:30 +0200 Subject: [PATCH] (ui) Split primary and system navigation Move operator routes into a primary navigation group and demote admin, self-check, changelog, and status API links into a secondary system group so the header reflects the control panel workflow more clearly. Refs #37 --- .../templates/pobsync_backend/base.html | 44 +++++++++++++++---- src/pobsync_backend/tests/test_views.py | 17 +++++++ 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/pobsync_backend/templates/pobsync_backend/base.html b/src/pobsync_backend/templates/pobsync_backend/base.html index 9a670b1..35eef5f 100644 --- a/src/pobsync_backend/templates/pobsync_backend/base.html +++ b/src/pobsync_backend/templates/pobsync_backend/base.html @@ -80,6 +80,23 @@ padding-left: 0; } nav strong a:hover { background: transparent; } + .nav-primary, + .nav-secondary { + align-items: center; + display: flex; + flex-wrap: wrap; + gap: 4px; + } + .nav-secondary { + justify-content: flex-end; + } + .nav-secondary a { + font-size: 13px; + } + .nav-user { + margin-left: 6px; + white-space: nowrap; + } nav .spacer { flex: 1; } main { max-width: 1180px; @@ -801,6 +818,12 @@ padding: 8px 0; } nav strong { flex-basis: 100%; margin-right: 0; } + .nav-secondary { + justify-content: flex-start; + } + .nav-user { + margin-left: 0; + } nav .spacer { display: none; } .page-header { align-items: stretch; @@ -866,15 +889,20 @@
diff --git a/src/pobsync_backend/tests/test_views.py b/src/pobsync_backend/tests/test_views.py index 68c64d2..497f3ea 100644 --- a/src/pobsync_backend/tests/test_views.py +++ b/src/pobsync_backend/tests/test_views.py @@ -39,6 +39,23 @@ class ViewTests(TestCase): self.assertEqual(response.status_code, 302) self.assertIn("/admin/login/", response["Location"]) + def test_base_navigation_groups_primary_and_system_links(self) -> None: + self.client.force_login(self.staff_user) + + response = self.client.get(reverse("dashboard")) + + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'aria-label="Primary navigation"', html=False) + self.assertContains(response, 'aria-label="System navigation"', html=False) + self.assertContains(response, reverse("dashboard")) + self.assertContains(response, reverse("ssh_credentials")) + self.assertContains(response, reverse("logs")) + self.assertContains(response, reverse("purged_snapshots")) + self.assertContains(response, reverse("self_check")) + self.assertContains(response, reverse("changelog")) + self.assertContains(response, "/api/status/") + self.assertContains(response, reverse("admin:index")) + def test_changelog_requires_staff_login(self) -> None: response = self.client.get(reverse("changelog"))