## Summary
- Add a dedicated `/hosts/` page with host cards and enabled/disabled filtering. - Link the dashboard Hosts metric and top navigation to the new page. - Add host enable/disable plus schedule and scheduled-retention pause/resume actions. ## Tests - `.venv/bin/python manage.py test src.pobsync_backend.tests.test_views.ViewTests.test_base_navigation_groups_primary_and_system_links src.pobsync_backend.tests.test_views.ViewTests.test_dashboard_renders_hosts_and_latest_runs src.pobsync_backend.tests.test_views.ViewTests.test_dashboard_hosts_live_returns_hosts_partial src.pobsync_backend.tests.test_views.ViewTests.test_hosts_list_renders_host_cards_and_controls src.pobsync_backend.tests.test_views.ViewTests.test_hosts_list_filters_by_enabled_state src.pobsync_backend.tests.test_views.ViewTests.test_update_host_state_toggles_host_schedule_and_retention --verbosity 2` - `.venv/bin/python manage.py check` - `.venv/bin/python manage.py test src.pobsync_backend --verbosity 2` Closes #48 Closes #49
This commit is contained in:
@@ -48,6 +48,7 @@ class ViewTests(TestCase):
|
||||
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("hosts_list"))
|
||||
self.assertContains(response, reverse("ssh_credentials"))
|
||||
self.assertContains(response, reverse("logs"))
|
||||
self.assertContains(response, reverse("purged_snapshots"))
|
||||
@@ -202,6 +203,72 @@ class ViewTests(TestCase):
|
||||
self.assertContains(response, "Snapshot health")
|
||||
self.assertNotContains(response, "<html", html=False)
|
||||
|
||||
def test_hosts_list_renders_host_cards_and_controls(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
web = HostConfig.objects.create(host="web-01", address="web-01.example.test")
|
||||
db = HostConfig.objects.create(host="db-01", address="db-01.example.test", enabled=False)
|
||||
ScheduleConfig.objects.create(host=web, cron_expr="15 2 * * *", enabled=True, prune=True)
|
||||
BackupRun.objects.create(host=web, status=BackupRun.Status.RUNNING)
|
||||
|
||||
response = self.client.get(reverse("hosts_list"))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Inventory")
|
||||
self.assertContains(response, "Configured backup targets")
|
||||
self.assertContains(response, "web-01")
|
||||
self.assertContains(response, "db-01")
|
||||
self.assertContains(response, "running 1")
|
||||
self.assertContains(response, "schedule on")
|
||||
self.assertContains(response, "retention on")
|
||||
self.assertContains(response, "Disable host")
|
||||
self.assertContains(response, "Enable host")
|
||||
self.assertContains(response, "Pause schedule")
|
||||
self.assertContains(response, "Pause retention")
|
||||
self.assertContains(response, reverse("update_host_state", args=[web.host]))
|
||||
self.assertContains(response, reverse("edit_host_config", args=[web.host]))
|
||||
self.assertContains(response, reverse("edit_host_schedule", args=[web.host]))
|
||||
|
||||
def test_hosts_list_filters_by_enabled_state(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
HostConfig.objects.create(host="web-01", address="web-01.example.test")
|
||||
HostConfig.objects.create(host="db-01", address="db-01.example.test", enabled=False)
|
||||
|
||||
response = self.client.get(reverse("hosts_list"), {"enabled": "no"})
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "db-01")
|
||||
self.assertNotContains(response, "web-01")
|
||||
|
||||
def test_update_host_state_toggles_host_schedule_and_retention(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
host = HostConfig.objects.create(host="web-01", address="web-01.example.test")
|
||||
schedule = ScheduleConfig.objects.create(host=host, cron_expr="15 2 * * *", enabled=True, prune=True)
|
||||
|
||||
response = self.client.post(
|
||||
reverse("update_host_state", args=[host.host]),
|
||||
{"action": "disable_host", "next": reverse("hosts_list")},
|
||||
follow=True,
|
||||
)
|
||||
self.assertRedirects(response, reverse("hosts_list"))
|
||||
host.refresh_from_db()
|
||||
self.assertFalse(host.enabled)
|
||||
self.assertContains(response, "Disabled host web-01.")
|
||||
|
||||
self.client.post(reverse("update_host_state", args=[host.host]), {"action": "disable_schedule"})
|
||||
self.client.post(reverse("update_host_state", args=[host.host]), {"action": "disable_prune"})
|
||||
schedule.refresh_from_db()
|
||||
self.assertFalse(schedule.enabled)
|
||||
self.assertFalse(schedule.prune)
|
||||
|
||||
self.client.post(reverse("update_host_state", args=[host.host]), {"action": "enable_host"})
|
||||
self.client.post(reverse("update_host_state", args=[host.host]), {"action": "enable_schedule"})
|
||||
self.client.post(reverse("update_host_state", args=[host.host]), {"action": "enable_prune"})
|
||||
host.refresh_from_db()
|
||||
schedule.refresh_from_db()
|
||||
self.assertTrue(host.enabled)
|
||||
self.assertTrue(schedule.enabled)
|
||||
self.assertTrue(schedule.prune)
|
||||
|
||||
def test_dashboard_renders_backup_trend_summary(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
GlobalConfig.objects.create(name="default", backup_root="/missing-backup-root")
|
||||
|
||||
Reference in New Issue
Block a user