diff --git a/src/pobsync_backend/stats_summary.py b/src/pobsync_backend/stats_summary.py index 8382891..c682203 100644 --- a/src/pobsync_backend/stats_summary.py +++ b/src/pobsync_backend/stats_summary.py @@ -52,9 +52,10 @@ def collect_dashboard_stats(*, hosts: Iterable[HostConfig], global_config: Globa def collect_host_stats(*, host: HostConfig, limit: int = 8) -> dict[str, Any]: - runs = list(host.runs.select_related("snapshot").filter(status__in=_COMPLETED_BACKUP_STATUSES).order_by("-started_at", "-created_at")[:50]) + runs = list(host.runs.select_related("snapshot").order_by("-started_at", "-created_at")[:50]) real_runs = [_run_summary(run) for run in runs if _is_real_run(run)] - trend_runs = [run for run in real_runs if run["has_stats"]][:limit] + completed_real_runs = [run for run in real_runs if run["status"] in _COMPLETED_BACKUP_STATUSES] + trend_runs = [run for run in completed_real_runs if run["has_stats"]][:limit] latest_snapshot = host.snapshots.order_by("-started_at", "-discovered_at", "-id").first() latest_snapshot_stats = _snapshot_summary(latest_snapshot) if latest_snapshot else {} @@ -67,7 +68,9 @@ def collect_host_stats(*, host: HostConfig, limit: int = 8) -> dict[str, Any]: return { "runs": [_with_bar_percentages(run, max_literal=max_literal, max_matched=max_matched) for run in trend_runs], - "latest_run": real_runs[0] if real_runs else {}, + "latest_run": completed_real_runs[0] if completed_real_runs else {}, + "latest_good_run": _first_run_with_status(real_runs, {BackupRun.Status.SUCCESS}), + "latest_problem_run": _first_run_with_status(real_runs, {BackupRun.Status.WARNING, BackupRun.Status.FAILED}), "latest_snapshot": latest_snapshot_stats, "avg_literal_data_bytes": _average(literal_values), "avg_daily_literal_data_bytes": _average_daily_literal(trend_runs), @@ -87,6 +90,7 @@ def _run_summary(run: BackupRun) -> dict[str, Any]: "ended_at": run.ended_at, "snapshot": run.snapshot, "snapshot_path": run.snapshot_path, + "status": run.status, "has_stats": bool(stats), "duration_seconds": _int_at(stats, "duration_seconds"), "rsync": stats.get("rsync") if isinstance(stats.get("rsync"), dict) else {}, @@ -121,6 +125,13 @@ def _is_real_run(run: BackupRun) -> bool: return requested.get("dry_run") is not True +def _first_run_with_status(runs: list[dict[str, Any]], statuses: set[str]) -> dict[str, Any]: + for run in runs: + if run["status"] in statuses: + return run + return {} + + def _capacity_from_system(global_config: GlobalConfig | None) -> dict[str, Any]: if global_config is None or not global_config.backup_root: return {} diff --git a/src/pobsync_backend/templates/pobsync_backend/dashboard.html b/src/pobsync_backend/templates/pobsync_backend/dashboard.html index 9b2b6ba..9a6b755 100644 --- a/src/pobsync_backend/templates/pobsync_backend/dashboard.html +++ b/src/pobsync_backend/templates/pobsync_backend/dashboard.html @@ -32,7 +32,9 @@