diff --git a/packages/web-ui/src/sections/Document/Sidebar/Files/index.tsx b/packages/web-ui/src/sections/Document/Sidebar/Files/index.tsx index d547f2d35..ceccaef15 100644 --- a/packages/web-ui/src/sections/Document/Sidebar/Files/index.tsx +++ b/packages/web-ui/src/sections/Document/Sidebar/Files/index.tsx @@ -92,39 +92,36 @@ function FolderHeader({ node, open, indentation, + onToggleOpen, }: { node: Node open: boolean indentation: IndentType[] + onToggleOpen: () => void }) { const inputRef = useRef(null) const nodeRef = useRef(null) const { onDeleteFolder } = useFileTreeContext() - const { addFolder, updateFolder, deleteTmpFolder } = useTempNodes((state) => ({ - addFolder: state.addFolder, - updateFolder: state.updateFolder, - deleteTmpFolder: state.deleteTmpFolder, - })) + const { addFolder, updateFolder, deleteTmpFolder } = useTempNodes( + (state) => ({ + addFolder: state.addFolder, + updateFolder: state.updateFolder, + deleteTmpFolder: state.deleteTmpFolder, + }), + ) const { isEditing, error, onInputChange, onInputKeyDown } = useNodeValidator({ node, nodeRef, inputRef, saveValue: ({ path }: { path: string }) => { - updateFolder({ path }) + updateFolder({ path, id: node.id }) }, leaveWithoutSave: () => { deleteTmpFolder({ id: node.id }) }, }) - const togglePath = useOpenPaths((state) => state.togglePath) const FolderIcon = open ? Icons.folderOpen : Icons.folderClose const ChevronIcon = open ? Icons.chevronDown : Icons.chevronRight - const onTooglePath = useCallback(() => { - const lastSegment = node.path.split('/').pop() - if (lastSegment === '' || lastSegment === ' ') return - - togglePath(node.path) - }, [togglePath, node.path, node.isPersisted]) const options = useMemo( () => [ { @@ -135,7 +132,7 @@ function FolderHeader({ }, { label: 'New Prompt', - onClick: () => {}, + onClick: () => { }, }, { label: 'Delete folder', @@ -156,7 +153,7 @@ function FolderHeader({ >
@@ -252,16 +249,19 @@ function FileHeader({ function NodeHeader({ selected, - node, open, + onToggleOpen, + node, indentation, }: { selected: boolean - node: Node open: boolean + node: Node indentation: IndentType[] + onToggleOpen: () => void }) { if (node.isRoot) return null + if (node.isFile) { return ( + return ( + + ) } function FileNode({ @@ -287,12 +294,28 @@ function FileNode({ const tmpNodes = allTmpFolders[node.path] ?? [] const { currentPath } = useFileTreeContext() const [selected, setSelected] = useState(currentPath === node.path) - const openPaths = useOpenPaths((state) => state.openPaths) - const open = node.isRoot || openPaths.includes(node.path) const lastIdx = node.children.length - 1 + const { togglePath, openPaths } = useOpenPaths((state) => ({ + openPaths: state.openPaths, + togglePath: state.togglePath, + })) + const open = !!openPaths[node.path] + const onToggleOpen = useCallback(() => { + const lastSegment = node.path.split('/').pop() + if (lastSegment === '' || lastSegment === ' ') return + + togglePath(node.path) + }, [togglePath, node.path, node.isPersisted]) + useEffect(() => { setSelected(currentPath === node.path) }, [currentPath]) + + if (node.path === 'some-folder/doc2') { + console.log("OPEN_PATHS", openPaths) + console.log('some-folder/doc2 isOpen', open) + } + return (
{node.isFile ? null : ( diff --git a/packages/web-ui/src/sections/Document/Sidebar/Files/useOpenPaths/index.test.ts b/packages/web-ui/src/sections/Document/Sidebar/Files/useOpenPaths/index.test.ts index fa560f4d5..6b052b73f 100644 --- a/packages/web-ui/src/sections/Document/Sidebar/Files/useOpenPaths/index.test.ts +++ b/packages/web-ui/src/sections/Document/Sidebar/Files/useOpenPaths/index.test.ts @@ -4,21 +4,20 @@ import { describe, expect, it } from 'vitest' import { useOpenPaths } from './index' describe('useOpenPaths', () => { - it('shout add the paths', async () => { + it.only('shout add the paths', async () => { const { result } = renderHook(() => useOpenPaths((state) => state)) act(() => { result.current.togglePath('some-folder/nested-folder/doc1') }) - expect(result.current.openPaths).toEqual([ - '', - 'some-folder', - 'some-folder/nested-folder', - 'some-folder/nested-folder/doc1', - ]) + expect(result.current.openPaths).toEqual({ + 'some-folder': true, + 'some-folder/nested-folder': true, + 'some-folder/nested-folder/doc1': true, + }) }) - it('shout remove nested paths', async () => { + it('should close nested-folder', async () => { const { result } = renderHook(() => useOpenPaths((state) => state)) act(() => { result.current.togglePath('some-folder/nested-folder/doc1') @@ -27,6 +26,8 @@ describe('useOpenPaths', () => { act(() => { result.current.togglePath('some-folder/nested-folder') }) - expect(result.current.openPaths).toEqual(['', 'some-folder']) + expect(result.current.openPaths).toEqual({ + 'some-folder': true, + }) }) }) diff --git a/packages/web-ui/src/sections/Document/Sidebar/Files/useOpenPaths/index.ts b/packages/web-ui/src/sections/Document/Sidebar/Files/useOpenPaths/index.ts index 3c83bee26..2fdb1fd7a 100644 --- a/packages/web-ui/src/sections/Document/Sidebar/Files/useOpenPaths/index.ts +++ b/packages/web-ui/src/sections/Document/Sidebar/Files/useOpenPaths/index.ts @@ -1,7 +1,7 @@ import { create } from 'zustand' type OpenPathsState = { - openPaths: string[] + openPaths: { [key: string]: boolean } togglePath: (path: string) => void } @@ -12,22 +12,35 @@ function checkIsPathOrDescendant(basePath: string, path: string) { } export const useOpenPaths = create((set) => ({ - openPaths: [''], + openPaths: {}, togglePath: (path: string) => { set((state) => { - const isPathOpen = state.openPaths.includes(path) + const paths = state.openPaths + const isPathOpen = paths[path] + if (!isPathOpen) { const segments = path.split('/') - const newPaths = segments.map((_, idx) => - segments.slice(0, idx + 1).join('/'), + const newPaths = segments.reduce( + (acc, _, idx) => { + const newPath = segments.slice(0, idx + 1).join('/') + return { ...acc, [newPath]: true } + }, + {} as { [key: string]: boolean }, ) return { - openPaths: [...state.openPaths, ...newPaths], + openPaths: { ...paths, ...newPaths }, } } else { - const filteredPaths = state.openPaths.filter( - (p) => !checkIsPathOrDescendant(path, p), + const filteredPaths = Object.keys(paths).reduce( + (acc, p) => { + if (checkIsPathOrDescendant(path, p)) { + return acc + } + + return { ...acc, [p]: true } + }, + {} as { [key: string]: boolean }, ) return {