From 66fa471d004f327988bbd3840d393586458b658f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hern=C3=A2ni=20Marques?= Date: Sun, 19 Jul 2026 04:41:24 +0200 Subject: [PATCH 01/41] release 1.15.1: SUMMARY severity backgrounds on mon HTML; fix section paint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase section() ╔═║╚ boxes are class section (no sum-header). Real SUMMARY rows keep solid OK/WARN/ERROR/INFO backgrounds on the web. --- VERSION | 2 +- VERSIONS.md | 1 + lib.sh | 6 +- site-gen/console_to_html.py | 124 +++++++++++++++++++++++------------- 4 files changed, 85 insertions(+), 48 deletions(-) diff --git a/VERSION b/VERSION index 141f2e8..ace4423 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.15.0 +1.15.1 diff --git a/VERSIONS.md b/VERSIONS.md index f1ac38d..45ca9b2 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.15.1** | 2026-07-19 | **Bugfix:** mon HTML — phase `section()` boxes no longer painted as SUMMARY (were blue/green `sum-header`); only real SUMMARY rows get solid severity backgrounds (OK/WARN/ERROR/INFO). | | **v1.15.0** | 2026-07-19 | **Feature:** CHF **fake-incoming amount ladder** in `devtesting` (`DEVTESTING_LADDER=1`, default **23** log-spaced rungs **CHF:0.01 → CHF:50000**); synthetic geniban debit funds each rung; baseline plumbing probe kept. | | **v1.14.0** | 2026-07-19 | **Feature:** SUMMARY box rows are **colour-distinct** (per-severity badge + tinted background + bold counts; verdict-coloured header); HTML mon pages style `sum-ok` / `sum-warn` / `sum-err` / … panels the same way. | | **v1.13.13** | 2026-07-19 | **Bugfix:** progress estimate for **devtesting** / fake-franken is 8 (happy-path numbered checks), not 10 — avoids mid-run 42/48 then end snap 46/46. | diff --git a/lib.sh b/lib.sh index 358e6a6..d9ca60c 100755 --- a/lib.sh +++ b/lib.sh @@ -921,9 +921,11 @@ _summary_totals_box() { local ROW_BLK=$'\e[1;97;48;5;53m' # bold white on dark magenta local ROW_TOT=$'\e[1;37;48;5;236m' # bold white on dark gray - printf -- '\n%s╔══════════════════════════════════════╗%s\n' "$hdr_bg" "$N" + # Include SUMMARY on all three frame lines so HTML classify maps them to sum-header + # (phase section() boxes use the same ╔═║╚ glyphs but must not get sum-* paint). + printf -- '\n%s╔════════ %s ════════════════════╗%s\n' "$hdr_bg" "$_sum_lbl" "$N" printf -- '%s║ %-34s ║%s\n' "$hdr_bg" "$_sum_lbl" "$N" - printf -- '%s╚══════════════════════════════════════╝%s\n' "$hdr_bg" "$N" + printf -- '%s╚════════ %s ════════════════════╝%s\n' "$hdr_bg" "$_sum_lbl" "$N" # $1=row_bg $2=badge_bg $3=tag $4=n $5=label_fg — full-width-ish row _sum_row() { diff --git a/site-gen/console_to_html.py b/site-gen/console_to_html.py index 6633f87..43ffcd2 100755 --- a/site-gen/console_to_html.py +++ b/site-gen/console_to_html.py @@ -277,19 +277,13 @@ def is_numbered_check_line(line: str) -> bool: def classify(line: str) -> str: u = line.upper() low = line.lower() - # section / summary headers before badge matching (they contain the word ERROR) - if re.search(r"[╔═║╚]|SUMMARY", u) and ( - "SUMMARY" in u or "═══" in line or "╔" in line or "╚" in line - ): - if "SUMMARY" in u or ("╔" in line and "═" in line) or ("╚" in line and "═" in line): - if "SUMMARY" in u or (not is_numbered_check_line(line) and ("╔" in line or "╚" in line or "║" in line)): - if "SUMMARY" in u or re.match(r"^\s*[╔╚║]", line): - if "SUMMARY" in u: - return "sum-header" - if re.match(r"^\s*[╔╚]", line) and "═" in line: - return "sum-header" - if re.match(r"^\s*║", line) and not is_numbered_check_line(line): - return "sum-header" + # SUMMARY box header only when the word SUMMARY is present (not phase section() boxes). + # Phase section() also uses ╔═║╚ with blue BG_SEC — those must stay class "section". + if "SUMMARY" in u: + return "sum-header" + # Double-line box frames from section() → section (no sum-* paint) + if re.match(r"^\s*[╔╚].*═", line) or re.match(r"^\s*║\s", line): + return "section" if "--- ERRORS" in u or "ERRORS ·" in u or "ERRORS (" in u: return "meta" if "numbered checks" in low: @@ -1883,59 +1877,99 @@ main {{ padding: 12px 14px 48px; max-width: 1200px; }} .line.warn {{ color: var(--warn); }} .line.info {{ color: var(--info); }} .line.blocker {{ color: var(--blocker); }} -.line.section {{ color: var(--sec); margin-top: 8px; font-weight: 600; }} +/* Phase section titles (╔═║╚ from section()) — light chrome, NOT sum-* paint */ +.line.section {{ + color: #9cf; + margin-top: 10px; + font-weight: 700; + background: transparent; + border-left: 3px solid #345; + padding: 2px 0 2px 8px; +}} .line.meta {{ color: var(--dim); }} .line.plain {{ color: var(--fg); }} -/* v1.14.0: SUMMARY box rows — distinct bg + bold per severity */ +/* SUMMARY box — full-width solid backgrounds matching terminal ROW_* tints */ +.line.sum-header, +.line.sum-ok, +.line.sum-err, +.line.sum-warn, +.line.sum-info, +.line.sum-block, +.line.sum-totals, +.line.sum-verdict-ok, +.line.sum-verdict-warn, +.line.sum-verdict-err {{ + display: block; + box-sizing: border-box; + width: 100%; + margin: 2px 0; + padding: 6px 10px; + border-radius: 3px; + font-weight: 800; + letter-spacing: 0.02em; +}} .line.sum-header {{ - color: #fff; font-weight: 800; letter-spacing: 0.04em; - background: linear-gradient(90deg, #1a3a1a 0%, #0a1a0a 100%); - border-left: 4px solid var(--ok); padding: 4px 8px; margin-top: 10px; + color: #e8ffe8; + background: #145214; /* solid green header (not blue) */ + border: 1px solid #2a8a2a; + border-left: 6px solid #3d3; + margin-top: 14px; + text-shadow: 0 1px 0 #0008; }} .line.sum-ok {{ - color: #b8f0b8; font-weight: 700; - background: #0d1f0d; border-left: 4px solid var(--ok); - padding: 3px 8px; margin: 2px 0; + color: #d4ffd4; + background: #0f3d0f; + border: 1px solid #1a6b1a; + border-left: 6px solid var(--ok); }} .line.sum-err {{ - color: #ffc9c9; font-weight: 700; - background: #2a0a0a; border-left: 4px solid var(--err); - padding: 3px 8px; margin: 2px 0; + color: #ffe0e0; + background: #4a1010; + border: 1px solid #822; + border-left: 6px solid var(--err); }} .line.sum-warn {{ - color: #1a1400; font-weight: 800; - background: #c9a227; border-left: 4px solid #8a7010; - padding: 3px 8px; margin: 2px 0; + color: #1a1400; + background: #e6c200; /* bright gold — clearly not blue */ + border: 1px solid #a68b00; + border-left: 6px solid #8a7010; }} .line.sum-info {{ - color: #c8e7ff; font-weight: 700; - background: #0a1520; border-left: 4px solid var(--info); - padding: 3px 8px; margin: 2px 0; + color: #e0f2ff; + background: #0c2a4a; /* navy INFO row only */ + border: 1px solid #1a4a7a; + border-left: 6px solid var(--info); }} .line.sum-block {{ - color: #f5d0ff; font-weight: 700; - background: #1a0a1a; border-left: 4px solid var(--blocker); - padding: 3px 8px; margin: 2px 0; + color: #ffe0ff; + background: #3a1040; + border: 1px solid #6a2a70; + border-left: 6px solid var(--blocker); }} .line.sum-totals {{ - color: #eee; font-weight: 700; - background: #1a1a1a; border-left: 4px solid #666; - padding: 4px 8px; margin: 4px 0 2px; + color: #f0f0f0; + background: #2a2a2a; + border: 1px solid #555; + border-left: 6px solid #888; + margin-top: 6px; }} .line.sum-verdict-ok {{ - color: #b8f0b8; font-weight: 800; - background: #0d1f0d; border: 1px solid #2a5a2a; - padding: 4px 8px; margin: 4px 0 8px; + color: #d4ffd4; + background: #0f3d0f; + border: 2px solid #2a8a2a; + margin-bottom: 10px; }} .line.sum-verdict-warn {{ - color: #1a1400; font-weight: 800; - background: #c9a227; border: 1px solid #8a7010; - padding: 4px 8px; margin: 4px 0 8px; + color: #1a1400; + background: #e6c200; + border: 2px solid #8a7010; + margin-bottom: 10px; }} .line.sum-verdict-err {{ - color: #ffc9c9; font-weight: 800; - background: #2a0a0a; border: 1px solid #622; - padding: 4px 8px; margin: 4px 0 8px; + color: #ffe0e0; + background: #4a1010; + border: 2px solid #a33; + margin-bottom: 10px; }} a.jump {{ color: inherit; text-decoration: underline dotted; }} footer {{ From bf3a2e34dc7bcbeadf15010a5e1340e9f4130d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hern=C3=A2ni=20Marques?= Date: Sun, 19 Jul 2026 04:43:49 +0200 Subject: [PATCH 02/41] =?UTF-8?q?release=201.15.2:=20compact=20warn/error?= =?UTF-8?q?=20filter=20=E2=80=94=20no=20black=20voids?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Omit blank log lines from mon HTML. Filter mode collapses non-matches to zero size, uses tighter useful context, and a minimal cluster gap. --- VERSION | 2 +- VERSIONS.md | 1 + site-gen/console_to_html.py | 118 ++++++++++++++++++++++++++++-------- 3 files changed, 94 insertions(+), 27 deletions(-) diff --git a/VERSION b/VERSION index ace4423..42cf067 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.15.1 +1.15.2 diff --git a/VERSIONS.md b/VERSIONS.md index 45ca9b2..470fe10 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.15.2** | 2026-07-19 | **Bugfix:** warn/error filter — drop blank log lines from HTML; compact console (no black voids above/mid/below); context skips SUMMARY chrome & pure box frames; tighter filter-gap. | | **v1.15.1** | 2026-07-19 | **Bugfix:** mon HTML — phase `section()` boxes no longer painted as SUMMARY (were blue/green `sum-header`); only real SUMMARY rows get solid severity backgrounds (OK/WARN/ERROR/INFO). | | **v1.15.0** | 2026-07-19 | **Feature:** CHF **fake-incoming amount ladder** in `devtesting` (`DEVTESTING_LADDER=1`, default **23** log-spaced rungs **CHF:0.01 → CHF:50000**); synthetic geniban debit funds each rung; baseline plumbing probe kept. | | **v1.14.0** | 2026-07-19 | **Feature:** SUMMARY box rows are **colour-distinct** (per-severity badge + tinted background + bold counts; verdict-coloured header); HTML mon pages style `sum-ok` / `sum-warn` / `sum-err` / … panels the same way. | diff --git a/site-gen/console_to_html.py b/site-gen/console_to_html.py index 43ffcd2..89dd4ee 100755 --- a/site-gen/console_to_html.py +++ b/site-gen/console_to_html.py @@ -549,6 +549,10 @@ def slug_error(i: int, text: str) -> str: def render_line(ln: str, err_slugs: dict[str, str], extra_ids: list[str] | None = None) -> str: + # Drop blank log lines entirely — they only create black voids in the console + # (especially visible under warn/error filter). Anchors still attach to next real line. + if not (ln or "").strip(): + return "" kind = classify(ln) esc = html.escape(ln) for tid, slug in err_slugs.items(): @@ -563,8 +567,11 @@ def render_line(ln: str, err_slugs: dict[str, str], extra_ids: list[str] | None # HTML allows one id — join carefully id_attr = f' id="{html.escape(extra_ids[0])}"' if len(extra_ids) > 1: - # secondary anchors as empty spans prepended - spans = "".join(f'' for x in extra_ids[1:]) + # secondary anchors as empty spans prepended (inline, zero layout impact) + spans = "".join( + f'' + for x in extra_ids[1:] + ) return f'{spans}{esc}\n' return f'{esc}\n' @@ -1175,38 +1182,83 @@ 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; 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; } +/* Console filter: sticky + overviews stay; match lines + dimmed neighbours (v1.13.11+) + v1.15.2: stamp out black voids — hide blanks, zero-size non-matches, compact console */ +body.filter-error #mon-console, +body.filter-warn #mon-console { + padding: 6px 8px; + min-height: 0; + display: flex; + flex-direction: column; + gap: 1px; +} +body.filter-error #mon-console .line:not(.error):not(.blocker):not(.filter-ctx), +body.filter-warn #mon-console .line:not(.warn):not(.filter-ctx) { + display: none !important; + height: 0 !important; + margin: 0 !important; + padding: 0 !important; + border: none !important; + overflow: hidden !important; + line-height: 0 !important; +} +/* empty / whitespace-only lines never take space in filter mode */ +body.filter-error #mon-console .line:empty, +body.filter-warn #mon-console .line:empty, +body.filter-error #mon-console .line.line-blank, +body.filter-warn #mon-console .line.line-blank { + 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); + opacity: 0.55; + color: #8a8a8a !important; + filter: grayscale(0.85); + margin: 0 !important; + padding: 1px 4px !important; + border: none !important; + background: transparent !important; } 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 */ +/* Match lines stay tight */ +body.filter-error #mon-console .line.error, +body.filter-error #mon-console .line.blocker, +body.filter-warn #mon-console .line.warn { + margin: 1px 0 !important; + padding: 3px 6px !important; +} +/* Compact ellipsis between distant clusters (not a black slab) */ body.filter-error #mon-console .filter-gap, body.filter-warn #mon-console .filter-gap { display: block; - color: #555; + color: #666; text-align: center; - padding: 6px 0; - margin: 4px 0; - letter-spacing: 0.35em; - font-size: 11px; + padding: 0; + margin: 2px 0; + letter-spacing: 0.25em; + font-size: 10px; + line-height: 1.2; user-select: none; - border-top: 1px dashed #333; - border-bottom: 1px dashed #333; + border: none; + background: transparent; + height: auto; } 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; } +/* secondary jump anchors: never affect layout */ +#mon-console .anchor-only { + display: inline; + width: 0; + height: 0; + overflow: hidden; + position: absolute; +} /* v1.12.0: collapsible monitoring env context (default closed) */ .env-context { margin: 0 0 12px; @@ -1436,14 +1488,14 @@ STICKY_JS = """ } // 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 + // v1.13.11: dimmed neighbour context; v1.15.2: stamp out black voids, compact layout 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; + // useful neighbours each side (skip blanks / SUMMARY chrome / pure box frames) + var FILTER_CTX = 2; function currentFilter() { if (document.body.classList.contains("filter-error")) return "error"; @@ -1459,11 +1511,13 @@ STICKY_JS = """ consoleEl.querySelectorAll(".filter-gap").forEach(function (el) { el.parentNode && el.parentNode.removeChild(el); }); + document.body.classList.remove("filter-compact"); } function markFilterContext(mode) { clearFilterContext(); if (!consoleEl || !mode) return; + document.body.classList.add("filter-compact"); var lines = Array.prototype.slice.call(consoleEl.querySelectorAll(".line")); if (!lines.length) return; function isMatch(el) { @@ -1477,19 +1531,30 @@ STICKY_JS = """ var t = (el.textContent || "").replace(/\u00a0/g, " ").trim(); return t.length === 0; } - // 0 = hide, 1 = match, 2 = context + function isLowValue(el) { + if (isBlankLine(el)) return true; + if (el.classList.contains("sum-header") || el.classList.contains("sum-ok") + || el.classList.contains("sum-warn") || el.classList.contains("sum-err") + || el.classList.contains("sum-info") || el.classList.contains("sum-block") + || el.classList.contains("sum-totals") || el.classList.contains("sum-verdict-ok") + || el.classList.contains("sum-verdict-warn") || el.classList.contains("sum-verdict-err")) { + return true; + } + var t = (el.textContent || "").replace(/\u00a0/g, " ").trim(); + if (/^[╔╗╚╝║═\-\s│┌┐└┘]+$/.test(t)) return true; + return false; + } var keep = new Array(lines.length); var i, j, k, n, idx; 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; - // ±FILTER_CTX *non-empty* neighbours (skip blank lines so filter is not full of voids) n = 0; idx = i - 1; while (idx >= 0 && n < FILTER_CTX) { if (keep[idx] === 1) { idx--; continue; } - if (isBlankLine(lines[idx])) { idx--; continue; } + if (isLowValue(lines[idx])) { idx--; continue; } keep[idx] = 2; n++; idx--; @@ -1498,7 +1563,7 @@ STICKY_JS = """ idx = i + 1; while (idx < lines.length && n < FILTER_CTX) { if (keep[idx] === 1) { idx++; continue; } - if (isBlankLine(lines[idx])) { idx++; continue; } + if (isLowValue(lines[idx])) { idx++; continue; } keep[idx] = 2; n++; idx++; @@ -1506,10 +1571,11 @@ STICKY_JS = """ } for (j = 0; j < lines.length; j++) { if (keep[j] === 2) lines[j].classList.add("filter-ctx"); - // never show pure blank lines in filter mode - if (isBlankLine(lines[j]) && keep[j] !== 1) keep[j] = 0; + if (isBlankLine(lines[j])) { + keep[j] = 0; + lines[j].classList.add("line-blank"); + } } - // dashed gap between non-contiguous visible clusters var prevVisible = -2; for (k = 0; k < lines.length; k++) { if (keep[k] === 0) continue; From ae8a72a5f3cdc3d2a551fdb0dde9c73f5936c2d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hern=C3=A2ni=20Marques?= Date: Sun, 19 Jul 2026 04:45:12 +0200 Subject: [PATCH 03/41] release 1.15.3: auto-French console for lefrancpaysan domains Do not treat a non-empty TALER_MON_LANG from env as explicit language. Domain *lefrancpaysan* selects fr unless TALER_MON_LANG_SET=1 (--lang). --- VERSION | 2 +- VERSIONS.md | 1 + i18n.sh | 21 ++++++++++++++------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/VERSION b/VERSION index 42cf067..f2380cc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.15.2 +1.15.3 diff --git a/VERSIONS.md b/VERSIONS.md index 470fe10..b900ef4 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.15.3** | 2026-07-19 | **Bugfix:** console language auto-**fr** for `*lefrancpaysan*` domains again — env `TALER_MON_LANG=en` no longer locks English; only `--lang` / `TALER_MON_LANG_SET=1` is explicit. | | **v1.15.2** | 2026-07-19 | **Bugfix:** warn/error filter — drop blank log lines from HTML; compact console (no black voids above/mid/below); context skips SUMMARY chrome & pure box frames; tighter filter-gap. | | **v1.15.1** | 2026-07-19 | **Bugfix:** mon HTML — phase `section()` boxes no longer painted as SUMMARY (were blue/green `sum-header`); only real SUMMARY rows get solid severity backgrounds (OK/WARN/ERROR/INFO). | | **v1.15.0** | 2026-07-19 | **Feature:** CHF **fake-incoming amount ladder** in `devtesting` (`DEVTESTING_LADDER=1`, default **23** log-spaced rungs **CHF:0.01 → CHF:50000**); synthetic geniban debit funds each rung; baseline plumbing probe kept. | diff --git a/i18n.sh b/i18n.sh index 5ca1d18..1b0c90d 100644 --- a/i18n.sh +++ b/i18n.sh @@ -1,23 +1,29 @@ #!/usr/bin/env bash # i18n.sh — language for taler-monitoring console + HTML chrome # -# TALER_MON_LANG=en|fr (default en) -# Auto: domains *lefrancpaysan* → fr unless TALER_MON_LANG is set explicitly. +# TALER_MON_LANG=en|fr +# TALER_MON_LANG_SET=1 → language is explicit (--lang or host-agent wrapper); do not override. +# Auto (SET≠1): domain *lefrancpaysan* / *francpaysan* → fr, else keep env or en. +# +# Important: a bare TALER_MON_LANG=en in ~/.config/taler-monitoring/env must NOT lock +# language for FP domains (that used to force English on stage.monnaie…). : "${TALER_MON_LANG:=}" : "${TALER_MON_LANG_SET:=0}" i18n_init() { - if [ -n "${TALER_MON_LANG:-}" ]; then - TALER_MON_LANG_SET=1 - fi - if [ "${TALER_MON_LANG_SET}" != "1" ]; then + # Only TALER_MON_LANG_SET=1 is "explicit". Do not promote non-empty TALER_MON_LANG + # to SET=1 — env files often ship LANG=en for the default GOA workstation. + if [ "${TALER_MON_LANG_SET:-0}" != "1" ]; then case "${TALER_DOMAIN:-}" in *lefrancpaysan*|*francpaysan*) TALER_MON_LANG=fr ;; *) - TALER_MON_LANG=en + # Non-FP: keep pre-set env value if any, else English + if [ -z "${TALER_MON_LANG:-}" ]; then + TALER_MON_LANG=en + fi ;; esac fi @@ -26,6 +32,7 @@ i18n_init() { *) TALER_MON_LANG=en ;; esac export TALER_MON_LANG + export TALER_MON_LANG_SET } i18n_tag() { From b4f5f060ccb07bfe405b82d7515cfe67b4bee975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hern=C3=A2ni=20Marques?= Date: Sun, 19 Jul 2026 04:51:42 +0200 Subject: [PATCH 04/41] release 1.15.4: French sticky titles and SUMMARY verdict strings Localize monitoring host label, stack summary (public + interne), and SUMMARY all-clear / warnings-only / totals for FR console and HTML. --- VERSION | 2 +- VERSIONS.md | 1 + i18n.sh | 5 +++++ lib.sh | 18 ++++++++------- site-gen/console_to_html.py | 44 +++++++++++++++++++++++++++++-------- 5 files changed, 52 insertions(+), 18 deletions(-) diff --git a/VERSION b/VERSION index f2380cc..e34208c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.15.3 +1.15.4 diff --git a/VERSIONS.md b/VERSIONS.md index b900ef4..ee61b4c 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.15.4** | 2026-07-19 | **Bugfix:** French sticky titles — page label *surveillance*, stack summary *public + interne*, SUMMARY verdict/totals via i18n (`tout est clair`, `totaux :`). | | **v1.15.3** | 2026-07-19 | **Bugfix:** console language auto-**fr** for `*lefrancpaysan*` domains again — env `TALER_MON_LANG=en` no longer locks English; only `--lang` / `TALER_MON_LANG_SET=1` is explicit. | | **v1.15.2** | 2026-07-19 | **Bugfix:** warn/error filter — drop blank log lines from HTML; compact console (no black voids above/mid/below); context skips SUMMARY chrome & pure box frames; tighter filter-gap. | | **v1.15.1** | 2026-07-19 | **Bugfix:** mon HTML — phase `section()` boxes no longer painted as SUMMARY (were blue/green `sum-header`); only real SUMMARY rows get solid severity backgrounds (OK/WARN/ERROR/INFO). | diff --git a/i18n.sh b/i18n.sh index 1b0c90d..a5a2285 100644 --- a/i18n.sh +++ b/i18n.sh @@ -73,6 +73,11 @@ i18n_text() { "pay/withdraw cannot finish") printf 'paiement/retrait impossible a terminer' ;; "SUMMARY") printf 'RESUME' ;; "totals:") printf 'totaux :' ;; + "all clear") printf 'tout est clair' ;; + "warnings only (no hard fail)") printf 'avertissements seulement (pas d'\''echec dur)' ;; + "monitoring") printf 'surveillance' ;; + "surface") printf 'surface' ;; + "aptdeploy") printf 'aptdeploy' ;; "container") printf 'conteneur' ;; "disk") printf 'disque' ;; "package") printf 'paquet' ;; diff --git a/lib.sh b/lib.sh index d9ca60c..4e7f137 100755 --- a/lib.sh +++ b/lib.sh @@ -944,7 +944,7 @@ _summary_totals_box() { [ "$blk_n" -gt 0 ] && _sum_row "$ROW_BLK" "$BG_BLK" "BLOCK" "$blk_n" "$M" # totals rollup on tinted bar - printf -- ' %s %s totals: %s%d OK%s' "$ROW_TOT" "$B" "$G$B" "$pass_n" "$N$ROW_TOT" + printf -- ' %s %s %s %s%d OK%s' "$ROW_TOT" "$B" "$(i18n_text 'totals:')" "$G$B" "$pass_n" "$N$ROW_TOT" [ "$fail_n" -gt 0 ] && printf -- ' %s·%s %s%d ERROR%s' "$D" "$N$ROW_TOT" "$R$B" "$fail_n" "$N$ROW_TOT" [ "$warn_n" -gt 0 ] && printf -- ' %s·%s %s%d WARN%s' "$D" "$N$ROW_TOT" "$Y$B" "$warn_n" "$N$ROW_TOT" [ "$info_n" -gt 0 ] && printf -- ' %s·%s %s%d INFO%s' "$D" "$N$ROW_TOT" "$C$B" "$info_n" "$N$ROW_TOT" @@ -957,28 +957,30 @@ _summary_totals_box() { [ "$warn_n" -gt 0 ] && printf -- ' [ %-5s ] %s%4d%s\n' "$(i18n_tag WARN)" "$Y$B" "$warn_n" "$N" [ "$info_n" -gt 0 ] && printf -- ' [ %-5s ] %s%4d%s\n' "$(i18n_tag INFO)" "$C$B" "$info_n" "$N" [ "$blk_n" -gt 0 ] && printf -- ' [ %-5s ] %s%4d%s\n' "$(i18n_tag BLOCK)" "$M$B" "$blk_n" "$N" - printf -- ' %stotals:%s %s%d OK%s' "$B" "$N" "$G$B" "$pass_n" "$N" + printf -- ' %s%s%s %s%d OK%s' "$B" "$(i18n_text 'totals:')" "$N" "$G$B" "$pass_n" "$N" [ "$fail_n" -gt 0 ] && printf -- ' · %s%d ERROR%s' "$R$B" "$fail_n" "$N" [ "$warn_n" -gt 0 ] && printf -- ' · %s%d WARN%s' "$Y$B" "$warn_n" "$N" [ "$info_n" -gt 0 ] && printf -- ' · %s%d INFO%s' "$C$B" "$info_n" "$N" [ "$blk_n" -gt 0 ] && printf -- ' · %s%d BLOCKER%s' "$M$B" "$blk_n" "$N" printf '\n' fi - # overall verdict — bold label, filled badge + # overall verdict — bold label, filled badge (i18n for FR console/HTML) + local _ok_msg _warn_msg _fail_msg + _ok_msg=$(i18n_text 'all clear') + _warn_msg=$(i18n_text 'warnings only (no hard fail)') if [ "$fail_n" -eq 0 ] && [ "$blk_n" -eq 0 ] && [ "$warn_n" -eq 0 ]; then if [ "${BOX:-0}" = "1" ]; then - printf -- ' %s┌ OK ┐%s %s%sall clear%s\n' "$BG_OK" "$N" "$G" "$B" "$N" + printf -- ' %s┌ OK ┐%s %s%s%s%s\n' "$BG_OK" "$N" "$G" "$B" "$_ok_msg" "$N" else - printf -- ' %s[ OK ] %sall clear%s\n' "$G" "$B" "$N" + printf -- ' %s[ OK ] %s%s%s\n' "$G" "$B" "$_ok_msg" "$N" fi elif [ "$fail_n" -eq 0 ] && [ "$blk_n" -eq 0 ]; then if [ "${BOX:-0}" = "1" ]; then - printf -- ' %s┌ WARN ┐%s %s%swarnings only (no hard fail)%s\n' "$BG_WARN" "$N" "$Y" "$B" "$N" + printf -- ' %s┌ WARN ┐%s %s%s%s%s\n' "$BG_WARN" "$N" "$Y" "$B" "$_warn_msg" "$N" else - printf -- ' %s[ WARN ] %swarnings only (no hard fail)%s\n' "$Y" "$B" "$N" + printf -- ' %s[ WARN ] %s%s%s\n' "$Y" "$B" "$_warn_msg" "$N" fi else - local _fail_msg _fail_msg=$(i18n_text 'failed — see list above') if [ "${BOX:-0}" = "1" ]; then printf -- ' %s┌ ERROR ┐%s %s%s%s%s\n' "$BG_ERR" "$N" "$R" "$B" "$_fail_msg" "$N" diff --git a/site-gen/console_to_html.py b/site-gen/console_to_html.py index 89dd4ee..0874c1e 100755 --- a/site-gen/console_to_html.py +++ b/site-gen/console_to_html.py @@ -114,6 +114,12 @@ def ui(lang: str, key: str, **kwargs) -> str: "stack_i4": "HTML host: {host}", "stack_i5": "Timer: host-agent path + 4h · /monitoring on bank, exchange, merchant fronts", "stack_i_phases": "Log header phases= {phases}", + "page_label_monitoring": "monitoring", + "page_label_surface": "surface", + "page_label_aptdeploy": "aptdeploy", + "mode_ok": "OK", + "mode_err": "ERR", + "mode_redirect": "REDIR", "pages_title": "Monitoring pages (suite HTML)", "pages_summary": "Public sticky-bar reports · phase monpages · part of taler-monitoring", "pages_i1": "Suite name taler-monitoring ≠ URL. Only three public families (bare + slash each):", @@ -200,14 +206,20 @@ def ui(lang: str, key: str, **kwargs) -> str: "focus_merchant": "Backend marchand / SPA HTTPS public + contrôles inside conteneur", "focus_stack": "Pile Taler public + inside", "stack_title": "Surveillance de pile · {host}", - "stack_summary": "{phases} · public + inside", + "stack_summary": "{phases} · public + interne", "stack_i1": "Focus : {focus}", "stack_i2": "Phases de cette exécution : {phases}", "stack_i3": "Typique : URL publiques (HTTPS, QR, perf), inside (podman/ssh), versions des paquets", "stack_i4": "Hôte HTML : {host}", "stack_i5": "Minuterie : host-agent path + 4 h · /monitoring sur bank, exchange, fronts marchands", "stack_i_phases": "En-tête de journal phases= {phases}", - "pages_title": "Pages de monitoring (HTML de la suite)", + "page_label_monitoring": "surveillance", + "page_label_surface": "surface", + "page_label_aptdeploy": "aptdeploy", + "mode_ok": "OK", + "mode_err": "ERR", + "mode_redirect": "REDIR", + "pages_title": "Pages de monitoring (HTML de la suite)", "pages_summary": "Rapports publics sticky-bar · phase monpages · partie de taler-monitoring", "pages_i1": "Nom de suite taler-monitoring ≠ URL. Trois familles publiques seulement (sans et avec /) :", "pages_i2": "1) /monitoring(+_err) · 2) /taler-monitoring-surface(+_err) · 3) /taler-monitoring-aptdeploy(+_err) sur taler.hacktivism.ch", @@ -288,14 +300,14 @@ def classify(line: str) -> str: return "meta" if "numbered checks" in low: return "meta" - if "totals:" in low: + if "totals:" in low or "totaux :" in low or low.strip().startswith("totaux"): return "sum-totals" # SUMMARY verdict chrome (not a check) — keep distinct for HTML boxes - if "warnings only" in low: + if "warnings only" in low or "avertissements seulement" in low: return "sum-verdict-warn" - if "all clear" in low: + if "all clear" in low or "tout est clair" in low: return "sum-verdict-ok" - if "failed — see" in low or "failed - see" in low: + if "failed — see" in low or "failed - see" in low or "echec — voir" in low or "échec — voir" in low: return "sum-verdict-err" # host-agent tees converter "wrote … (errors=N …)" into the same log if line.lstrip().lower().startswith("wrote ") and "errors=" in low: @@ -443,8 +455,12 @@ def is_summary_error_line(ln: str) -> bool: return True if "warnings only" in low or "all clear" in low: return True + if "avertissements seulement" in low or "tout est clair" in low: + return True + if "totaux" in low and not is_numbered_check_line(ln): + return True # SUMMARY count rows without #NNN / tid (e.g. " [ ERROR ] 3") - if re.search(r"[\[\u250c]\s*(ERROR|WARN|OK|INFO|BLOCK)", ln, re.I) and not is_numbered_check_line( + if re.search(r"[\[\u250c]\s*(ERROR|WARN|OK|INFO|BLOCK|ERREUR|AVERT)", ln, re.I) and not is_numbered_check_line( ln ): return True @@ -1066,6 +1082,16 @@ def sticky_bar_html( version_html = f'{html.escape(ver)}' else: version_html = "" + # Localize page label for sticky host title (monitoring → surveillance in FR) + pl = (page_label or "monitoring").lower().replace("_", "-") + if "surface" in pl: + pl_disp = ui(lang, "page_label_surface") + elif "aptdeploy" in pl or "apt-deploy" in pl: + pl_disp = ui(lang, "page_label_aptdeploy") + else: + pl_disp = ui(lang, "page_label_monitoring") + mode_key = f"mode_{mode}" if mode in ("ok", "err", "redirect") else "" + mode_disp = ui(lang, mode_key) if mode_key and ui(lang, mode_key) != mode_key else mode.upper() # Compact sticky row always visible; "Was geprüft wird" expands inside sticky-bar return f"""