diff --git a/desktop/src/components/chat/ChatInput.test.tsx b/desktop/src/components/chat/ChatInput.test.tsx index 80185257..cd9953e2 100644 --- a/desktop/src/components/chat/ChatInput.test.tsx +++ b/desktop/src/components/chat/ChatInput.test.tsx @@ -520,7 +520,7 @@ describe('ChatInput file mentions', () => { }, }) - fireEvent.click(await screen.findByText('conditions.py')) + fireEvent.click(await screen.findByText('backend/src/conditions.py')) await waitFor(() => { expect(input.value).toBe('记一下这个文件讲了什么东西。') diff --git a/desktop/src/components/chat/FileSearchMenu.test.tsx b/desktop/src/components/chat/FileSearchMenu.test.tsx index b5a70cef..e44f4569 100644 --- a/desktop/src/components/chat/FileSearchMenu.test.tsx +++ b/desktop/src/components/chat/FileSearchMenu.test.tsx @@ -91,7 +91,7 @@ describe('FileSearchMenu', () => { />, ) - fireEvent.click(await screen.findByText('backend')) + fireEvent.click(await screen.findByText('backend/')) expect(onSelect).toHaveBeenCalledWith('/repo/backend', 'backend', true) expect(onNavigate).not.toHaveBeenCalled() @@ -132,11 +132,36 @@ describe('FileSearchMenu', () => { />, ) - fireEvent.click(await screen.findByText('pictactic')) + fireEvent.click(await screen.findByText('backend/src/pictactic')) expect(onSelect).toHaveBeenCalledWith('/repo/backend/src/pictactic', 'backend/src/pictactic', false) }) + it('renders search results as insertable paths instead of repeated basenames', async () => { + vi.mocked(filesystemApi.search).mockResolvedValueOnce({ + currentPath: '/repo', + parentPath: '/', + query: 'src', + entries: [ + { name: 'src', path: '/repo/src', relativePath: 'src', isDirectory: true }, + { name: 'hooks', path: '/repo/src/hooks', relativePath: 'src/hooks', isDirectory: true }, + { name: 'src', path: '/repo/desktop/src', relativePath: 'desktop/src', isDirectory: true }, + ], + }) + + render( + {}} + />, + ) + + expect(await screen.findByText('src/')).toBeInTheDocument() + expect(screen.getByText('src/hooks/')).toBeInTheDocument() + expect(screen.getByText('desktop/src/')).toBeInTheDocument() + }) + it('uses the resolved home root for typed folder filters when no workspace is selected', async () => { vi.mocked(filesystemApi.search).mockResolvedValueOnce({ currentPath: '/Users/nanmi', @@ -160,7 +185,7 @@ describe('FileSearchMenu', () => { />, ) - expect(await screen.findByText('workspace')).toBeInTheDocument() + expect(await screen.findByText('workspace/')).toBeInTheDocument() rerender( (({ cwd, fi return entry.name }, [cwd, rootPath]) + const getDisplayPath = useCallback((entry: DirEntry) => { + const relativePath = getRelativePath(entry).replace(/\\/g, '/') + if (!entry.isDirectory) return relativePath + return `${relativePath.replace(/\/+$/, '')}/` + }, [getRelativePath]) + const selectEntry = useCallback((entry: DirEntry) => { onSelect(entry.path, getRelativePath(entry), entry.isDirectory) }, [getRelativePath, onSelect]) @@ -194,6 +200,7 @@ export const FileSearchMenu = forwardRef(({ cwd, fi const renderEntry = (entry: DirEntry, index: number) => { const relativePath = getRelativePath(entry) + const displayPath = getDisplayPath(entry) const parentPath = relativePath.split('/').slice(0, -1).join('/') const selected = selectedIndex === index return ( @@ -208,7 +215,9 @@ export const FileSearchMenu = forwardRef(({ cwd, fi {entry.isDirectory ? (