Compare commits

...

2 Commits

6 changed files with 58 additions and 23 deletions

View File

@ -1 +1 @@
v20260103-10-reports-summary-columns-metadata
v20260103-11-reports-view-raw-columns-fix

View File

@ -180,24 +180,10 @@ def api_reports_create():
return {"id": r.id}
@main_bp.route("/api/reports/columns", methods=["GET"])
@login_required
def api_reports_columns():
"""Return column metadata used by the Reports UI.
The UI uses this endpoint for:
- grouped column selectors in the "New report" wizard
- translating column keys into human-readable labels
- sensible default columns per view
Note: Column keys map to fields returned by:
- /api/reports/<id>/data?view=summary
- /api/reports/<id>/data?view=snapshot
"""
err = _require_reporting_role()
if err is not None:
return err
def build_report_columns_meta():
"""Build the column metadata payload for reporting UIs."""
# Keep the payload stable so report_config can safely store selected keys.
return {
"views": [
@ -312,6 +298,28 @@ def api_reports_columns():
},
],
}
@main_bp.route("/api/reports/columns", methods=["GET"])
@login_required
def api_reports_columns():
"""Return column metadata used by the Reports UI.
The UI uses this endpoint for:
- grouped column selectors in the "New report" wizard
- translating column keys into human-readable labels
- sensible default columns per view
Note: Column keys map to fields returned by:
- /api/reports/<id>/data?view=summary
- /api/reports/<id>/data?view=snapshot
"""
err = _require_reporting_role()
if err is not None:
return err
# Keep the payload stable so report_config can safely store selected keys.
return build_report_columns_meta()
@main_bp.route("/api/reports/<int:report_id>", methods=["DELETE"])

View File

@ -1,5 +1,6 @@
from .routes_shared import * # noqa: F401,F403
from datetime import date, timedelta
from .routes_reporting_api import build_report_columns_meta
def get_default_report_period():
"""Return default report period (last 7 days)."""
@ -53,6 +54,7 @@ def reports():
return render_template(
"main/reports.html",
initial_reports=items,
columns_meta=build_report_columns_meta(),
default_period_start=period_start.isoformat(),
default_period_end=period_end.isoformat(),
)
@ -70,4 +72,4 @@ 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)
return render_template("main/reports_new.html", initial_customers=customer_items, columns_meta=build_report_columns_meta())

View File

@ -163,6 +163,7 @@
</div>
<script>
window.__reportColumnsMeta = {{ columns_meta|tojson }};
window.addEventListener('DOMContentLoaded', function () {
var rawModalEl = document.getElementById('rep_raw_modal');
var rawModal = window.bootstrap ? new bootstrap.Modal(rawModalEl) : null;
@ -175,10 +176,11 @@
var canDeleteReports = {{ 'true' if active_role in ('admin','operator','reporter') else 'false' }};
var reportsItems = [];
var reportColumnsMeta = null;
var reportColumnsMeta = window.__reportColumnsMeta || null;
var rawReportConfig = null;
function loadReportColumnsMeta() {
if (reportColumnsMeta) return Promise.resolve();
return fetch('/api/reports/columns', { credentials: 'same-origin' })
.then(function (r) { return r.json(); })
.then(function (j) { reportColumnsMeta = j || null; })
@ -283,7 +285,7 @@
if (!items || !items.length) {
tbody.innerHTML = '<tr><td colspan="' + String(cols.length || 1) + '" class="text-center text-muted py-4">No rows found.</td></tr>';
updateDownloadLink();
setRawDownloadLink();
return;
}
@ -302,7 +304,7 @@
);
}).join('');
updateDownloadLink();
setRawDownloadLink();
}
function loadRawData() {

View File

@ -197,6 +197,7 @@
</div>
<script>
window.__reportColumnsMeta = {{ columns_meta|tojson }};
window.addEventListener('DOMContentLoaded', function () {
function qs(id) { return document.getElementById(id); }
@ -216,7 +217,7 @@
// --- Report content / column selector ---
var repColsView = 'summary';
var repColsMeta = null;
var repColsMeta = window.__reportColumnsMeta || null;
var repColsSelected = { summary: [], snapshot: [] };
function colsHintText(viewKey) {
@ -434,6 +435,17 @@
var area = document.getElementById('rep_cols_available');
if (!area) return;
if (repColsMeta) {
showColsLoading(false);
clearColsError();
ensureDefaultsFromMeta();
qs('rep_cols_tab_summary').addEventListener('click', function () { setColsView('summary'); });
qs('rep_cols_tab_snapshot').addEventListener('click', function () { setColsView('snapshot'); });
setColsView('summary');
return;
}
showColsLoading(true);
clearColsError();
@ -654,4 +666,4 @@
});
</script>
{% endblock %}
{% endblock %}

View File

@ -90,6 +90,17 @@
- Corrected the **Missed** column mapping to use `missed_count` for Summary views instead of snapshot-specific fields.
- Ensured column metadata is consistent between backend and frontend to allow future graphical output.
---
## v20260103-11-reports-view-raw-columns-fix
### Changed
- Fixed the **View raw** action in Reports by correcting a broken JavaScript function call that prevented raw data from loading.
- Extended the Reports backend to always include column metadata (`columns_meta`) in the response.
- Updated the Reports UI to use embedded column metadata as a fallback, ensuring column selection is available even when an API fetch fails.
- Improved column metadata loading logic to only fetch metadata when it is not already present in the report payload.
================================================================================================================================================
## v0.1.15