(feature) add Django detail views for backup runs and snapshots

Add staff-only run and snapshot detail pages so scheduler and command
output can be inspected from the Django UI.

Link dashboard and host detail tables to the new detail views, including
snapshot/base relationships and linked backup runs.

Render stored result and metadata JSON in readable form and cover the new
inspection views with tests.
This commit is contained in:
2026-05-19 12:31:47 +02:00
parent 6bcc15c174
commit 66e1f549b9
8 changed files with 239 additions and 6 deletions

View File

@@ -1,5 +1,7 @@
from __future__ import annotations
import json
from django.contrib import messages
from django.contrib.admin.views.decorators import staff_member_required
from django.db.models import Count
@@ -100,6 +102,31 @@ def host_detail(request, host: str):
return render(request, "pobsync_backend/host_detail.html", context)
@staff_member_required
def run_detail(request, run_id: int):
run = get_object_or_404(BackupRun.objects.select_related("host", "snapshot"), id=run_id)
context = {
"run": run,
"result_json": _pretty_json(run.result),
}
return render(request, "pobsync_backend/run_detail.html", context)
@staff_member_required
def snapshot_detail(request, snapshot_id: int):
snapshot = get_object_or_404(
SnapshotRecord.objects.select_related("host", "base").prefetch_related("derived_snapshots", "backup_runs"),
id=snapshot_id,
)
context = {
"snapshot": snapshot,
"metadata_json": _pretty_json(snapshot.metadata),
"backup_runs": snapshot.backup_runs.select_related("host").order_by("-created_at"),
"derived_snapshots": snapshot.derived_snapshots.select_related("host").order_by("-started_at", "dirname"),
}
return render(request, "pobsync_backend/snapshot_detail.html", context)
@staff_member_required
@require_POST
def discover_host_snapshots(request, host: str):
@@ -229,3 +256,7 @@ def _default_host_initial() -> dict[str, object]:
"retention_monthly": 12,
"retention_yearly": 0,
}
def _pretty_json(value: object) -> str:
return json.dumps(value or {}, indent=2, sort_keys=True)