mirror of
https://github.com/langgenius/dify.git
synced 2026-05-03 00:48:04 +08:00
refactor: sync file tree open state
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import type { NodeApi, TreeApi } from 'react-arborist'
|
||||
import type { OpensObject } from './store'
|
||||
import type { TreeNodeData } from './type'
|
||||
import { RiDragDropLine } from '@remixicon/react'
|
||||
import * as React from 'react'
|
||||
@ -15,7 +16,7 @@ import { cn } from '@/utils/classnames'
|
||||
import FileTreeContextMenu from './file-tree-context-menu'
|
||||
import FileTreeNode from './file-tree-node'
|
||||
import { useSkillEditorStore, useSkillEditorStoreApi } from './store'
|
||||
import { getAncestorIds, toOpensObject } from './utils/tree-utils'
|
||||
import { getAncestorIds } from './utils/tree-utils'
|
||||
|
||||
type FilesProps = {
|
||||
className?: string
|
||||
@ -48,7 +49,11 @@ const Files: React.FC<FilesProps> = ({ className }) => {
|
||||
|
||||
const renameNode = useRenameAppAssetNode()
|
||||
|
||||
const initialOpenState = useMemo(() => toOpensObject(expandedFolderIds), [expandedFolderIds])
|
||||
const initialOpensObject = useMemo<OpensObject>(() => {
|
||||
return Object.fromEntries(
|
||||
[...expandedFolderIds].map(id => [id, true]),
|
||||
)
|
||||
}, [expandedFolderIds])
|
||||
|
||||
const handleToggle = useCallback((id: string) => {
|
||||
storeApi.getState().toggleFolder(id)
|
||||
@ -75,31 +80,23 @@ const Files: React.FC<FilesProps> = ({ className }) => {
|
||||
}, [appId, renameNode, t])
|
||||
|
||||
useEffect(() => {
|
||||
if (!activeTabId || !treeData?.children || !treeRef.current)
|
||||
if (!activeTabId || !treeData?.children)
|
||||
return
|
||||
|
||||
const tree = treeRef.current
|
||||
if (!tree)
|
||||
return
|
||||
|
||||
const ancestors = getAncestorIds(activeTabId, treeData.children)
|
||||
|
||||
if (ancestors.length > 0)
|
||||
storeApi.getState().revealFile(ancestors)
|
||||
|
||||
const timeoutId = setTimeout(() => {
|
||||
const tree = treeRef.current
|
||||
if (!tree)
|
||||
return
|
||||
|
||||
for (const ancestorId of ancestors) {
|
||||
const ancestorNode = tree.get(ancestorId)
|
||||
if (ancestorNode && !ancestorNode.isOpen)
|
||||
ancestorNode.open()
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
const node = tree.get(activeTabId)
|
||||
if (node)
|
||||
node.select()
|
||||
}, 0)
|
||||
|
||||
return () => clearTimeout(timeoutId)
|
||||
if (node) {
|
||||
tree.openParents(node)
|
||||
tree.scrollTo(activeTabId)
|
||||
}
|
||||
})
|
||||
}, [activeTabId, treeData?.children, storeApi])
|
||||
|
||||
if (isLoading) {
|
||||
@ -146,8 +143,8 @@ const Files: React.FC<FilesProps> = ({ className }) => {
|
||||
rowHeight={24}
|
||||
indent={20}
|
||||
overscanCount={5}
|
||||
initialOpenState={initialOpenState}
|
||||
selection={activeTabId ?? undefined}
|
||||
initialOpenState={initialOpensObject}
|
||||
onToggle={handleToggle}
|
||||
onActivate={handleActivate}
|
||||
onRename={handleRename}
|
||||
|
||||
@ -65,11 +65,15 @@ export const createTabSlice: StateCreator<TabSliceShape> = (set, get) => ({
|
||||
},
|
||||
})
|
||||
|
||||
export type OpensObject = Record<string, boolean>
|
||||
|
||||
export type FileTreeSliceShape = {
|
||||
expandedFolderIds: Set<string>
|
||||
setExpandedFolderIds: (ids: Set<string>) => void
|
||||
toggleFolder: (folderId: string) => void
|
||||
revealFile: (ancestorFolderIds: string[]) => void
|
||||
setExpandedFromOpens: (opens: OpensObject) => void
|
||||
getOpensObject: () => OpensObject
|
||||
}
|
||||
|
||||
export const createFileTreeSlice: StateCreator<FileTreeSliceShape> = (set, get) => ({
|
||||
@ -96,6 +100,22 @@ export const createFileTreeSlice: StateCreator<FileTreeSliceShape> = (set, get)
|
||||
ancestorFolderIds.forEach(id => newSet.add(id))
|
||||
set({ expandedFolderIds: newSet })
|
||||
},
|
||||
|
||||
setExpandedFromOpens: (opens: OpensObject) => {
|
||||
const newSet = new Set<string>(
|
||||
Object.entries(opens)
|
||||
.filter(([_, isOpen]) => isOpen)
|
||||
.map(([id]) => id),
|
||||
)
|
||||
set({ expandedFolderIds: newSet })
|
||||
},
|
||||
|
||||
getOpensObject: () => {
|
||||
const { expandedFolderIds } = get()
|
||||
return Object.fromEntries(
|
||||
[...expandedFolderIds].map(id => [id, true]),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
export type DirtySliceShape = {
|
||||
|
||||
Reference in New Issue
Block a user