Fix agent manager diff viewer collapse and scroll reset (#6406)

* Fix file view collapse regressions

* Fix agent manager diff viewer collapse and scroll reset bugs

Reset openInit flag when switching sessions via a new sessionKey prop so
diff files auto-expand for each session instead of staying collapsed.

Stabilize diff data references during 2.5s polling to prevent <For> from
tearing down and rebuilding <Diff> components, which destroyed scroll
position. Guard setOpen in the auto-open effect to skip updates when the
file list is unchanged.

* remove package.json
This commit is contained in:
Marius
2026-02-26 23:37:22 +01:00
committed by GitHub
parent 5f2a5c6906
commit 71cef2267b
3 changed files with 60 additions and 3 deletions
@@ -934,7 +934,24 @@ const AgentManagerContent: Component = () => {
if (msg.type === "agentManager.worktreeDiff") {
const ev = msg as AgentManagerWorktreeDiffMessage
setDiffDatas((prev) => ({ ...prev, [ev.sessionId]: ev.diffs }))
setDiffDatas((prev) => {
const existing = prev[ev.sessionId]
// Reuse previous array reference when content is unchanged to prevent
// <For> from tearing down / rebuilding <Diff> components (which resets scroll)
if (existing && existing.length === ev.diffs.length) {
const same = existing.every((old, i) => {
const next = ev.diffs[i]!
return (
old.file === next.file &&
old.before === next.before &&
old.after === next.after &&
old.status === next.status
)
})
if (same) return prev
}
return { ...prev, [ev.sessionId]: ev.diffs }
})
}
if (msg.type === "agentManager.worktreeDiffLoading") {
@@ -2059,6 +2076,7 @@ const AgentManagerContent: Component = () => {
<DiffPanel
diffs={diffDatas()[selection() === LOCAL ? LOCAL : (session.currentSessionID() ?? "")] ?? []}
loading={diffLoading()}
sessionKey={selection() === LOCAL ? LOCAL : (session.currentSessionID() ?? "")}
diffStyle={reviewDiffStyle()}
onDiffStyleChange={setSharedDiffStyle}
comments={reviewComments()}
@@ -2080,6 +2098,7 @@ const AgentManagerContent: Component = () => {
<FullScreenDiffView
diffs={reviewDiffs()}
loading={diffLoading()}
sessionKey={selection() === LOCAL ? LOCAL : (session.currentSessionID() ?? "")}
comments={reviewComments()}
onCommentsChange={setReviewCommentsForSelection}
onSendAll={closeReviewTab}
@@ -27,6 +27,7 @@ import { buildReviewAnnotation, type AnnotationLabels, type AnnotationMeta } fro
interface DiffPanelProps {
diffs: WorktreeFileDiff[]
loading: boolean
sessionKey?: string
diffStyle?: "unified" | "split"
onDiffStyleChange?: (style: "unified" | "split") => void
comments: ReviewComment[]
@@ -111,13 +112,31 @@ export const DiffPanel: Component<DiffPanelProps> = (props) => {
focusRoot()
}
// Reset auto-open state when switching sessions so diffs expand for the new session
createEffect(
on(
() => props.sessionKey,
() => {
setOpenInit(false)
},
{ defer: true },
),
)
// Auto-open files when diffs arrive
createEffect(
on(
() => props.diffs,
(diffs) => {
const files = diffs.map((d) => d.file)
setOpen((prev) => prev.filter((file) => files.includes(file)))
const fileSet = new Set(files)
// Only update open state when the file list actually changed to avoid
// unnecessary re-renders that reset scroll position during polling
setOpen((prev) => {
const filtered = prev.filter((file) => fileSet.has(file))
if (filtered.length === prev.length && prev.every((f) => fileSet.has(f))) return prev
return filtered
})
if (openInit()) return
if (diffs.length === 0) return
if (diffs.length <= 15) setOpen(files)
@@ -29,6 +29,7 @@ type DiffStyle = "unified" | "split"
interface FullScreenDiffViewProps {
diffs: WorktreeFileDiff[]
loading: boolean
sessionKey?: string
comments: ReviewComment[]
onCommentsChange: (comments: ReviewComment[]) => void
onSendAll?: () => void
@@ -104,13 +105,31 @@ export const FullScreenDiffView: Component<FullScreenDiffViewProps> = (props) =>
focusRoot()
}
// Reset auto-open state when switching sessions so diffs expand for the new session
createEffect(
on(
() => props.sessionKey,
() => {
setOpenInit(false)
},
{ defer: true },
),
)
// Auto-open files when diffs arrive
createEffect(
on(
() => props.diffs,
(diffs) => {
const files = diffs.map((d) => d.file)
setOpen((prev) => prev.filter((file) => files.includes(file)))
const fileSet = new Set(files)
// Only update open state when the file list actually changed to avoid
// unnecessary re-renders that reset scroll position during polling
setOpen((prev) => {
const filtered = prev.filter((file) => fileSet.has(file))
if (filtered.length === prev.length && prev.every((f) => fileSet.has(f))) return prev
return filtered
})
if (diffs.length === 0) {
setActiveFile(null)
return