diff --git a/.last-branch b/.last-branch index d5e3c52..8c90e92 100644 --- a/.last-branch +++ b/.last-branch @@ -1 +1 @@ -v20260109-01-veeam-m365-overall-message +v20260109-02-object-list-sorting diff --git a/containers/backupchecks/src/templates/main/admin_all_mail.html b/containers/backupchecks/src/templates/main/admin_all_mail.html index 9fd5c33..5c76e0b 100644 --- a/containers/backupchecks/src/templates/main/admin_all_mail.html +++ b/containers/backupchecks/src/templates/main/admin_all_mail.html @@ -235,6 +235,33 @@ if (el) el.textContent = value || ''; } + function objectSeverityRank(o) { + var st = String((o && o.status) || '').trim().toLowerCase(); + var err = String((o && o.error_message) || '').trim(); + if (st === 'error' || st === 'failed' || st === 'failure' || err) return 0; + if (st === 'warning') return 1; + return 2; + } + + function sortObjects(objects) { + return (objects || []).slice().sort(function (a, b) { + var ra = objectSeverityRank(a); + var rb = objectSeverityRank(b); + if (ra !== rb) return ra - rb; + + var na = String((a && a.name) || '').toLowerCase(); + var nb = String((b && b.name) || '').toLowerCase(); + if (na < nb) return -1; + if (na > nb) return 1; + + var ta = String((a && a.type) || '').toLowerCase(); + var tb = String((b && b.type) || '').toLowerCase(); + if (ta < tb) return -1; + if (ta > tb) return 1; + return 0; + }); + } + function renderObjects(objects) { var container = document.getElementById('msg_objects_container'); if (!container) return; @@ -248,8 +275,10 @@ var tableHtml = '
' + ''; - for (var i = 0; i < objects.length; i++) { - var o = objects[i] || {}; + var sorted = sortObjects(objects); + + for (var i = 0; i < sorted.length; i++) { + var o = sorted[i] || {}; tableHtml += '' + '' + '' + diff --git a/containers/backupchecks/src/templates/main/daily_jobs.html b/containers/backupchecks/src/templates/main/daily_jobs.html index 4fc11a1..bc6783d 100644 --- a/containers/backupchecks/src/templates/main/daily_jobs.html +++ b/containers/backupchecks/src/templates/main/daily_jobs.html @@ -293,6 +293,33 @@ return ""; } + function objectSeverityRank(o) { + var st = String((o && o.status) || '').trim().toLowerCase(); + var err = String((o && o.error_message) || '').trim(); + if (st === 'error' || st === 'failed' || st === 'failure' || err) return 0; + if (st === 'warning') return 1; + return 2; + } + + function sortObjects(objects) { + return (objects || []).slice().sort(function (a, b) { + var ra = objectSeverityRank(a); + var rb = objectSeverityRank(b); + if (ra !== rb) return ra - rb; + + var na = String((a && a.name) || '').toLowerCase(); + var nb = String((b && b.name) || '').toLowerCase(); + if (na < nb) return -1; + if (na > nb) return 1; + + var ta = String((a && a.type) || '').toLowerCase(); + var tb = String((b && b.type) || '').toLowerCase(); + if (ta < tb) return -1; + if (ta > tb) return 1; + return 0; + }); + } + function wrapMailHtml(html) { @@ -606,7 +633,7 @@ if (tStatus) tStatus.textContent = ''; var tbody = document.querySelector("#dj_objects_table tbody"); tbody.innerHTML = ""; - (run.objects || []).forEach(function (obj) { + sortObjects(run.objects || []).forEach(function (obj) { var tr = document.createElement("tr"); var tdName = document.createElement("td"); diff --git a/containers/backupchecks/src/templates/main/inbox.html b/containers/backupchecks/src/templates/main/inbox.html index 4dc82b5..328ef18 100644 --- a/containers/backupchecks/src/templates/main/inbox.html +++ b/containers/backupchecks/src/templates/main/inbox.html @@ -369,10 +369,39 @@ function findCustomerIdByName(name) { return; } + function objectSeverityRank(o) { + var st = String((o && o.status) || "").trim().toLowerCase(); + var err = String((o && o.error_message) || "").trim(); + if (st === "error" || st === "failed" || st === "failure" || err) return 0; + if (st === "warning") return 1; + return 2; + } + + function sortObjects(list) { + return (list || []).slice().sort(function (a, b) { + var ra = objectSeverityRank(a); + var rb = objectSeverityRank(b); + if (ra !== rb) return ra - rb; + + var na = String((a && a.name) || "").toLowerCase(); + var nb = String((b && b.name) || "").toLowerCase(); + if (na < nb) return -1; + if (na > nb) return 1; + + var ta = String((a && a.type) || "").toLowerCase(); + var tb = String((b && b.type) || "").toLowerCase(); + if (ta < tb) return -1; + if (ta > tb) return 1; + return 0; + }); + } + + var sorted = sortObjects(objects); + var html = "
NameTypeStatusError
' + (o.name || '') + '' + (o.type || '') + '
"; html += ""; - for (var i = 0; i < objects.length; i++) { - var o = objects[i] || {}; + for (var i = 0; i < sorted.length; i++) { + var o = sorted[i] || {}; html += ""; html += ""; html += ""; diff --git a/containers/backupchecks/src/templates/main/job_detail.html b/containers/backupchecks/src/templates/main/job_detail.html index 11913af..8495532 100644 --- a/containers/backupchecks/src/templates/main/job_detail.html +++ b/containers/backupchecks/src/templates/main/job_detail.html @@ -497,18 +497,29 @@ return; } - // Sort: objects with an error_message first (alphabetically by name), then the rest (also by name). - var sorted = (objects || []).slice().sort(function (a, b) { - a = a || {}; - b = b || {}; - var aHasErr = !!(a.error_message && a.error_message.toString().trim()); - var bHasErr = !!(b.error_message && b.error_message.toString().trim()); - if (aHasErr !== bHasErr) return aHasErr ? -1 : 1; + function objectSeverityRank(o) { + var st = String((o && o.status) || "").trim().toLowerCase(); + var err = String((o && o.error_message) || "").trim(); + if (st === "error" || st === "failed" || st === "failure" || err) return 0; + if (st === "warning") return 1; + return 2; + } - var an = (a.name || "").toString().toLowerCase(); - var bn = (b.name || "").toString().toLowerCase(); + // Sort: errors first, then warnings, then the rest; within each group sort alphabetically. + var sorted = (objects || []).slice().sort(function (a, b) { + var ra = objectSeverityRank(a); + var rb = objectSeverityRank(b); + if (ra !== rb) return ra - rb; + + var an = String((a && a.name) || "").toLowerCase(); + var bn = String((b && b.name) || "").toLowerCase(); if (an < bn) return -1; if (an > bn) return 1; + + var at = String((a && a.type) || "").toLowerCase(); + var bt = String((b && b.type) || "").toLowerCase(); + if (at < bt) return -1; + if (at > bt) return 1; return 0; }); diff --git a/containers/backupchecks/src/templates/main/run_checks.html b/containers/backupchecks/src/templates/main/run_checks.html index 597f464..72981ef 100644 --- a/containers/backupchecks/src/templates/main/run_checks.html +++ b/containers/backupchecks/src/templates/main/run_checks.html @@ -324,6 +324,33 @@ function statusClass(status) { return ""; } + function objectSeverityRank(o) { + var st = String((o && o.status) || '').trim().toLowerCase(); + var err = String((o && o.error_message) || '').trim(); + if (st === 'error' || st === 'failed' || st === 'failure' || err) return 0; + if (st === 'warning') return 1; + return 2; + } + + function sortObjects(objects) { + return (objects || []).slice().sort(function (a, b) { + var ra = objectSeverityRank(a); + var rb = objectSeverityRank(b); + if (ra !== rb) return ra - rb; + + var na = String((a && a.name) || '').toLowerCase(); + var nb = String((b && b.name) || '').toLowerCase(); + if (na < nb) return -1; + if (na > nb) return 1; + + var ta = String((a && a.type) || '').toLowerCase(); + var tb = String((b && b.type) || '').toLowerCase(); + if (ta < tb) return -1; + if (ta > tb) return 1; + return 0; + }); + } + function wrapMailHtml(html) { html = html || ""; return ( @@ -940,7 +967,7 @@ if (tStatus) tStatus.textContent = ''; var tbody = document.querySelector('#rcm_objects_table tbody'); if (tbody) { tbody.innerHTML = ''; - (run.objects || []).forEach(function (obj) { + sortObjects(run.objects || []).forEach(function (obj) { var tr = document.createElement('tr'); var tdName = document.createElement('td'); diff --git a/docs/changelog.md b/docs/changelog.md index b9e897a..27e37ad 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -4,6 +4,17 @@ - Improved extraction of the overall details message from the mail content, ensuring permission and role warnings are correctly captured. - Ensured the extracted overall message is consistently available in job details, run checks, and reporting views. +--- + +## v20260109-02-object-list-sorting + +- Updated object list sorting logic to improve readability and prioritization. +- Objects are now grouped by severity in the following order: + 1. Errors + 2. Warnings + 3. All other statuses +- Within each severity group, objects are sorted alphabetically (A–Z). +- Applied consistent sorting across all relevant views, including Inbox, Job Details, Run Checks, Daily Jobs, and Admin All Mail. ================================================================================================================================================ ## v0.1.19
ObjectTypeStatusError
" + (o.name || "") + "" + (o.type || "") + "