(feature) Show next scheduled run and backup run type in the UI

Add a scheduler helper that calculates the next due time for a cron-style
schedule expression and surface that value on the dashboard and host detail
pages.

Show the latest run type in host summaries and backup trend tables so
manual and scheduled backups are distinguishable in the Django UI.

Keep the calculation derived from existing ScheduleConfig data without
adding a migration.
This commit is contained in:
2026-05-19 22:57:58 +02:00
parent 9624fb469f
commit 86eee0f916
7 changed files with 55 additions and 6 deletions

View File

@@ -37,6 +37,7 @@ class ViewTests(TestCase):
snapshot = self._snapshot(host, "20260519-021500Z__ABCDEFGH")
run = BackupRun.objects.create(
host=host,
run_type=BackupRun.RunType.MANUAL,
status=BackupRun.Status.SUCCESS,
snapshot=snapshot,
started_at=datetime(2026, 5, 19, 2, 15, tzinfo=timezone.utc),
@@ -57,6 +58,7 @@ class ViewTests(TestCase):
snapshot = self._snapshot(host, "20260519-021500Z__ABCDEFGH")
run = BackupRun.objects.create(
host=host,
run_type=BackupRun.RunType.MANUAL,
status=BackupRun.Status.SUCCESS,
snapshot=snapshot,
started_at=datetime(2026, 5, 19, 2, 15, tzinfo=timezone.utc),
@@ -79,6 +81,7 @@ class ViewTests(TestCase):
},
},
)
ScheduleConfig.objects.create(host=host, cron_expr="* * * * *", enabled=True)
response = self.client.get(reverse("dashboard"))
@@ -87,8 +90,10 @@ class ViewTests(TestCase):
self.assertContains(response, "Runs Until Full")
self.assertContains(response, "Avg Daily New")
self.assertContains(response, "Days Until Full")
self.assertContains(response, "Next Run")
self.assertContains(response, "10")
self.assertContains(response, f"Run {run.id}")
self.assertContains(response, "manual")
self.assertContains(response, "1000")
def test_dashboard_links_latest_snapshot_for_each_host(self) -> None:
@@ -548,6 +553,7 @@ class ViewTests(TestCase):
self.assertContains(response, "15 2 * * *")
self.assertContains(response, "Schedule expression")
self.assertContains(response, "Evaluated by the pobsync scheduler service.")
self.assertContains(response, "Next run:")
self.assertContains(response, "20260519-021500Z__ABCDEFGH")
self.assertContains(response, "Discover snapshots")
self.assertContains(response, "Edit schedule")
@@ -570,6 +576,7 @@ class ViewTests(TestCase):
snapshot = self._snapshot(host, "20260519-021500Z__ABCDEFGH")
BackupRun.objects.create(
host=host,
run_type=BackupRun.RunType.MANUAL,
status=BackupRun.Status.SUCCESS,
snapshot=snapshot,
started_at=datetime(2026, 5, 19, 2, 15, tzinfo=timezone.utc),
@@ -611,6 +618,7 @@ class ViewTests(TestCase):
self.assertContains(response, "Backup Trends")
self.assertContains(response, "Avg New Data")
self.assertContains(response, "Avg Daily New")
self.assertContains(response, "manual")
self.assertContains(response, "45s")
self.assertContains(response, "250")
self.assertContains(response, "2.0")