Skip to content

πŸ› dashboard: agents section refresh shifts scroll position - #12209

Merged
hivecommons-hive[bot] merged 2 commits into
v5from
fix/agents-refresh-scroll-jump
Oct 15, 2026
Merged

hivecommons-hive[bot] merged 2 commits into
v5from
fix/agents-refresh-scroll-jump

Conversation

@clubanderson

Copy link
Copy Markdown
Member

Closes #12208

Root cause

renderAgents() rebuilt the entire agents grid with el.innerHTML = html whenever any byte changed β€” i.e. on every SSE status tick. Two consequences moved the content under the reader's viewport:

  1. .doing terminal-tail panes change height (min-height: 5.6em; max-height: 30em, content-sized). Each refresh adds liveSummary lines (or removes the pane when the summary is empty), so cards in the rows above the viewport grow/shrink and push the visible rows down/up. The existing captureScrollAnchor/restoreScrollAnchor in render() only anchors on the section's top edge, which doesn't move once you've scrolled into the section, so it corrected nothing.
  2. Destroying every node also invalidated Chrome's built-in scroll anchor; Safari has no scroll anchoring at all, so the jump is worst there (the reporter's browser).

Additionally prev.focus() ran without preventScroll, so a focused kick-prompt input was scrolled into view on every refresh.

Reproduced with Playwright WebKit + Chromium against a locally served index.html (9-card grid, scrolled so row 3 is first visible, refresh adds lines to the .doing panes in rows 1–2): the visible card moved by ~97px with window.scrollY unchanged.

Fix

  • Patch cards in place (morphAgentGrid / morphDomNode, keyed by data-agent): attributes and text nodes are patched, nodes are reordered/inserted/removed, form controls swapped only when their markup changed, JS-set inline style (resize-handle heights) preserved. Card nodes, .agent-card-details/.doing scrollTop, focus and typed input survive a refresh, and the browser's scroll anchor stays valid. Verified with an oracle that the live DOM after morphing across 8 varied payloads (reorder, add/remove cards, status/class/text changes) serialises identically to a cold render.
  • Card-level scroll anchor: once the reader has scrolled into a section, captureScrollAnchor records the first agent card still in view (by key) and restoreScrollAnchor corrects by that card's delta. This is what fixes Safari.
  • .doing auto-follow uses element scrollTop only, and only when the reader was already at the bottom.
  • focus({ preventScroll: true }).

After the fix the same repro keeps the visible card within <1px in both engines across alternating grow/shrink refreshes.

Tests

agents_refresh_scroll_jump_test.go: structural pins on renderAgents / captureScrollAnchor / restoreScrollAnchor, plus a node-executed behavioural test of morphDomNode against a minimal DOM stand-in (node identity kept, text/attrs patched, inline style preserved, form controls swapped only on change).

No new inline style= attributes (style ratchet unaffected). Other sections unchanged.

renderAgents rebuilt the grid with innerHTML on every status tick. The
.doing terminal tails of cards in rows above the viewport grew/shrank
with new log lines, pushing the rows the reader was looking at; the
section-level scroll anchor in render() couldn't see it, Chrome's own
scroll anchor was destroyed with the nodes, and Safari has no scroll
anchoring at all.

- Patch cards in place (keyed by data-agent) instead of innerHTML.
- Anchor render() scroll restore on the first visible agent card.
- Follow .doing tails via element scrollTop only when already at bottom.
- focus({ preventScroll: true }) on re-focus.

Closes #12208

Signed-off-by: Andrew Anderson <andy@clubanderson.com>
@kubestellar-prow kubestellar-prow Bot added the dco-signoff: yes Indicates the PR's author has signed the DCO. label Oct 15, 2026
@kubestellar-prow

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign clubanderson for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubestellar-prow kubestellar-prow Bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Oct 15, 2026
@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Open PR overlap check

Base branch: v5

Conflicts are checked with every PR merged onto the current tip of v5, so a PR that only needs a rebase is not reported as conflicting with its siblings.

PR Title Relation Files
#12187 ✨ dashboard settings: agent_sandbox scalar settings same files src/pkg/dashboard/static/index.html
#12182 ✨ intent: add intent.shadow to record would_have_blocked same files src/pkg/dashboard/static/index.html
#12170 πŸ› Settings modal: sticky-section gap, height, and section navigation same files src/pkg/dashboard/static/index.html
#12158 ✨ review: add review.shadow to record would_have_held for the review gate same files src/pkg/dashboard/static/index.html

Signed-off-by: Andrew Anderson <andy@clubanderson.com>
@hivecommons-hive
hivecommons-hive Bot merged commit 9e511db into v5 Oct 15, 2026
70 of 71 checks passed
@hivecommons-hive

Copy link
Copy Markdown
Contributor

merged by Hive trusted-author auto-merge: author @clubanderson holds role owner and GitHub permission admin on repo; CI green at e8f9e3d.

@kubestellar-prow
kubestellar-prow Bot deleted the fix/agents-refresh-scroll-jump branch October 15, 2026 21:18
@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution! Your PR has been merged.

We'd love to hear how your experience was: share feedback

hivecommons-hive Bot pushed a commit that referenced this pull request Oct 16, 2026
… stable on errors (#12518)

The spoke dashboard jumped every SSE tick while scrolled. renderCost rebuilt
#cost-panel via innerHTML with its sub-tables expanded, forced layout in
applyCostCollapse β†’ replaySparklinesIn, and only then re-collapsed them;
Chrome scroll anchoring moved scrollY by the transient delta and rode the
200ms max-height transition back. renderDebugSection and renderAuditTable
used the same innerHTML-then-recollapse pattern.

- Render collapsed state into markup (sectionCardShell/sectionCardHeader
  collapsed option, cost sub-table collapsed classes) and patch sections in
  place with morphInnerHtml (morphDomNode from #12209) so no transient
  height change occurs; re-apply sub-collapse before the panel collapse.
- Derive /api/pane polling from the live agent list: skip disabled/stopped
  agents and park an agent after a 404 until its state changes, removing
  the /api/pane/{guide,quality} 404 stream.
- Tests for candidate derivation, in-place patching and collapsed markup.

Closes #12512

Signed-off-by: Andy Anderson <andy@clubanderson.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-signoff: yes Indicates the PR's author has signed the DCO. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dashboard: AGENTS section refresh shifts scroll position (page jumps every poll, Safari)

1 participant