v20260104-14-reports-stats-total-runs-success-rate-fix #28
@ -1 +1 @@
|
|||||||
v20260104-08-reports-html-total-runs-and-jobs-table-fix
|
v20260104-09-reports-html-total-runs-selection-and-jobs-text-column-remove
|
||||||
|
|||||||
@ -222,7 +222,6 @@ def build_report_columns_meta():
|
|||||||
"reviewed_at",
|
"reviewed_at",
|
||||||
],
|
],
|
||||||
"jobs": [
|
"jobs": [
|
||||||
"object_name",
|
|
||||||
"customer_name",
|
"customer_name",
|
||||||
"job_name",
|
"job_name",
|
||||||
"backup_software",
|
"backup_software",
|
||||||
@ -292,7 +291,7 @@ def build_report_columns_meta():
|
|||||||
{
|
{
|
||||||
"name": "Text",
|
"name": "Text",
|
||||||
"items": [
|
"items": [
|
||||||
{"key": "object_name", "label": "Text", "views": ["snapshot", "summary", "jobs"]},
|
{"key": "object_name", "label": "Text", "views": ["snapshot", "summary"]},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -624,12 +623,14 @@ def api_reports_data(report_id: int):
|
|||||||
return err
|
return err
|
||||||
|
|
||||||
report = ReportDefinition.query.get_or_404(report_id)
|
report = ReportDefinition.query.get_or_404(report_id)
|
||||||
include_keys = _get_success_rate_keys_from_report(report)
|
include_keys = None
|
||||||
|
|
||||||
view = (request.args.get("view") or "summary").strip().lower()
|
view = (request.args.get("view") or "summary").strip().lower()
|
||||||
if view not in ("summary", "snapshot", "jobs"):
|
if view not in ("summary", "snapshot", "jobs"):
|
||||||
view = "summary"
|
view = "summary"
|
||||||
|
|
||||||
|
include_keys = _get_success_rate_keys_from_report(report, view_key=view)
|
||||||
|
|
||||||
limit = _clamp_int(request.args.get("limit"), default=100, min_v=1, max_v=500)
|
limit = _clamp_int(request.args.get("limit"), default=100, min_v=1, max_v=500)
|
||||||
offset = _clamp_int(request.args.get("offset"), default=0, min_v=0, max_v=1_000_000)
|
offset = _clamp_int(request.args.get("offset"), default=0, min_v=0, max_v=1_000_000)
|
||||||
|
|
||||||
@ -652,7 +653,7 @@ def api_reports_data(report_id: int):
|
|||||||
"object_name": r.object_name or "",
|
"object_name": r.object_name or "",
|
||||||
"customer_id": int(r.customer_id) if getattr(r, "customer_id", None) is not None else "",
|
"customer_id": int(r.customer_id) if getattr(r, "customer_id", None) is not None else "",
|
||||||
"customer_name": r.customer_name or "",
|
"customer_name": r.customer_name or "",
|
||||||
"total_runs": int(r.total_runs or 0),
|
"total_runs": _compute_total_runs(int(r.success_count or 0), int(r.warning_count or 0), int(r.failed_count or 0), int(r.missed_count or 0), include_keys),
|
||||||
"success_count": int(r.success_count or 0),
|
"success_count": int(r.success_count or 0),
|
||||||
"success_override_count": int(r.success_override_count or 0),
|
"success_override_count": int(r.success_override_count or 0),
|
||||||
"warning_count": int(r.warning_count or 0),
|
"warning_count": int(r.warning_count or 0),
|
||||||
@ -734,7 +735,7 @@ def api_reports_data(report_id: int):
|
|||||||
"job_name": r.job_name or "",
|
"job_name": r.job_name or "",
|
||||||
"backup_software": r.backup_software or "",
|
"backup_software": r.backup_software or "",
|
||||||
"backup_type": r.backup_type or "",
|
"backup_type": r.backup_type or "",
|
||||||
"total_runs": int(r.total_runs or 0),
|
"total_runs": _compute_total_runs(int(r.success_count or 0), int(r.warning_count or 0), int(r.failed_count or 0), int(r.missed_count or 0), include_keys),
|
||||||
"success_count": int(r.success_count or 0),
|
"success_count": int(r.success_count or 0),
|
||||||
"success_override_count": int(r.success_override_count or 0),
|
"success_override_count": int(r.success_override_count or 0),
|
||||||
"warning_count": int(r.warning_count or 0),
|
"warning_count": int(r.warning_count or 0),
|
||||||
@ -838,6 +839,20 @@ def _get_success_rate_keys_from_report(report: ReportDefinition, view_key: str =
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _compute_total_runs(success: int, warning: int, failed: int, missed: int, include_keys: set[str]) -> int:
|
||||||
|
total = 0
|
||||||
|
if "success_count" in include_keys:
|
||||||
|
total += int(success or 0)
|
||||||
|
if "warning_count" in include_keys:
|
||||||
|
total += int(warning or 0)
|
||||||
|
if "failed_count" in include_keys:
|
||||||
|
total += int(failed or 0)
|
||||||
|
if "missed_count" in include_keys:
|
||||||
|
total += int(missed or 0)
|
||||||
|
return int(total)
|
||||||
|
|
||||||
|
|
||||||
def _compute_success_rate(success: int, warning: int, failed: int, missed: int, include_keys: set[str]) -> float:
|
def _compute_success_rate(success: int, warning: int, failed: int, missed: int, include_keys: set[str]) -> float:
|
||||||
denom = 0
|
denom = 0
|
||||||
if "success_count" in include_keys:
|
if "success_count" in include_keys:
|
||||||
@ -859,7 +874,7 @@ def _build_report_stats_payload(report_id: int) -> dict:
|
|||||||
"""Compute summary and chart datasets for a generated report."""
|
"""Compute summary and chart datasets for a generated report."""
|
||||||
report = ReportDefinition.query.get_or_404(report_id)
|
report = ReportDefinition.query.get_or_404(report_id)
|
||||||
|
|
||||||
include_keys = _get_success_rate_keys_from_report(report)
|
include_keys = _get_success_rate_keys_from_report(report, view_key=view)
|
||||||
|
|
||||||
with db.engine.connect() as conn:
|
with db.engine.connect() as conn:
|
||||||
status_rows = conn.execute(
|
status_rows = conn.execute(
|
||||||
@ -973,15 +988,7 @@ def _build_report_stats_payload(report_id: int) -> dict:
|
|||||||
failed_count = int(pr.failed_count or 0)
|
failed_count = int(pr.failed_count or 0)
|
||||||
missed_count = int(pr.missed_count or 0)
|
missed_count = int(pr.missed_count or 0)
|
||||||
|
|
||||||
total_runs = 0
|
total_runs = _compute_total_runs(success_count, warning_count, failed_count, missed_count, include_keys)
|
||||||
if "success_count" in include_keys:
|
|
||||||
total_runs += success_count
|
|
||||||
if "warning_count" in include_keys:
|
|
||||||
total_runs += warning_count
|
|
||||||
if "failed_count" in include_keys:
|
|
||||||
total_runs += failed_count
|
|
||||||
if "missed_count" in include_keys:
|
|
||||||
total_runs += missed_count
|
|
||||||
|
|
||||||
totals["total_runs"] += total_runs
|
totals["total_runs"] += total_runs
|
||||||
totals["success_count"] += success_count
|
totals["success_count"] += success_count
|
||||||
@ -1062,7 +1069,7 @@ def _export_csv_response(report: ReportDefinition, report_id: int, view: str):
|
|||||||
if view not in ("summary", "snapshot", "jobs"):
|
if view not in ("summary", "snapshot", "jobs"):
|
||||||
view = "summary"
|
view = "summary"
|
||||||
|
|
||||||
include_keys = _get_success_rate_keys_from_report(report)
|
include_keys = _get_success_rate_keys_from_report(report, view_key=view)
|
||||||
|
|
||||||
with db.engine.connect() as conn:
|
with db.engine.connect() as conn:
|
||||||
if view == "summary":
|
if view == "summary":
|
||||||
@ -1097,11 +1104,11 @@ def _export_csv_response(report: ReportDefinition, report_id: int, view: str):
|
|||||||
"success_rate",
|
"success_rate",
|
||||||
])
|
])
|
||||||
for r in rows or []:
|
for r in rows or []:
|
||||||
total_runs = int(r.total_runs or 0)
|
|
||||||
success_count = int(r.success_count or 0)
|
success_count = int(r.success_count or 0)
|
||||||
warning_count = int(r.warning_count or 0)
|
warning_count = int(r.warning_count or 0)
|
||||||
failed_count = int(r.failed_count or 0)
|
failed_count = int(r.failed_count or 0)
|
||||||
missed_count = int(r.missed_count or 0)
|
missed_count = int(r.missed_count or 0)
|
||||||
|
total_runs = _compute_total_runs(success_count, warning_count, failed_count, missed_count, include_keys)
|
||||||
rate = _compute_success_rate(
|
rate = _compute_success_rate(
|
||||||
success=success_count,
|
success=success_count,
|
||||||
warning=warning_count,
|
warning=warning_count,
|
||||||
@ -1290,7 +1297,7 @@ def _export_html_response(report: ReportDefinition, report_id: int, view: str):
|
|||||||
include_keys_jobs = _get_success_rate_keys_from_report(report, view_key="jobs")
|
include_keys_jobs = _get_success_rate_keys_from_report(report, view_key="jobs")
|
||||||
|
|
||||||
jobs_selected_cols = _selected_cols("jobs")
|
jobs_selected_cols = _selected_cols("jobs")
|
||||||
jobs_sort_order = ["customer_name", "backup_software", "backup_type", "job_name", "object_name"]
|
jobs_sort_order = ["customer_name", "backup_software", "backup_type", "job_name"]
|
||||||
jobs_sort_fields = [k for k in jobs_sort_order if k in set(jobs_selected_cols or [])]
|
jobs_sort_fields = [k for k in jobs_sort_order if k in set(jobs_selected_cols or [])]
|
||||||
if not jobs_sort_fields:
|
if not jobs_sort_fields:
|
||||||
jobs_sort_fields = list(jobs_sort_order)
|
jobs_sort_fields = list(jobs_sort_order)
|
||||||
|
|||||||
@ -257,6 +257,14 @@
|
|||||||
- Fixed **Jobs table column headers** so the correct labels are displayed instead of placeholder keys (e.g. `{jobs_th}`).
|
- Fixed **Jobs table column headers** so the correct labels are displayed instead of placeholder keys (e.g. `{jobs_th}`).
|
||||||
- Improved **Jobs table sorting** to follow a logical hierarchy: Customer > Backup software > Backup type > Job name > Object, depending on the selected columns.
|
- Improved **Jobs table sorting** to follow a logical hierarchy: Customer > Backup software > Backup type > Job name > Object, depending on the selected columns.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v20260104-09-reports-html-total-runs-selection-and-jobs-text-column-remove
|
||||||
|
|
||||||
|
- Fixed “Total runs” to only sum the selected status counters (e.g. excluding missed when it’s not selected), instead of using the raw total that included missed runs.
|
||||||
|
- Removed the duplicate “Text” column from the Jobs report view by excluding `object_name` from the Jobs column set and Jobs defaults.
|
||||||
|
|
||||||
|
|
||||||
================================================================================================================================================
|
================================================================================================================================================
|
||||||
|
|
||||||
## v0.1.15
|
## v0.1.15
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user