Skip to content

fix(file-viewer): prevent scroll jump to top during Mothership streaming#4559

Merged
waleedlatif1 merged 9 commits into
stagingfrom
fix/fil
May 12, 2026
Merged

fix(file-viewer): prevent scroll jump to top during Mothership streaming#4559
waleedlatif1 merged 9 commits into
stagingfrom
fix/fil

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

Summary

  • Fix root cause of scroll jump: MarkdownCheckboxCtx.Provider was conditionally rendered around the scroll container, causing it to unmount/remount (and reset scrollTop to 0) every time streaming started
  • Add useScrollAnchor hook with a spacer element that inflates scrollHeight to prevent the browser from clamping scrollTop when streamed content temporarily shrinks
  • Linger activeSessionId on complete so streamingContent never becomes undefined between two consecutive Mothership tool calls on the same file
  • Gate session activation in upsert on the incoming session having renderable content, preventing a blank flash when a new session starts before its first chunk arrives
  • Fix shouldShowStreamingFilePanel to keep the panel mounted while the lingered session is active
  • Fix use-chat post-write navigation condition to work with lingered completed sessions
  • Fix useAutoScroll to check proximity before pinning to bottom on stream start (prevents unwanted jump-to-bottom in the chat panel)

Type of Change

  • Bug fix

Testing

Tested manually — scrolled to middle of a file, asked Mothership to make multi-step edits. Scroll position preserved across tool call boundaries. Also verified single patch, fresh write, and cross-file edits all behave correctly.

Unit tests added:

  • use-scroll-anchor.test.ts: 15 tests for computeSpacerShortage pure function
  • use-file-preview-sessions.test.tsx: 7 new tests for linger, content-gate, and edge cases
  • text-editor-state.test.ts: 5 new tests for inter-session content shrink scenario

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

- Fix root cause: MarkdownCheckboxCtx.Provider was conditionally rendered,
  causing the scroll container to unmount/remount when isStreaming flipped,
  resetting scrollTop to 0 on every stream start
- Add useScrollAnchor hook with spacer element to preserve scroll position
  when streamed content temporarily shrinks the scroll container
- Linger active session ID on complete to prevent streamingContent→undefined
  flicker between consecutive tool calls on the same file
- Gate upsert activation on incoming session having renderable content
- Fix shouldShowStreamingFilePanel to keep panel mounted during linger
- Fix use-chat post-write navigation to work with lingered completed session
- Fix useAutoScroll to check proximity before pinning to bottom on stream start
@vercel
Copy link
Copy Markdown

vercel Bot commented May 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped May 12, 2026 0:38am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented May 11, 2026

PR Summary

Medium Risk
Medium risk because it changes streaming preview session activation/linger behavior and introduces new scroll anchoring logic that could affect viewer/chat scrolling and resource navigation edge cases.

Overview
Prevents the file viewer from jumping to the top during Mothership streaming by keeping the markdown scroll container mounted (always rendering MarkdownCheckboxCtx.Provider) and replacing useAutoScroll with a new useScrollAnchor + spacer element to preserve scrollTop when replace-mode chunks temporarily shrink content.

Updates file preview session state so activeSessionId lingers on a completed session until a successor with renderable content arrives (including updated hydrate/upsert selection rules), and adjusts Mothership view/chat navigation conditions to match this lingered-complete behavior.

Refines useAutoScroll to only pin to bottom on stream start when already near the bottom, and adds focused unit tests covering inter-session shrink scenarios, scroll-anchor calculations, and preview-session reducer edge cases.

Reviewed by Cursor Bugbot for commit 791f76a. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 11, 2026

Greptile Summary

This PR fixes a scroll-jump bug in the Mothership file-viewer that occurs between consecutive streaming tool calls. The root causes were a conditionally-rendered context provider unmounting the scroll container on every stream start, and activeSessionId resetting to null between tool calls (collapsing streamingContent to undefined).

  • MarkdownCheckboxCtx.Provider is now always rendered (removing the conditional that caused the scroll container to unmount/remount and reset scrollTop to 0 on each stream start).
  • Session linger: activeSessionId is held on the most-recently-completed session until a successor with renderable content upserts, keeping streamingContent non-undefined across tool-call boundaries; hydrate and upsert(activate:false) also preserve the linger via successor ?? state.activeSessionId.
  • useScrollAnchor replaces useAutoScroll in MarkdownPreview; a spacer div inflates scrollHeight to prevent the browser clamping scrollTop when replace-mode streaming temporarily produces shorter content, and useAutoScroll is patched to not jump-to-bottom in the chat panel unless the user is already near the bottom.

Confidence Score: 5/5

This PR is safe to merge — all changes are scoped to the file-viewer and chat scroll paths, and each fix is independently tested.

The root causes are addressed at both the React tree level (unconditional MarkdownCheckboxCtx.Provider) and the state-machine level (linger preserves activeSessionId across tool-call gaps). The useScrollAnchor spacer logic is pure-function-testable and well-covered. Previously-flagged issues with linger clearance in hydrate and upsert(activate:false) were resolved before this review. No new auth, data, or API surface is touched.

No files require special attention. The most complex new file is use-scroll-anchor.ts, and its pure helpers are thoroughly unit-tested.

Important Files Changed

Filename Overview
apps/sim/hooks/use-scroll-anchor.ts New hook that anchors scroll position during streaming via a spacer element; exposes pure helpers computeSpacerShortage and shouldReengage that are well-covered by unit tests. Logic is sound.
apps/sim/app/workspace/[workspaceId]/home/hooks/use-file-preview-sessions.ts Session-linger logic added to complete, hydrate, and upsert cases; previously-flagged issues with linger clearance now resolved with successor ?? state.activeSessionId pattern throughout.
apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/preview-panel.tsx Switches from useAutoScroll to useScrollAnchor, adds the spacer <div>, and unconditionally wraps body in MarkdownCheckboxCtx.Provider to fix the unmount/remount root cause.
apps/sim/hooks/use-auto-scroll.ts Stream-start now checks proximity before pinning to bottom, preventing unwanted jump-to-bottom in the chat panel when the user has scrolled up.
apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/mothership-view.tsx shouldShowStreamingFilePanel now keeps the panel mounted when a lingered completed session has renderable content, aligning with the new linger semantics.
apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts Post-write navigation condition extended to fire when the preview session is in a lingered completed state, not only when activePreviewSessionIdRef is null.

Reviews (4): Last reviewed commit: "chore(file-viewer): trim verbose inline ..." | Re-trigger Greptile

Comment thread apps/sim/hooks/use-scroll-anchor.ts Outdated
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 77f6364. Configure here.

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/hooks/use-scroll-anchor.ts
Pulls the spacer-guard re-engage condition out of onScroll into an
exported pure function so the false-re-engage invariant (spacer active
→ no re-engage) is covered by automated tests rather than relying on
manual QA. Adds 8 unit tests for shouldReengage alongside the existing
15 for computeSpacerShortage.
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 791f76a. Configure here.

@waleedlatif1 waleedlatif1 merged commit b7c34d4 into staging May 12, 2026
13 checks passed
@waleedlatif1 waleedlatif1 deleted the fix/fil branch May 12, 2026 00:49
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.

1 participant