Auto-commit local changes before build (2026-01-04 16:50:41)
This commit is contained in:
parent
17d0398fb7
commit
f680e799b2
@ -1 +1 @@
|
|||||||
v20260104-11-reports-jobs-remove-text-column-option
|
v20260104-12-reports-object-name-job-name-columns-fix
|
||||||
|
|||||||
@ -262,6 +262,10 @@ def build_report_columns_meta():
|
|||||||
{
|
{
|
||||||
"name": "Job Information",
|
"name": "Job Information",
|
||||||
"items": [
|
"items": [
|
||||||
|
# NOTE: object_name is currently populated with the job name in the reporting snapshot
|
||||||
|
# generator. Keep the key stable (report_config stores keys) but present it as "Job name"
|
||||||
|
# so it can be toggled like other columns.
|
||||||
|
{"key": "object_name", "label": "Job name", "views": ["summary", "snapshot", "jobs"]},
|
||||||
{"key": "job_name", "label": "Job name", "views": ["snapshot", "jobs"]},
|
{"key": "job_name", "label": "Job name", "views": ["snapshot", "jobs"]},
|
||||||
{"key": "job_id", "label": "Job ID", "views": ["snapshot"]},
|
{"key": "job_id", "label": "Job ID", "views": ["snapshot"]},
|
||||||
{"key": "backup_software", "label": "Software", "views": ["snapshot", "jobs"]},
|
{"key": "backup_software", "label": "Software", "views": ["snapshot", "jobs"]},
|
||||||
@ -1239,23 +1243,34 @@ def _export_html_response(report: ReportDefinition, report_id: int, view: str):
|
|||||||
allowed_by_view.setdefault(v, set()).add(k)
|
allowed_by_view.setdefault(v, set()).add(k)
|
||||||
|
|
||||||
def _selected_cols(view_key: str) -> list[str]:
|
def _selected_cols(view_key: str) -> list[str]:
|
||||||
cols = []
|
# Only apply defaults when the report config does not define a list for this view.
|
||||||
|
# If a list is present but empty, the user intentionally selected no columns.
|
||||||
|
user_provided = False
|
||||||
|
cols: list[str] | None = None
|
||||||
|
|
||||||
rc_cols = rc.get("columns") if isinstance(rc, dict) else None
|
rc_cols = rc.get("columns") if isinstance(rc, dict) else None
|
||||||
if isinstance(rc_cols, dict):
|
if isinstance(rc_cols, dict) and view_key in rc_cols:
|
||||||
v = rc_cols.get(view_key)
|
v = rc_cols.get(view_key)
|
||||||
if isinstance(v, list):
|
if isinstance(v, list):
|
||||||
|
user_provided = True
|
||||||
cols = [str(x).strip() for x in v if str(x).strip()]
|
cols = [str(x).strip() for x in v if str(x).strip()]
|
||||||
|
|
||||||
if not cols:
|
if cols is None:
|
||||||
d = (cols_meta.get("defaults") or {}).get(view_key)
|
d = (cols_meta.get("defaults") or {}).get(view_key)
|
||||||
if isinstance(d, list):
|
if isinstance(d, list):
|
||||||
cols = [str(x).strip() for x in d if str(x).strip()]
|
cols = [str(x).strip() for x in d if str(x).strip()]
|
||||||
|
else:
|
||||||
|
cols = []
|
||||||
|
|
||||||
allowed = allowed_by_view.get(view_key) or set()
|
allowed = allowed_by_view.get(view_key) or set()
|
||||||
cols = [c for c in cols if c in allowed]
|
filtered = [c for c in cols if c in allowed]
|
||||||
if not cols:
|
|
||||||
cols = [c for c in (cols_meta.get("defaults") or {}).get(view_key, []) if c in allowed]
|
# If the user provided keys but all were invalid/out-of-scope, fall back to defaults.
|
||||||
return cols
|
if user_provided and cols and not filtered:
|
||||||
|
filtered = [c for c in (cols_meta.get("defaults") or {}).get(view_key, []) if c in allowed]
|
||||||
|
|
||||||
|
# If the user explicitly selected none, keep it empty.
|
||||||
|
return filtered
|
||||||
|
|
||||||
def _td(value: str, cls: str = "") -> str:
|
def _td(value: str, cls: str = "") -> str:
|
||||||
cl = f" class='{cls}'" if cls else ""
|
cl = f" class='{cls}'" if cls else ""
|
||||||
@ -1268,6 +1283,10 @@ def _export_html_response(report: ReportDefinition, report_id: int, view: str):
|
|||||||
def _render_table(view_key: str, rows: list[dict]) -> tuple[str, str]:
|
def _render_table(view_key: str, rows: list[dict]) -> tuple[str, str]:
|
||||||
cols = _selected_cols(view_key)
|
cols = _selected_cols(view_key)
|
||||||
|
|
||||||
|
if not cols:
|
||||||
|
# Keep the HTML valid and explicit when the user deselects all columns.
|
||||||
|
return _th("No columns selected", "text-muted"), "<tr><td class='text-muted'>No columns selected.</td></tr>"
|
||||||
|
|
||||||
th = []
|
th = []
|
||||||
for k in cols:
|
for k in cols:
|
||||||
cls = "text-end" if k in ("missed", "override_applied") else ""
|
cls = "text-end" if k in ("missed", "override_applied") else ""
|
||||||
|
|||||||
@ -210,7 +210,16 @@
|
|||||||
|
|
||||||
function selectedColsFor(view) {
|
function selectedColsFor(view) {
|
||||||
var cfg = rawReportConfig || {};
|
var cfg = rawReportConfig || {};
|
||||||
var cols = (cfg.columns && cfg.columns[view]) ? cfg.columns[view] : null;
|
var cols = null;
|
||||||
|
var hasView = false;
|
||||||
|
if (cfg.columns && typeof cfg.columns === 'object') {
|
||||||
|
hasView = Object.prototype.hasOwnProperty.call(cfg.columns, view);
|
||||||
|
cols = cfg.columns[view];
|
||||||
|
}
|
||||||
|
if (hasView && Array.isArray(cols)) {
|
||||||
|
// If an empty list is saved, keep it empty.
|
||||||
|
return cols;
|
||||||
|
}
|
||||||
if (cols && cols.length) return cols;
|
if (cols && cols.length) return cols;
|
||||||
return defaultColsFor(view);
|
return defaultColsFor(view);
|
||||||
}
|
}
|
||||||
@ -300,6 +309,13 @@
|
|||||||
|
|
||||||
var cols = selectedColsFor(view);
|
var cols = selectedColsFor(view);
|
||||||
|
|
||||||
|
if (!cols || !cols.length) {
|
||||||
|
thead.innerHTML = '<tr><th class="text-muted">No columns selected</th></tr>';
|
||||||
|
tbody.innerHTML = '<tr><td class="text-muted py-4">No columns selected.</td></tr>';
|
||||||
|
setRawDownloadLink();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function thRow(keys) {
|
function thRow(keys) {
|
||||||
return '<tr>' + keys.map(function (k) { return '<th>' + escapeHtml(colLabel(k)) + '</th>'; }).join('') + '</tr>';
|
return '<tr>' + keys.map(function (k) { return '<th>' + escapeHtml(colLabel(k)) + '</th>'; }).join('') + '</tr>';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -275,14 +275,16 @@
|
|||||||
// --- Report content / column selector ---
|
// --- Report content / column selector ---
|
||||||
var repColsView = 'summary';
|
var repColsView = 'summary';
|
||||||
var repColsMeta = window.__reportColumnsMeta || null;
|
var repColsMeta = window.__reportColumnsMeta || null;
|
||||||
var repColsSelected = { summary: [], snapshot: [], jobs: [] };
|
// Use null to indicate "no value configured" so defaults can be applied.
|
||||||
|
// If the user explicitly saves an empty list, keep it empty.
|
||||||
|
var repColsSelected = { summary: null, snapshot: null, jobs: null };
|
||||||
|
|
||||||
if (isEdit && initialReport && initialReport.report_config && initialReport.report_config.columns) {
|
if (isEdit && initialReport && initialReport.report_config && initialReport.report_config.columns) {
|
||||||
var cols = initialReport.report_config.columns;
|
var cols = initialReport.report_config.columns;
|
||||||
repColsSelected = {
|
repColsSelected = {
|
||||||
summary: Array.isArray(cols.summary) ? cols.summary.slice() : [],
|
summary: (cols && Object.prototype.hasOwnProperty.call(cols, 'summary') && Array.isArray(cols.summary)) ? cols.summary.slice() : null,
|
||||||
snapshot: Array.isArray(cols.snapshot) ? cols.snapshot.slice() : [],
|
snapshot: (cols && Object.prototype.hasOwnProperty.call(cols, 'snapshot') && Array.isArray(cols.snapshot)) ? cols.snapshot.slice() : null,
|
||||||
jobs: Array.isArray(cols.jobs) ? cols.jobs.slice() : [],
|
jobs: (cols && Object.prototype.hasOwnProperty.call(cols, 'jobs') && Array.isArray(cols.jobs)) ? cols.jobs.slice() : null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,7 +437,7 @@
|
|||||||
function ensureDefaultsFromMeta() {
|
function ensureDefaultsFromMeta() {
|
||||||
if (!repColsMeta || !repColsMeta.defaults) return;
|
if (!repColsMeta || !repColsMeta.defaults) return;
|
||||||
['summary', 'snapshot', 'jobs'].forEach(function (v) {
|
['summary', 'snapshot', 'jobs'].forEach(function (v) {
|
||||||
if (!repColsSelected[v] || !repColsSelected[v].length) {
|
if (repColsSelected[v] === null || typeof repColsSelected[v] === 'undefined') {
|
||||||
repColsSelected[v] = (repColsMeta.defaults[v] || []).slice();
|
repColsSelected[v] = (repColsMeta.defaults[v] || []).slice();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -281,6 +281,14 @@
|
|||||||
- Cleaned up column metadata so the “Text” option no longer appears in the Reports UI.
|
- Cleaned up column metadata so the “Text” option no longer appears in the Reports UI.
|
||||||
- Ensured consistency between selectable columns and rendered report output.
|
- Ensured consistency between selectable columns and rendered report output.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v20260104-12-reports-object-name-job-name-columns-fix
|
||||||
|
|
||||||
|
- Added the missing `object_name` column to the available report columns and labeled it as "Job name" for Summary/Snapshot/Jobs.
|
||||||
|
- Fixed column selection behavior so an explicitly saved empty selection stays empty (defaults are only applied when the view has no configured selection).
|
||||||
|
- Updated the raw data table and HTML export to show a clear “No columns selected” message when all columns are disabled, instead of still rendering default data.
|
||||||
|
|
||||||
================================================================================================================================================
|
================================================================================================================================================
|
||||||
|
|
||||||
## v0.1.15
|
## v0.1.15
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user