From 025cd0336cb446e31f4879bef38c9e415b11f6b7 Mon Sep 17 00:00:00 2001 From: Peter van Arkel Date: Thu, 21 May 2026 14:43:24 +0200 Subject: [PATCH 1/3] (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") From b55950e24a3a61864c51da82e11b12913decf408 Mon Sep 17 00:00:00 2001 From: Peter van Arkel Date: Thu, 21 May 2026 14:46:23 +0200 Subject: [PATCH 2/3] (ui) Add dashboard section responsive hooks Give dashboard summary, trends, and host sections dedicated layout hooks and tighten their responsive behavior so metrics and host cards remain readable on narrower screens. Refs #38 --- .../templates/pobsync_backend/base.html | 52 ++++++++++++++++--- .../templates/pobsync_backend/dashboard.html | 6 +-- src/pobsync_backend/tests/test_views.py | 3 ++ 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/pobsync_backend/templates/pobsync_backend/base.html b/src/pobsync_backend/templates/pobsync_backend/base.html index 7764651..9fd7f44 100644 --- a/src/pobsync_backend/templates/pobsync_backend/base.html +++ b/src/pobsync_backend/templates/pobsync_backend/base.html @@ -179,10 +179,19 @@ box-shadow: var(--shadow); transform: translateY(-1px); } - .metric-link:focus-visible { - outline: 3px solid #93c5fd; - outline-offset: 2px; - } + .metric-link:focus-visible { + outline: 3px solid #93c5fd; + outline-offset: 2px; + } + .dashboard-summary-grid { + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + } + .dashboard-summary-grid .metric { + min-height: 78px; + } + .dashboard-summary-grid .metric .value { + font-size: 25px; + } .panel { margin-bottom: 18px; overflow: auto; @@ -622,8 +631,8 @@ } .host-card-layout { display: grid; - gap: 24px; - grid-template-columns: minmax(0, 2fr) minmax(260px, 1fr); + gap: 18px; + grid-template-columns: minmax(0, 1.7fr) minmax(240px, 0.9fr); } .host-card-section { align-content: start; @@ -700,6 +709,9 @@ margin-top: 14px; padding: 10px; } + .host-card-warning > * { + min-width: 0; + } .messages { display: grid; gap: 8px; margin-bottom: 18px; } .message { background: var(--panel); @@ -803,6 +815,16 @@ .dashboard-priority-grid { grid-template-columns: 1fr; } + .dashboard-summary-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + .host-card-layout { + grid-template-columns: 1fr; + } + .host-card-status { + justify-content: flex-start; + max-width: none; + } .schedule-row { grid-template-columns: 1fr; } @@ -811,6 +833,24 @@ text-align: left; } } + @media (max-width: 560px) { + .dashboard-summary-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .metric { + min-height: 76px; + padding: 12px; + } + .metric .value { + font-size: 24px; + } + .host-card { + padding: 13px; + } + .host-card-stats { + grid-template-columns: 1fr; + } + } diff --git a/src/pobsync_backend/templates/pobsync_backend/dashboard.html b/src/pobsync_backend/templates/pobsync_backend/dashboard.html index 830b0ad..cefa769 100644 --- a/src/pobsync_backend/templates/pobsync_backend/dashboard.html +++ b/src/pobsync_backend/templates/pobsync_backend/dashboard.html @@ -163,7 +163,7 @@
-
+
Hosts
{{ counts.enabled_hosts }}/{{ counts.hosts }}
Schedules
{{ counts.enabled_schedules }}/{{ counts.schedules }}
Snapshots
{{ counts.snapshots }}
@@ -172,7 +172,7 @@
Failed
{{ counts.failed_runs }}
-
+ -
+

Hosts

{% for host in hosts %} diff --git a/src/pobsync_backend/tests/test_views.py b/src/pobsync_backend/tests/test_views.py index 227e602..68c64d2 100644 --- a/src/pobsync_backend/tests/test_views.py +++ b/src/pobsync_backend/tests/test_views.py @@ -107,6 +107,9 @@ class ViewTests(TestCase): self.assertContains(response, "dashboard-panel-schedules") self.assertContains(response, "dashboard-panel-activity") self.assertContains(response, "dashboard-panel-storage") + self.assertContains(response, "dashboard-summary-grid") + self.assertContains(response, "dashboard-trends-panel") + self.assertContains(response, "dashboard-hosts-panel") self.assertContains(response, "Dashboard") self.assertContains(response, "web-01") self.assertContains(response, "20260519-021500Z__ABCDEFGH") From 0e2f48ab6535e127ed8120e80df9f30e776eac8d Mon Sep 17 00:00:00 2001 From: Peter van Arkel Date: Thu, 21 May 2026 14:50:05 +0200 Subject: [PATCH 3/3] (ui) Remove dashboard panel overflow traps Let dashboard-specific panels size naturally instead of inheriting generic panel overflow behavior, and tighten activity and host card sizing so long content wraps without creating internal scrollbars. Refs #38 --- src/pobsync_backend/templates/pobsync_backend/base.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/pobsync_backend/templates/pobsync_backend/base.html b/src/pobsync_backend/templates/pobsync_backend/base.html index 9fd7f44..9a670b1 100644 --- a/src/pobsync_backend/templates/pobsync_backend/base.html +++ b/src/pobsync_backend/templates/pobsync_backend/base.html @@ -191,6 +191,10 @@ } .dashboard-summary-grid .metric .value { font-size: 25px; + } + .dashboard-trends-panel, + .dashboard-hosts-panel { + overflow: visible; } .panel { margin-bottom: 18px; @@ -324,6 +328,7 @@ gap: 12px; margin-bottom: 0; min-width: 0; + overflow: visible; } .priority-panel > h2:first-child { flex-wrap: wrap; @@ -399,6 +404,9 @@ .activity-row { grid-template-columns: max-content minmax(0, 1fr); } + .activity-row .status { + justify-self: start; + } .schedule-row { grid-template-columns: minmax(0, 1fr) max-content; } @@ -598,6 +606,7 @@ border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-sm); + min-width: 0; padding: 16px; } .host-card:hover {