Skip to content

Commit cb781ff

Browse files
committed
diff-overlay: reload on filePath change
1 parent f99122d commit cb781ff

File tree

2 files changed

+63
-2
lines changed

2 files changed

+63
-2
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { describe, it, expect, vi, beforeEach } from 'vitest';
2+
import { render, waitFor } from '@testing-library/react';
3+
import { DiffOverlay } from './DiffOverlay';
4+
import { API } from '../../utils/api';
5+
6+
vi.mock('../../utils/api', () => ({
7+
API: {
8+
sessions: {
9+
getDiff: vi.fn(),
10+
getFileContent: vi.fn(),
11+
},
12+
},
13+
}));
14+
15+
describe('DiffOverlay', () => {
16+
beforeEach(() => {
17+
vi.clearAllMocks();
18+
(API.sessions.getDiff as any).mockResolvedValue({ success: true, data: { diff: '' } });
19+
(API.sessions.getFileContent as any).mockResolvedValue({ success: true, data: { content: 'a\nb\nc' } });
20+
});
21+
22+
it('reloads when filePath changes while open', async () => {
23+
const props = {
24+
isOpen: true,
25+
sessionId: 's1',
26+
filePath: 'a.txt',
27+
target: { kind: 'working', scope: 'all' } as any,
28+
onClose: vi.fn(),
29+
files: [],
30+
};
31+
32+
const { rerender } = render(<DiffOverlay {...(props as any)} />);
33+
34+
await waitFor(() => {
35+
expect(API.sessions.getFileContent).toHaveBeenCalledWith('s1', expect.objectContaining({ filePath: 'a.txt' }));
36+
});
37+
38+
rerender(<DiffOverlay {...({ ...props, filePath: 'b.txt' } as any)} />);
39+
40+
await waitFor(() => {
41+
expect(API.sessions.getFileContent).toHaveBeenCalledWith('s1', expect.objectContaining({ filePath: 'b.txt' }));
42+
});
43+
});
44+
});
45+

packages/ui/src/components/layout/DiffOverlay.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ export const DiffOverlay: React.FC<DiffOverlayProps> = React.memo(({
149149
};
150150

151151
loadDiff();
152-
}, [isOpen, sessionId, target, onClose]);
152+
}, [isOpen, sessionId, target, filePath, onClose]);
153153

154154
const handleRefresh = useCallback(async () => {
155155
if (!sessionId || !target) return;
@@ -172,6 +172,22 @@ export const DiffOverlay: React.FC<DiffOverlayProps> = React.memo(({
172172
setDiff(allRes.data?.diff ?? '');
173173
setStagedDiff(stagedRes.data?.diff ?? '');
174174
setUnstagedDiff(unstagedRes.data?.diff ?? '');
175+
176+
// Keep full-file rendering stable during refresh as well.
177+
const preferredRef = target.scope === 'untracked' ? 'WORKTREE' : 'HEAD';
178+
let sourceRes = await withTimeout(
179+
API.sessions.getFileContent(sessionId, { filePath, ref: preferredRef, maxBytes: 1024 * 1024 }),
180+
15_000,
181+
'Load file content'
182+
);
183+
if (!sourceRes.success && preferredRef !== 'WORKTREE') {
184+
sourceRes = await withTimeout(
185+
API.sessions.getFileContent(sessionId, { filePath, ref: 'WORKTREE', maxBytes: 1024 * 1024 }),
186+
15_000,
187+
'Load file content'
188+
);
189+
}
190+
setFileSource(sourceRes.success ? (sourceRes.data?.content ?? '') : '');
175191
} else {
176192
const response = await withTimeout(API.sessions.getDiff(sessionId, target), 15_000, 'Load diff');
177193
if (response.success && response.data) {
@@ -196,7 +212,7 @@ export const DiffOverlay: React.FC<DiffOverlayProps> = React.memo(({
196212
} finally {
197213
setLoading(false);
198214
}
199-
}, [sessionId, target, onClose]);
215+
}, [sessionId, target, filePath, onClose]);
200216

201217
const handleCopyPath = useCallback(async () => {
202218
if (!filePath) return;

0 commit comments

Comments
 (0)