From 2710a140adea5bc0ec22a0ed06fa0ac59c6a4cbe Mon Sep 17 00:00:00 2001 From: Ivo Oskamp Date: Sat, 3 Jan 2026 18:22:48 +0100 Subject: [PATCH] Auto-commit local changes before build (2026-01-03 18:22:48) --- .last-branch | 2 +- .../src/backend/app/main/routes_reports.py | 46 +++++++- .../src/templates/main/reports.html | 28 ++++- .../src/templates/main/reports_new.html | 106 +++++++++++++++--- docs/changelog.md | 9 ++ 5 files changed, 173 insertions(+), 18 deletions(-) diff --git a/.last-branch b/.last-branch index 92ab6e6..7f55fc8 100644 --- a/.last-branch +++ b/.last-branch @@ -1 +1 @@ -v20260103-12-reports-columns-selector-init-fix +v20260103-13-reports-edit-and-view-raw-fix diff --git a/containers/backupchecks/src/backend/app/main/routes_reports.py b/containers/backupchecks/src/backend/app/main/routes_reports.py index 5b29dc6..f05d0ca 100644 --- a/containers/backupchecks/src/backend/app/main/routes_reports.py +++ b/containers/backupchecks/src/backend/app/main/routes_reports.py @@ -21,6 +21,17 @@ def _safe_json_list(value): return [] +def _safe_json_dict(value): + if not value: + return {} + if isinstance(value, dict): + return value + try: + return json.loads(value) + except Exception: + return {} + + def _build_report_item(r): return { "id": int(r.id), @@ -33,6 +44,7 @@ def _build_report_item(r): "period_start": r.period_start.isoformat() if getattr(r, "period_start", None) else "", "period_end": r.period_end.isoformat() if getattr(r, "period_end", None) else "", "schedule": r.schedule or "", + "report_config": _safe_json_dict(getattr(r, "report_config", None)), "created_at": r.created_at.isoformat() if getattr(r, "created_at", None) else "", } @@ -72,4 +84,36 @@ def reports_new(): ) customer_items = [{"id": int(c.id), "name": c.name or ""} for c in customers] - return render_template("main/reports_new.html", initial_customers=customer_items, columns_meta=build_report_columns_meta()) + return render_template( + "main/reports_new.html", + initial_customers=customer_items, + columns_meta=build_report_columns_meta(), + is_edit=False, + initial_report=None, + ) + + +@main_bp.route("/reports//edit") +@login_required +def reports_edit(report_id: int): + # Editing reports is limited to the same roles that can create them. + if get_active_role() not in ("admin", "operator", "reporter"): + return abort(403) + + r = ReportDefinition.query.get_or_404(report_id) + + customers = ( + db.session.query(Customer) + .filter(Customer.active.is_(True)) + .order_by(Customer.name.asc()) + .all() + ) + customer_items = [{"id": int(c.id), "name": c.name or ""} for c in customers] + + return render_template( + "main/reports_new.html", + initial_customers=customer_items, + columns_meta=build_report_columns_meta(), + is_edit=True, + initial_report=_build_report_item(r), + ) diff --git a/containers/backupchecks/src/templates/main/reports.html b/containers/backupchecks/src/templates/main/reports.html index ddc0fc0..95f42fe 100644 --- a/containers/backupchecks/src/templates/main/reports.html +++ b/containers/backupchecks/src/templates/main/reports.html @@ -40,7 +40,7 @@ {% for item in initial_reports %} {{ item.name }}
{{ item.description }}
- {{ item.created_at.replace('T',' ') if item.created_at else '' }} + {{ item.report_type }} {% if item.period_start or item.period_end %} {{ item.period_start.replace('T',' ') if item.period_start else '' }} → {{ item.period_end.replace('T',' ') if item.period_end else '' }} @@ -50,6 +50,7 @@ {{ item.output_format }} + Edit Download @@ -64,7 +65,7 @@ No reports found. {% endif %} - > + @@ -271,6 +272,28 @@ } } + function setRawDownloadLink() { + var btn = qs('rep_raw_download_btn'); + if (!btn) return; + if (!rawReportId) { + btn.setAttribute('href', '#'); + btn.classList.add('disabled'); + return; + } + btn.classList.remove('disabled'); + btn.setAttribute('href', '/api/reports/' + rawReportId + '/export.csv?view=' + rawView); + } + + function updateRawMeta(total) { + var t = parseInt(total || 0, 10) || 0; + var start = t ? (rawOffset + 1) : 0; + var end = t ? Math.min(rawOffset + rawLimit, t) : 0; + var label = (rawView === 'snapshot') ? 'Snapshot' : 'Summary'; + qs('rep_raw_meta').textContent = label + ' · Rows ' + start + '-' + end + ' of ' + t; + qs('rep_raw_prev_btn').disabled = (rawOffset <= 0); + qs('rep_raw_next_btn').disabled = ((rawOffset + rawLimit) >= t); + } + function renderRawTable(view, items) { var thead = qs('rep_raw_thead'); var tbody = qs('rep_raw_tbody'); @@ -368,6 +391,7 @@ function loadRawData() { '' + period + '' + '' + fmt + '' + '' + + 'Edit' + '' + '' + 'Download' + diff --git a/containers/backupchecks/src/templates/main/reports_new.html b/containers/backupchecks/src/templates/main/reports_new.html index 66486db..c622191 100644 --- a/containers/backupchecks/src/templates/main/reports_new.html +++ b/containers/backupchecks/src/templates/main/reports_new.html @@ -3,8 +3,8 @@
-

New report

-
Create a one-time report definition. Generate output from the Reports overview.
+

{{ 'Edit report' if is_edit else 'New report' }}

+
{{ 'Update this report definition. Generate output from the Reports overview.' if is_edit else 'Create a one-time report definition. Generate output from the Reports overview.' }}
Back @@ -157,7 +157,7 @@
- + Cancel
@@ -199,6 +199,8 @@