feat: apply smart fold automatically on page load
Logs with errors now open already smart-folded — every entry within ±25 of an error stays visible, gaps collapse into draggable bars. Folds can only be expanded individually via per-bar click or drag; the previous "toggle to unfold everything" path is gone. The header error-count chip becomes informational only (cursor and pointer-events stripped so it no longer reads as interactive). Removed the dead toggleErrors / uncollapseAllErrors / "toggled" state plumbing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1153,6 +1153,17 @@ main {
|
|||||||
0 6px 16px color-mix(in srgb, var(--accent) 25%, transparent);
|
0 6px 16px color-mix(in srgb, var(--accent) 25%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The header error-count chip is informational only — the smart fold is
|
||||||
|
* applied automatically on page load and folds can only be expanded
|
||||||
|
* individually. Strip the .btn cursor / hover affordance so the chip
|
||||||
|
* doesn't read as interactive.
|
||||||
|
*/
|
||||||
|
#error-toggle {
|
||||||
|
cursor: default;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.log-inner .level {
|
.log-inner .level {
|
||||||
display: block;
|
display: block;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
|
|||||||
@@ -48,48 +48,44 @@ function scrollToHeight(top, smoothScrollLimit = 10000) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Error collapse toggle.
|
* Smart fold around errors.
|
||||||
*
|
*
|
||||||
* Smart fold: every entry within ±ERROR_WINDOW_SIZE of an error stays
|
* Every entry within ±ERROR_WINDOW_SIZE of an error stays visible; runs of
|
||||||
* visible; runs of non-error entries with no nearby errors collapse into
|
* non-error entries with no nearby errors collapse into a draggable fold
|
||||||
* a draggable fold bar. Vertical drag on the bar progressively reveals or
|
* bar. Vertical drag on the bar progressively reveals or re-hides lines;
|
||||||
* re-hides lines; a click without drag reveals the next DEFAULT_CLICK_REVEAL
|
* a click without drag reveals the next DEFAULT_CLICK_REVEAL lines.
|
||||||
* lines.
|
*
|
||||||
|
* The fold is applied automatically on page load when the log contains
|
||||||
|
* errors. Folds can only be expanded individually — there is no
|
||||||
|
* "unfold everything" path. The error-count chip in the header is purely
|
||||||
|
* informational; it is not interactive.
|
||||||
*/
|
*/
|
||||||
const ERROR_WINDOW_SIZE = 25;
|
const ERROR_WINDOW_SIZE = 25;
|
||||||
const PIXELS_PER_LINE_DRAG = 6;
|
const PIXELS_PER_LINE_DRAG = 6;
|
||||||
const DEFAULT_CLICK_REVEAL = 25;
|
const DEFAULT_CLICK_REVEAL = 25;
|
||||||
const DRAG_PIXEL_THRESHOLD = 3;
|
const DRAG_PIXEL_THRESHOLD = 3;
|
||||||
|
|
||||||
const toggleErrorsButton = document.getElementById("error-toggle");
|
applySmartFold();
|
||||||
if (toggleErrorsButton) {
|
|
||||||
toggleErrorsButton.addEventListener("click", toggleErrors);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleErrors() {
|
function applySmartFold() {
|
||||||
if (toggleErrorsButton.classList.contains("toggled")) {
|
|
||||||
toggleErrorsButton.classList.remove("toggled");
|
|
||||||
uncollapseAllErrors();
|
|
||||||
} else {
|
|
||||||
toggleErrorsButton.classList.add("toggled");
|
|
||||||
collapseAllErrors();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function collapseAllErrors() {
|
|
||||||
const lines = Array.from(document.querySelectorAll('.log-inner > .entry'));
|
const lines = Array.from(document.querySelectorAll('.log-inner > .entry'));
|
||||||
const total = lines.length;
|
const total = lines.length;
|
||||||
if (!total) return;
|
if (!total) return;
|
||||||
|
|
||||||
// Pass 1: mark entries within ±ERROR_WINDOW_SIZE of any error.
|
// Pass 1: mark entries within ±ERROR_WINDOW_SIZE of any error. If the
|
||||||
|
// log has no errors, every entry stays visible (we never produce one
|
||||||
|
// giant fold spanning the whole log).
|
||||||
const mustShow = new Array(total).fill(false);
|
const mustShow = new Array(total).fill(false);
|
||||||
|
let sawError = false;
|
||||||
for (let i = 0; i < total; i++) {
|
for (let i = 0; i < total; i++) {
|
||||||
if (lines[i].classList.contains("entry-error")) {
|
if (lines[i].classList.contains("entry-error")) {
|
||||||
|
sawError = true;
|
||||||
const lo = Math.max(0, i - ERROR_WINDOW_SIZE);
|
const lo = Math.max(0, i - ERROR_WINDOW_SIZE);
|
||||||
const hi = Math.min(total - 1, i + ERROR_WINDOW_SIZE);
|
const hi = Math.min(total - 1, i + ERROR_WINDOW_SIZE);
|
||||||
for (let j = lo; j <= hi; j++) mustShow[j] = true;
|
for (let j = lo; j <= hi; j++) mustShow[j] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!sawError) return;
|
||||||
|
|
||||||
// Pass 2: hide unmarked entries; emit a fold bar at the START of each run.
|
// Pass 2: hide unmarked entries; emit a fold bar at the START of each run.
|
||||||
let runEntries = [];
|
let runEntries = [];
|
||||||
@@ -110,11 +106,6 @@ function collapseAllErrors() {
|
|||||||
flushRun();
|
flushRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
function uncollapseAllErrors() {
|
|
||||||
document.querySelectorAll(".log-inner > .entry").forEach(line => line.style.removeProperty("display"));
|
|
||||||
document.querySelectorAll(".collapsed-lines").forEach(bar => bar.remove());
|
|
||||||
}
|
|
||||||
|
|
||||||
function createFoldBar(entries) {
|
function createFoldBar(entries) {
|
||||||
const bar = document.createElement("div");
|
const bar = document.createElement("div");
|
||||||
bar.classList.add("collapsed-lines", "collapsed-lines-foldable");
|
bar.classList.add("collapsed-lines", "collapsed-lines-foldable");
|
||||||
|
|||||||
Reference in New Issue
Block a user