release 1.15.2: compact warn/error filter — no black voids
Omit blank log lines from mon HTML. Filter mode collapses non-matches to zero size, uses tighter useful context, and a minimal cluster gap.
This commit is contained in:
parent
66fa471d00
commit
bf3a2e34dc
3 changed files with 94 additions and 27 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
1.15.1
|
||||
1.15.2
|
||||
|
|
|
|||
|
|
@ -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. |
|
||||
|
|
|
|||
|
|
@ -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'<span id="{html.escape(x)}"></span>' for x in extra_ids[1:])
|
||||
# secondary anchors as empty spans prepended (inline, zero layout impact)
|
||||
spans = "".join(
|
||||
f'<span id="{html.escape(x)}" class="anchor-only"></span>'
|
||||
for x in extra_ids[1:]
|
||||
)
|
||||
return f'{spans}<div{id_attr} class="line {kind}">{esc}</div>\n'
|
||||
return f'<div{id_attr} class="line {kind}">{esc}</div>\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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue