Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2d8cce5
feat(agent-file-preview): show previews in files overlay
AtomsH4 Jul 3, 2026
46089c1
fix(agent-file-preview): gate file tree model by pane state
AtomsH4 Jul 4, 2026
2685558
fix(agent-file-preview): clear stale overlay selections
AtomsH4 Jul 4, 2026
1da9eae
fix(file-tree): allow context menu bubbling
AtomsH4 Jul 4, 2026
18565f8
fix(agent-file-preview): focus overlay previews
AtomsH4 Jul 4, 2026
41b87d8
Merge remote-tracking branch 'origin/main' into feat/file-preview-ove…
AtomsH4 Jul 4, 2026
29ca171
Merge branch 'main' into feat/file-preview-overlay
AtomsH4 Jul 4, 2026
97a260a
Merge branch 'main' into feat/file-preview-overlay
AtomsH4 Jul 4, 2026
24af41c
fix(agent-file-preview): clear stale standalone overlays
AtomsH4 Jul 5, 2026
d693f62
fix(agent-file-preview): gate file tree by active tab
AtomsH4 Jul 5, 2026
2e186c3
refactor(artifact-pane): simplify file preview overlay
AtomsH4 Jul 5, 2026
287f5f9
Merge remote-tracking branch 'origin/main' into feat/file-preview-ove…
AtomsH4 Jul 6, 2026
988773a
docs(file-docs): revert unrelated reference link updates
AtomsH4 Jul 6, 2026
81eb5d4
fix(command-menu): stop nested context menu bubbling
AtomsH4 Jul 6, 2026
74d64c3
docs(agent-file-preview): update overlay docs
AtomsH4 Jul 6, 2026
764a42c
Merge branch 'main' into feat/file-preview-overlay
AtomsH4 Jul 6, 2026
633c7f1
chore(file-preview-overlay): merge main
AtomsH4 Jul 6, 2026
28d38dc
Merge branch 'main' into feat/file-preview-overlay
AtomsH4 Jul 6, 2026
0ff2151
Merge branch 'main' into feat/file-preview-overlay
AtomsH4 Jul 6, 2026
5082ce5
Merge branch 'main' into feat/file-preview-overlay
0xfullex Jul 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 27 additions & 22 deletions src/renderer/components/FileTree/FileTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export function FileTree(props: FileTreeProps) {
searchKeyword = '',
onSearchKeywordChange,
searchPlaceholder,
searchToolbar,
searchClearLabel,
emptyState
} = props

Expand Down Expand Up @@ -114,28 +116,31 @@ export function FileTree(props: FileTreeProps) {

return (
<div className="flex h-full min-h-0 flex-col">
<div className="relative px-2 py-2">
<Search
size={14}
className="-translate-y-1/2 pointer-events-none absolute top-1/2 left-4 text-muted-foreground"
/>
<Input
type="text"
value={searchKeyword}
onChange={(e) => onSearchKeywordChange?.(e.target.value)}
placeholder={searchPlaceholder}
className="h-8 pr-7 pl-7 text-sm"
data-testid="file-tree-search-input"
/>
{searchKeyword && (
<button
type="button"
aria-label="Clear search"
onClick={() => onSearchKeywordChange?.('')}
className="-translate-y-1/2 absolute top-1/2 right-3 flex size-5 cursor-pointer items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground">
<X size={13} />
</button>
)}
<div className="flex items-center gap-2 px-2 py-2">
<div className="relative min-w-0 flex-1">
<Search
size={14}
className="-translate-y-1/2 pointer-events-none absolute top-1/2 left-2 text-muted-foreground"
/>
<Input
type="text"
value={searchKeyword}
onChange={(e) => onSearchKeywordChange?.(e.target.value)}
placeholder={searchPlaceholder}
className="h-8 min-w-0 flex-1 pr-7 pl-7 text-sm"
data-testid="file-tree-search-input"
/>
{searchKeyword && (
<button
type="button"
aria-label={searchClearLabel ?? 'Clear search'}
onClick={() => onSearchKeywordChange?.('')}
className="-translate-y-1/2 absolute top-1/2 right-1 flex size-5 cursor-pointer items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground">
<X size={13} />
</button>
)}
</div>
{searchToolbar}
</div>
<div className="min-h-0 flex-1">{tree}</div>
</div>
Expand Down
33 changes: 32 additions & 1 deletion src/renderer/components/FileTree/__tests__/FileTree.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,15 @@ describe('FileTree - icon behaviour', () => {

describe('FileTree - search box', () => {
it('does not render the search input when showSearch is omitted', () => {
render(<FileTree nodes={nodes} renderList={passthroughRenderList} />)
render(
<FileTree
nodes={nodes}
searchToolbar={<span data-testid="search-toolbar">Tools</span>}
renderList={passthroughRenderList}
/>
)
expect(screen.queryByTestId('file-tree-search-input')).toBeNull()
expect(screen.queryByTestId('search-toolbar')).toBeNull()
})

it('renders the search input when showSearch is true', () => {
Expand Down Expand Up @@ -290,6 +297,30 @@ describe('FileTree - search box', () => {
expect(onSearchKeywordChange).toHaveBeenCalledWith('a')
})

it('renders the search toolbar and keeps the clear button usable', async () => {
const onSearchKeywordChange = vi.fn()
const user = userEvent.setup()
render(
<FileTree
nodes={nodes}
showSearch
searchKeyword="abc"
searchClearLabel="Clear files search"
searchToolbar={
<button type="button" data-testid="search-toolbar">
Refresh
</button>
}
onSearchKeywordChange={onSearchKeywordChange}
renderList={passthroughRenderList}
/>
)

expect(screen.getByTestId('search-toolbar')).toBeInTheDocument()
await user.click(screen.getByLabelText('Clear files search'))
expect(onSearchKeywordChange).toHaveBeenCalledWith('')
})

it('clears the keyword via the clear button', async () => {
const onSearchKeywordChange = vi.fn()
const user = userEvent.setup()
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/components/FileTree/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ export interface FileTreeProps {
onSearchKeywordChange?: (keyword: string) => void
/** Placeholder for the search input. */
searchPlaceholder?: string
/** Optional trailing toolbar rendered on the search row. */
searchToolbar?: React.ReactNode
/** Accessible label for the search clear button. */
searchClearLabel?: string

emptyState?: React.ReactNode
}
Loading
Loading