Compare commits

..

No commits in common. "6944755dd992d6e885bb456c50d08198e4bdab70" and "5100093be4776ea6a778f4579e9d31b1c784f8a2" have entirely different histories.

6 changed files with 23 additions and 58 deletions

View File

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

View File

@ -180,10 +180,24 @@ def api_reports_create():
return {"id": r.id} 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. # Keep the payload stable so report_config can safely store selected keys.
return { return {
"views": [ "views": [
@ -298,28 +312,6 @@ def build_report_columns_meta():
}, },
], ],
} }
@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"]) @main_bp.route("/api/reports/<int:report_id>", methods=["DELETE"])

View File

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

View File

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

View File

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

View File

@ -90,17 +90,6 @@
- Corrected the **Missed** column mapping to use `missed_count` for Summary views instead of snapshot-specific fields. - 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. - 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 ## v0.1.15