From 025cd0336cb446e31f4879bef38c9e415b11f6b7 Mon Sep 17 00:00:00 2001 From: Peter van Arkel Date: Thu, 21 May 2026 14:43:24 +0200 Subject: [PATCH] (ui) Harden dashboard responsive layout Rework the dashboard priority grid to avoid cramped four-column layouts, prevent stretched empty panels, and make long host and snapshot text wrap safely across dashboard cards. Refs #38 --- .../templates/pobsync_backend/base.html | 39 +++++++++++++++++-- .../templates/pobsync_backend/dashboard.html | 8 ++-- src/pobsync_backend/tests/test_views.py | 4 ++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/pobsync_backend/templates/pobsync_backend/base.html b/src/pobsync_backend/templates/pobsync_backend/base.html index 7a343fe..7764651 100644 --- a/src/pobsync_backend/templates/pobsync_backend/base.html +++ b/src/pobsync_backend/templates/pobsync_backend/base.html @@ -304,17 +304,22 @@ } .inline-form { margin: 0; } .dashboard-priority-grid { + align-items: start; display: grid; gap: 14px; - grid-template-columns: minmax(280px, 1.25fr) repeat(3, minmax(220px, 1fr)); + grid-template-columns: repeat(2, minmax(0, 1fr)); margin-bottom: 20px; } .priority-panel { display: grid; gap: 12px; margin-bottom: 0; + min-width: 0; + } + .priority-panel > h2:first-child { + flex-wrap: wrap; + margin-bottom: 0; } - .priority-panel > h2:first-child { margin-bottom: 0; } .action-list, .activity-list, .schedule-list { @@ -404,6 +409,14 @@ gap: 2px; min-width: 0; } + .action-row strong, + .action-row .muted, + .activity-row strong, + .activity-row .muted, + .schedule-row strong, + .schedule-row .muted { + overflow-wrap: anywhere; + } .schedule-time { justify-items: end; text-align: right; @@ -436,6 +449,10 @@ justify-content: space-between; padding-top: 8px; } + .storage-priority-facts strong { + text-align: right; + overflow-wrap: anywhere; + } .host-control-grid { display: grid; gap: 14px; @@ -623,7 +640,7 @@ .host-card-timeline { display: grid; gap: 16px 22px; - grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); } .host-card-stats { align-content: start; @@ -649,6 +666,10 @@ .host-card-item .value { overflow-wrap: anywhere; } + .host-card-item .value a { + overflow-wrap: anywhere; + word-break: break-word; + } .host-card-stat { display: grid; gap: 3px; @@ -778,6 +799,18 @@ .host-card-stats { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); } .insight-grid { grid-template-columns: 1fr; } } + @media (max-width: 1100px) { + .dashboard-priority-grid { + grid-template-columns: 1fr; + } + .schedule-row { + grid-template-columns: 1fr; + } + .schedule-time { + justify-items: start; + text-align: left; + } + } diff --git a/src/pobsync_backend/templates/pobsync_backend/dashboard.html b/src/pobsync_backend/templates/pobsync_backend/dashboard.html index 97324f8..830b0ad 100644 --- a/src/pobsync_backend/templates/pobsync_backend/dashboard.html +++ b/src/pobsync_backend/templates/pobsync_backend/dashboard.html @@ -33,7 +33,7 @@ {% endif %}
-
+

Required Action

{% if action_items %}
@@ -70,7 +70,7 @@ {% endif %}
-
+

Next Scheduled Work View all

{% if next_schedule_rows %}
@@ -96,7 +96,7 @@ {% endif %}
-
+

Recent Activity View all

{% if recent_runs %}
@@ -115,7 +115,7 @@ {% endif %}
-
+

Storage Pressure

{% if stats_summary.runs_sampled %}
diff --git a/src/pobsync_backend/tests/test_views.py b/src/pobsync_backend/tests/test_views.py index e221eeb..227e602 100644 --- a/src/pobsync_backend/tests/test_views.py +++ b/src/pobsync_backend/tests/test_views.py @@ -103,6 +103,10 @@ class ViewTests(TestCase): 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-panel-required") + self.assertContains(response, "dashboard-panel-schedules") + self.assertContains(response, "dashboard-panel-activity") + self.assertContains(response, "dashboard-panel-storage") self.assertContains(response, "Dashboard") self.assertContains(response, "web-01") self.assertContains(response, "20260519-021500Z__ABCDEFGH")