Skip to content

fix(console-log): stop dragging the reader back to the newest line - #3872

Open
ntdatt812 wants to merge 1 commit into
decolua:masterfrom
ntdatt812:fix/3838-console-log-scroll
Open

ntdatt812 wants to merge 1 commit into
decolua:masterfrom
ntdatt812:fix/3838-console-log-scroll

Conversation

@ntdatt812

Copy link
Copy Markdown
Contributor

Closes #3838.

The console log scrolled to the bottom on every append:

useEffect(() => {
  if (!logRef.current) return;
  logRef.current.scrollTop = logRef.current.scrollHeight;
}, [logs]);

So scrolling up to read an older line lasted until the next entry arrived. And something is always appending — a combo fanning out to several models, a background token refresh — which is what makes it unreadable rather than merely awkward. The reporter could not see which member of a fusion had failed.

The change

Following the tail becomes a property of where the reader already is: at the bottom means keep me there, anywhere else means leave me alone.

Two details that are not obvious:

  • The position is recorded on scroll, not read inside the effect. By the time the effect runs, the new lines are already laid out, so the element no longer reports where the reader was before they arrived.
  • The comparison carries a few pixels of slack rather than testing equality. scrollHeight and clientHeight are integers while scrollTop is fractional under a non-integer device pixel ratio, so an element sitting at its bottom routinely reports a residue of a pixel or two. An exact test drops the reader out of follow mode without them having scrolled.

The decision lives in a plain function (src/shared/utils/scrollFollow.js) because tests/vitest.config.js runs with environment: "node" and there is no React testing setup — a component test could not have run at all, and I would rather have a real test of the rule than none.

Verification

tests/unit/scroll-follow.test.js — 7 passed. Each claim checked by reverting it:

reverted fails
slack removed (exact comparison) the sub-pixel case, and the explicit-slack case
always follow (the old behaviour) the older-lines case, and two others

npx next build — ✓ compiled successfully.

Not changed

EndpointPageClient.js has the same unconditional scroll for the Tailscale install log. Left alone deliberately: it runs for the length of one install and has nothing older to read. The helper is there if you want it applied.

…ecolua#3838)

The console log wrote `scrollTop = scrollHeight` on every append:

    useEffect(() => {
      if (!logRef.current) return;
      logRef.current.scrollTop = logRef.current.scrollHeight;
    }, [logs]);

So scrolling up to read an older line lasted until the next entry
arrived. Something is always appending -- a combo fanning out to several
models, a background token refresh -- which is what makes this unreadable
rather than merely awkward: the reporter could not see which member of a
fusion had failed.

Following the tail is now a property of where the reader already is. It
is recorded on scroll, not read inside the effect, because by the time the
effect runs the new lines are laid out and the element no longer reports
where the reader was before they arrived.

The comparison carries a few pixels of slack rather than testing equality.
`scrollHeight` and `clientHeight` are integers while `scrollTop` is
fractional under a non-integer device pixel ratio, so an element sitting
at its bottom routinely reports a residue -- an exact test would drop the
reader out of follow mode without them having scrolled at all.

The decision lives in a plain function because the test environment is
`node` with no DOM, so a component test could not have run. Verified: 7
tests, and each claim checked by reverting it -- comparing exactly fails
the sub-pixel case, always-following fails the older-lines case.

`next build` compiles.

The install log in EndpointPageClient.js has the same unconditional
scroll. It is left alone: it runs for the length of one install, with
nothing older to read.
user177013 added a commit to user177013/9router that referenced this pull request Nov 15, 2026
Cherry-pick the scroll-follow behavior from PR decolua#3872.

Co-authored-by: Copilot <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Console Log scroll reset as new entries are printed, making it hard to read old entries for debugging.

1 participant