diff --git a/src/pobsync_backend/templates/pobsync_backend/base.html b/src/pobsync_backend/templates/pobsync_backend/base.html index 070bf2b..0d321f5 100644 --- a/src/pobsync_backend/templates/pobsync_backend/base.html +++ b/src/pobsync_backend/templates/pobsync_backend/base.html @@ -43,7 +43,7 @@ outline: 3px solid rgba(7, 95, 174, 0.24); outline-offset: 2px; } - header { + body > header { background: var(--panel); border-bottom: 1px solid var(--border); box-shadow: var(--shadow-sm); @@ -105,6 +105,35 @@ } p { margin: 0 0 12px; } p:last-child { margin-bottom: 0; } + .page-header { + align-items: end; + display: flex; + gap: 18px; + justify-content: space-between; + margin-bottom: 20px; + } + .page-title { + display: grid; + gap: 5px; + min-width: 0; + } + .page-title h1 { margin-bottom: 0; overflow-wrap: anywhere; } + .page-kicker { + color: var(--muted); + font-size: 12px; + font-weight: 750; + letter-spacing: 0.05em; + text-transform: uppercase; + } + .page-subtitle { + color: var(--muted); + max-width: 760px; + } + .page-header .actions { + flex: 0 0 auto; + justify-content: flex-end; + margin-bottom: 0; + } .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); @@ -483,7 +512,7 @@ padding: 0; } @media (max-width: 800px) { - header { padding: 0 14px; position: static; } + body > header { padding: 0 14px; position: static; } main { padding: 18px 14px 32px; } nav { align-items: flex-start; @@ -493,6 +522,11 @@ } nav strong { flex-basis: 100%; margin-right: 0; } nav .spacer { display: none; } + .page-header { + align-items: stretch; + display: grid; + } + .page-header .actions { justify-content: flex-start; } .two-col { grid-template-columns: 1fr; } .host-card-header { display: grid; } .host-card-status { justify-content: flex-start; max-width: none; } diff --git a/src/pobsync_backend/templates/pobsync_backend/dashboard.html b/src/pobsync_backend/templates/pobsync_backend/dashboard.html index b6067fb..358fd72 100644 --- a/src/pobsync_backend/templates/pobsync_backend/dashboard.html +++ b/src/pobsync_backend/templates/pobsync_backend/dashboard.html @@ -3,12 +3,17 @@ {% block title %}pobsync dashboard{% endblock %} {% block content %} -

Dashboard

- -
- New host - {% if global_config %}Edit global config{% else %}Create global config{% endif %} -
+ {% if not global_config or not counts.hosts %}
diff --git a/src/pobsync_backend/templates/pobsync_backend/host_detail.html b/src/pobsync_backend/templates/pobsync_backend/host_detail.html index ae530e2..60bbae8 100644 --- a/src/pobsync_backend/templates/pobsync_backend/host_detail.html +++ b/src/pobsync_backend/templates/pobsync_backend/host_detail.html @@ -3,29 +3,34 @@ {% block title %}{{ host.host }} | pobsync{% endblock %} {% block content %} -

{{ host.host }}

- -
- Edit config -
- {% csrf_token %} - -
- Plan retention - Edit schedule -
- {% csrf_token %} - -
-
- {% csrf_token %} - -
-
- {% csrf_token %} - -
-
+
Snapshots
{{ counts.snapshots }}
diff --git a/src/pobsync_backend/templates/pobsync_backend/retention_plan.html b/src/pobsync_backend/templates/pobsync_backend/retention_plan.html index ba88c9c..c1547b8 100644 --- a/src/pobsync_backend/templates/pobsync_backend/retention_plan.html +++ b/src/pobsync_backend/templates/pobsync_backend/retention_plan.html @@ -3,15 +3,20 @@ {% block title %}Retention plan | {{ host.host }}{% endblock %} {% block content %} -

Retention Plan: {{ host.host }}

- -
- Back to host - Scheduled - Manual - All - Protect bases -
+
Kind
{{ plan.kind }}
diff --git a/src/pobsync_backend/templates/pobsync_backend/run_detail.html b/src/pobsync_backend/templates/pobsync_backend/run_detail.html index 4fbf6aa..8f042f9 100644 --- a/src/pobsync_backend/templates/pobsync_backend/run_detail.html +++ b/src/pobsync_backend/templates/pobsync_backend/run_detail.html @@ -3,25 +3,30 @@ {% block title %}Run {{ run.id }} | {{ run.host.host }}{% endblock %} {% block content %} -

Run {{ run.id }}

- -
- Back to host - {% if can_cancel %} -
- {% csrf_token %} - -
- {% endif %} - {% if run.status == "failed" or run.status == "warning" %} - {% if not run.reviewed_at %} -
+
+
Host
{{ run.host.host }}
diff --git a/src/pobsync_backend/templates/pobsync_backend/snapshot_detail.html b/src/pobsync_backend/templates/pobsync_backend/snapshot_detail.html index c37b5ee..9520853 100644 --- a/src/pobsync_backend/templates/pobsync_backend/snapshot_detail.html +++ b/src/pobsync_backend/templates/pobsync_backend/snapshot_detail.html @@ -3,11 +3,16 @@ {% block title %}Snapshot {{ snapshot.dirname }} | {{ snapshot.host.host }}{% endblock %} {% block content %} -

{{ snapshot.dirname }}

- -
- Back to host -
+
Host
{{ snapshot.host.host }}
diff --git a/src/pobsync_backend/tests/test_views.py b/src/pobsync_backend/tests/test_views.py index a731ba5..cb42255 100644 --- a/src/pobsync_backend/tests/test_views.py +++ b/src/pobsync_backend/tests/test_views.py @@ -101,6 +101,8 @@ class ViewTests(TestCase): response = self.client.get(reverse("dashboard")) self.assertEqual(response.status_code, 200) + self.assertContains(response, "Control panel") + self.assertContains(response, "Backup health, required action, storage pressure, and recent activity in one place.") self.assertContains(response, "Dashboard") self.assertContains(response, "web-01") self.assertContains(response, "20260519-021500Z__ABCDEFGH") @@ -869,6 +871,8 @@ class ViewTests(TestCase): response = self.client.get(reverse("host_detail", args=[host.host])) self.assertEqual(response.status_code, 200) + self.assertContains(response, "Host") + self.assertContains(response, "web-01.example.test") self.assertContains(response, "Effective Config") self.assertContains(response, "Backup source:") self.assertNotContains(response, "Source root:") @@ -1425,6 +1429,8 @@ class ViewTests(TestCase): response = self.client.get(reverse("run_detail", args=[run.id])) self.assertEqual(response.status_code, 200) + self.assertContains(response, "Backup run") + self.assertContains(response, "web-01") self.assertContains(response, "Failure") self.assertContains(response, "transport") self.assertContains(response, "Check network connectivity.") @@ -1615,6 +1621,7 @@ class ViewTests(TestCase): response = self.client.get(reverse("snapshot_detail", args=[base.id])) self.assertEqual(response.status_code, 200) + self.assertContains(response, "Snapshot") self.assertContains(response, base.dirname) self.assertContains(response, "BASESNAP") self.assertContains(response, "Stats") @@ -1697,7 +1704,9 @@ class ViewTests(TestCase): response = self.client.get(reverse("host_retention_plan", args=[host.host])) self.assertEqual(response.status_code, 200) - self.assertContains(response, "Retention Plan: web-01") + self.assertContains(response, "Retention") + self.assertContains(response, "Preview which snapshots stay") + self.assertContains(response, "web-01") self.assertContains(response, old_snapshot.dirname) self.assertContains(response, new_snapshot.dirname) self.assertContains(response, "newest")