Skip to content

Commit 1a6c38e

Browse files
committed
preserve scroll position across auto-refresh
1 parent 3e4a1c5 commit 1a6c38e

File tree

1 file changed

+20
-1
lines changed

1 file changed

+20
-1
lines changed

src/browser/components/RightSidebar/CodeReview/ReviewPanel.tsx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ export const ReviewPanel: React.FC<ReviewPanelProps> = ({
182182
}) => {
183183
const { api } = useAPI();
184184
const panelRef = useRef<HTMLDivElement>(null);
185+
const scrollContainerRef = useRef<HTMLDivElement>(null);
185186
const searchInputRef = useRef<HTMLInputElement>(null);
186187

187188
// Unified diff state - discriminated union makes invalid states unrepresentable
@@ -248,6 +249,9 @@ export const ReviewPanel: React.FC<ReviewPanelProps> = ({
248249
const isUserInteractingRef = useRef(false);
249250
const pendingRefreshRef = useRef(false);
250251

252+
// Save scroll position before refresh to restore after
253+
const savedScrollTopRef = useRef<number | null>(null);
254+
251255
const [filters, setFilters] = useState<ReviewFiltersType>({
252256
showReadHunks: showReadHunks,
253257
diffBase: diffBase,
@@ -274,6 +278,9 @@ export const ReviewPanel: React.FC<ReviewPanelProps> = ({
274278
// Skip if already refreshing (for origin/* bases with fetch)
275279
if (isRefreshingRef.current) return;
276280

281+
// Save scroll position before refresh
282+
savedScrollTopRef.current = scrollContainerRef.current?.scrollTop ?? null;
283+
277284
const originBranch = getOriginBranchForFetch(filters.diffBase);
278285
if (originBranch) {
279286
// Remote base: fetch before refreshing diff
@@ -325,6 +332,18 @@ export const ReviewPanel: React.FC<ReviewPanelProps> = ({
325332
}
326333
}, [isPanelFocused]);
327334

335+
// Restore scroll position after auto-refresh completes
336+
useEffect(() => {
337+
if (
338+
diffState.status === "loaded" &&
339+
savedScrollTopRef.current !== null &&
340+
scrollContainerRef.current
341+
) {
342+
scrollContainerRef.current.scrollTop = savedScrollTopRef.current;
343+
savedScrollTopRef.current = null;
344+
}
345+
}, [diffState.status]);
346+
328347
// Focus panel when focusTrigger changes (preserves current hunk selection)
329348

330349
const handleRefreshRef = useRef<() => void>(() => {
@@ -989,7 +1008,7 @@ export const ReviewPanel: React.FC<ReviewPanelProps> = ({
9891008
</div>
9901009

9911010
{/* Single scrollable area containing both file tree and hunks */}
992-
<div className="flex min-h-0 flex-1 flex-col overflow-y-auto">
1011+
<div ref={scrollContainerRef} className="flex min-h-0 flex-1 flex-col overflow-y-auto">
9931012
{/* FileTree at the top */}
9941013
{(fileTree ?? isLoadingTree) && (
9951014
<div className="border-border-light flex w-full flex-[0_0_auto] flex-col overflow-hidden border-b">

0 commit comments

Comments
 (0)