From d47cf43e56640acb309e2efdf9b2d599da1f583f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hern=C3=A2ni=20Marques?= Date: Sun, 19 Jul 2026 04:13:26 +0200 Subject: [PATCH] release 1.13.11: warn/error filter keeps dimmed context lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When filtering by warnings or errors, show ±3 neighbouring log lines grayed out so phase/group context remains visible; dashed gaps between non-contiguous clusters. --- VERSION | 2 +- VERSIONS.md | 1 + site-gen/console_to_html.py | 115 +++++++++++++++++++++++++++++++----- 3 files changed, 102 insertions(+), 16 deletions(-) diff --git a/VERSION b/VERSION index f3352b3..66fae2a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.13.10 +1.13.11 diff --git a/VERSIONS.md b/VERSIONS.md index 75b337c..893099a 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -17,6 +17,7 @@ Git tags: `vMAJOR.FEATURE.FIX` (e.g. `v1.8.0`). File `VERSION` omits the `v` pre | Tag | Date (UTC) | Notes | |-----|------------|--------| +| **v1.13.11** | 2026-07-19 | **Bugfix:** sticky error/warn filter keeps **±3 dimmed context lines** around each match (gray/grayscale) so phase/group context stays readable; dashed gap between distant clusters. | | **v1.13.10** | 2026-07-19 | **Bugfix:** multi-phase runs print **one global SUMMARY** at parent end (aggregated OK/ERROR/WARN/INFO/BLOCK via `TALER_MON_STATE`); no phase SUMMARY at all (not even last phase); mid-phase still lists ERRORS/BLOCKERS; solo `check_*.sh` unchanged. | | **v1.13.9** | 2026-07-19 | **Bugfix:** no mid-run SUMMARY / progress standings between phases (no more 34/52 + SUMMARY after urls while monpages still runs); full stand only on last phase or solo check script; `progress_finish` remains. | | **v1.13.8** | 2026-07-19 | **Bugfix:** monpages **TOP** meta/marker failures (missing generated/version-link/taler-mon-page, empty race body) are **WARN only** — no longer self-red the run; optional `MONPAGES_TOP_STRICT=1` restores ERROR. | diff --git a/site-gen/console_to_html.py b/site-gen/console_to_html.py index bb574ba..bf4d312 100755 --- a/site-gen/console_to_html.py +++ b/site-gen/console_to_html.py @@ -67,11 +67,11 @@ def ui(lang: str, key: str, **kwargs) -> str: "warn_many": "{n} warnings", "jump_first_error": "Jump to first error", "jump_first_warn": "Jump to first warning", - "filter_errors": "Filter: show all errors (hide other log lines)", - "filter_warns": "Filter: show all warnings (hide other log lines)", + "filter_errors": "Filter: errors + a few dimmed context lines", + "filter_warns": "Filter: warnings + a few dimmed context lines", "filter_clear": "Clear filter · show all lines", - "filter_active_err": "Filter: errors only", - "filter_active_warn": "Filter: warnings only", + "filter_active_err": "Filter: errors + context", + "filter_active_warn": "Filter: warnings + context", "filter_show_all": "Show all", "env_context": "Monitoring env context", "env_context_title": "Expand: agent env, suite pin, domain hosts & flags (from run header)", @@ -141,7 +141,7 @@ def ui(lang: str, key: str, **kwargs) -> str: "mail_i1": "Outside-in phase mail: MX, SMTP/IMAP ports and handshakes, SPF/DMARC", "mail_i2": "Mail hosts: firefly.gnunet.org (taler.net/gnunet.org) and anastasis.taler-systems.com", "mail_i3": "Reported on taler-monitoring-surface HTML (no separate /taler-monitoring-mail* page)", - "footer": "Console-style render of taler-monitoring output. Sticky bar: green = clean · yellow = warnings · red = errors. Click error/warning counts to filter the log. Monitoring env context (agent header) is collapsed by default. Commit pins the exact tree used for this run.", + "footer": "Console-style render of taler-monitoring output. Sticky bar: green = clean · yellow = warnings · red = errors. Click error/warning counts to filter the log (match lines plus a few dimmed neighbours for context). Monitoring env context (agent header) is collapsed by default. Commit pins the exact tree used for this run.", "redirect_fail": "has failures.", "redirect_see": "See {link} for the full console log, error index, and sticky status bar.", "ago_s": "{n}s ago", @@ -160,11 +160,11 @@ def ui(lang: str, key: str, **kwargs) -> str: "warn_many": "{n} avertissements", "jump_first_error": "Aller à la première erreur", "jump_first_warn": "Aller au premier avertissement", - "filter_errors": "Filtrer : toutes les erreurs (masquer le reste du journal)", - "filter_warns": "Filtrer : tous les avertissements (masquer le reste du journal)", + "filter_errors": "Filtrer : erreurs + quelques lignes de contexte grisées", + "filter_warns": "Filtrer : avertissements + quelques lignes de contexte grisées", "filter_clear": "Effacer le filtre · tout afficher", - "filter_active_err": "Filtre : erreurs seulement", - "filter_active_warn": "Filtre : avertissements seulement", + "filter_active_err": "Filtre : erreurs + contexte", + "filter_active_warn": "Filtre : avertissements + contexte", "filter_show_all": "Tout afficher", "env_context": "Contexte d'env. de monitoring", "env_context_title": "Déplier : env agent, pin de suite, hôtes domaine et flags (en-tête d'exécution)", @@ -1121,9 +1121,35 @@ body.filter-warn .filter-chip { border-color: #a68b2d; background: #1a1608; colo padding: 1px 8px; } .filter-clear:hover { border-color: #aaa; background: #222; } -/* Console filter: sticky + overviews stay; hide non-matching log lines */ -body.filter-error #mon-console .line:not(.error):not(.blocker) { display: none !important; } -body.filter-warn #mon-console .line:not(.warn) { display: none !important; } +/* Console filter: sticky + overviews stay; match lines + dimmed neighbours (v1.13.11) */ +body.filter-error #mon-console .line:not(.error):not(.blocker):not(.filter-ctx) { display: none !important; } +body.filter-warn #mon-console .line:not(.warn):not(.filter-ctx) { display: none !important; } +/* Context lines: grayed / muted so the warn|error still stands out */ +body.filter-error #mon-console .line.filter-ctx, +body.filter-warn #mon-console .line.filter-ctx { + opacity: 0.48; + color: #7a7a7a !important; + filter: grayscale(0.9); +} +body.filter-error #mon-console .line.filter-ctx a.jump, +body.filter-warn #mon-console .line.filter-ctx a.jump { + color: #6a6a6a !important; +} +/* Visual break when filter jumps across a gap in the log */ +body.filter-error #mon-console .filter-gap, +body.filter-warn #mon-console .filter-gap { + display: block; + color: #555; + text-align: center; + padding: 6px 0; + margin: 4px 0; + letter-spacing: 0.35em; + font-size: 11px; + user-select: none; + border-top: 1px dashed #333; + border-bottom: 1px dashed #333; +} +body:not(.filter-error):not(.filter-warn) #mon-console .filter-gap { display: none !important; } body.filter-error .env-context, body.filter-warn .env-context { display: none !important; } body.filter-warn .err-top { display: none; } @@ -1355,12 +1381,15 @@ STICKY_JS = """ } catch (e) {} } - // v1.11.0: click error/warn stats → show only those log lines; sticky + overviews stay + // v1.11.0: click error/warn stats → filter log; sticky + overviews stay + // v1.13.11: keep a few neighbour lines (dimmed) so phase/group context stays readable var bar = document.getElementById("status-bar"); var chip = document.getElementById("filter-chip"); var chipLabel = document.getElementById("filter-chip-label"); var clearBtn = document.getElementById("filter-clear"); var consoleEl = document.getElementById("mon-console"); + // lines above + below each match (same count either side) + var FILTER_CTX = 3; function currentFilter() { if (document.body.classList.contains("filter-error")) return "error"; @@ -1368,6 +1397,58 @@ STICKY_JS = """ return ""; } + function clearFilterContext() { + if (!consoleEl) return; + consoleEl.querySelectorAll(".line.filter-ctx").forEach(function (el) { + el.classList.remove("filter-ctx"); + }); + consoleEl.querySelectorAll(".filter-gap").forEach(function (el) { + el.parentNode && el.parentNode.removeChild(el); + }); + } + + function markFilterContext(mode) { + clearFilterContext(); + if (!consoleEl || !mode) return; + var lines = Array.prototype.slice.call(consoleEl.querySelectorAll(".line")); + if (!lines.length) return; + function isMatch(el) { + if (mode === "error") { + return el.classList.contains("error") || el.classList.contains("blocker"); + } + if (mode === "warn") return el.classList.contains("warn"); + return false; + } + // 0 = hide, 1 = match, 2 = context + var keep = new Array(lines.length); + var i, d, j, k; + for (i = 0; i < lines.length; i++) keep[i] = 0; + for (i = 0; i < lines.length; i++) { + if (!isMatch(lines[i])) continue; + keep[i] = 1; + for (d = 1; d <= FILTER_CTX; d++) { + if (i - d >= 0 && keep[i - d] !== 1) keep[i - d] = 2; + if (i + d < lines.length && keep[i + d] !== 1) keep[i + d] = 2; + } + } + for (j = 0; j < lines.length; j++) { + if (keep[j] === 2) lines[j].classList.add("filter-ctx"); + } + // dashed gap between non-contiguous visible clusters + var prevVisible = -2; + for (k = 0; k < lines.length; k++) { + if (keep[k] === 0) continue; + if (prevVisible >= 0 && k > prevVisible + 1) { + var gap = document.createElement("div"); + gap.className = "filter-gap"; + gap.setAttribute("aria-hidden", "true"); + gap.textContent = "· · ·"; + lines[k].parentNode.insertBefore(gap, lines[k]); + } + prevVisible = k; + } + } + function setFilter(mode, opts) { opts = opts || {}; document.body.classList.remove("filter-error", "filter-warn"); @@ -1384,13 +1465,17 @@ STICKY_JS = """ if (warnA) warnA.setAttribute("aria-pressed", "true"); } + // Mark dimmed neighbours (or clear when filter off) + if (mode === "error" || mode === "warn") markFilterContext(mode); + else clearFilterContext(); + if (chip && chipLabel && bar) { if (mode === "error") { chip.hidden = false; - chipLabel.textContent = bar.getAttribute("data-i18n-filter-err") || "Filter: errors only"; + chipLabel.textContent = bar.getAttribute("data-i18n-filter-err") || "Filter: errors + context"; } else if (mode === "warn") { chip.hidden = false; - chipLabel.textContent = bar.getAttribute("data-i18n-filter-warn") || "Filter: warnings only"; + chipLabel.textContent = bar.getAttribute("data-i18n-filter-warn") || "Filter: warnings + context"; } else { chip.hidden = true; chipLabel.textContent = "";