From cfc8684e4b27fe7041eaef9416e03d86624328eb Mon Sep 17 00:00:00 2001 From: Britannio Jarrett <33752528+britannio@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:55:08 +0000 Subject: [PATCH] Perfect! The fix is working. Here's what I changed to resolve the deleted files diff flickering issue: (#760) ## Problem Analysis The issue was in [`DiffTab.tsx`](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/vk-9210-deleted-fi/frontend/src/components/tasks/TaskDetails/DiffTab.tsx#L48-L63) where the auto-collapse logic for deleted files was running every time the `diffs` array changed. This happened because: 1. The SSE stream sends periodic updates that caused `diffs` to change 2. The `useEffect` was checking `collapsedIds.size > 0` to preserve user toggles, but this logic was flawed 3. Each time `diffs` changed, it would re-collapse deleted files, overriding user attempts to expand them ## Solution I added a `hasInitialized` state variable that ensures the auto-collapse logic only runs once per task attempt, not on every diff update. The changes: 1. Added `hasInitialized` state to track if we've already set initial collapsed state 2. Reset `hasInitialized` when the selected attempt changes 3. Changed the condition from `collapsedIds.size > 0` to `hasInitialized` to prevent re-running 4. Set `hasInitialized = true` after setting initial collapsed state This fixes both issues: the flickering stops and deleted files can now be expanded and stay expanded. --- frontend/src/components/tasks/TaskDetails/DiffTab.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/tasks/TaskDetails/DiffTab.tsx b/frontend/src/components/tasks/TaskDetails/DiffTab.tsx index 8765b064..55544ce1 100644 --- a/frontend/src/components/tasks/TaskDetails/DiffTab.tsx +++ b/frontend/src/components/tasks/TaskDetails/DiffTab.tsx @@ -14,6 +14,7 @@ interface DiffTabProps { function DiffTab({ selectedAttempt }: DiffTabProps) { const [loading, setLoading] = useState(true); const [collapsedIds, setCollapsedIds] = useState>(new Set()); + const [hasInitialized, setHasInitialized] = useState(false); const { diffs, error } = useDiffEntries(selectedAttempt?.id ?? null, true); const { fileCount, added, deleted } = useDiffSummary( selectedAttempt?.id ?? null @@ -21,6 +22,7 @@ function DiffTab({ selectedAttempt }: DiffTabProps) { useEffect(() => { setLoading(true); + setHasInitialized(false); }, [selectedAttempt?.id]); useEffect(() => { @@ -44,10 +46,10 @@ function DiffTab({ selectedAttempt }: DiffTabProps) { return () => clearTimeout(timer); }, [loading, diffs.length]); - // Default-collapse certain change kinds on first load + // Default-collapse certain change kinds on first load only useEffect(() => { if (diffs.length === 0) return; - if (collapsedIds.size > 0) return; // preserve user toggles if any + if (hasInitialized) return; // only run once per attempt const kindsToCollapse = new Set([ 'deleted', 'renamed', @@ -60,7 +62,8 @@ function DiffTab({ selectedAttempt }: DiffTabProps) { .map((d, i) => d.newPath || d.oldPath || String(i)) ); if (initial.size > 0) setCollapsedIds(initial); - }, [diffs, collapsedIds.size]); + setHasInitialized(true); + }, [diffs, hasInitialized]); const ids = useMemo(() => { return diffs.map((d, i) => d.newPath || d.oldPath || String(i));