Files
dify/web/app/components/workflow/skill/file-tree/tree-context-menu.tsx
yyh 783cdb1357 feat(skill): add inline rename and guide lines to file tree
Add TreeEditInput component for inline file/folder renaming with keyboard
support (Enter to submit, Escape to cancel). Add TreeGuideLines component
to render vertical indent lines based on node depth for better visual
hierarchy in the tree view.

Reorganize file tree components into dedicated `file-tree` subdirectory
for better code organization.
2026-01-15 21:30:02 +08:00

73 lines
1.9 KiB
TypeScript

'use client'
import type { FC } from 'react'
import type { TreeApi } from 'react-arborist'
import type { TreeNodeData } from '../type'
import { useClickAway } from 'ahooks'
import * as React from 'react'
import { useCallback, useMemo, useRef } from 'react'
import { useSkillAssetTreeData } from '../hooks/use-skill-asset-tree'
import { useSkillEditorStore, useSkillEditorStoreApi } from '../store'
import { findNodeById } from '../utils/tree-utils'
import FileNodeMenu from './file-node-menu'
import FolderNodeMenu from './folder-node-menu'
type TreeContextMenuProps = {
treeRef: React.RefObject<TreeApi<TreeNodeData> | null>
}
const TreeContextMenu: FC<TreeContextMenuProps> = ({ treeRef }) => {
const ref = useRef<HTMLDivElement>(null)
const contextMenu = useSkillEditorStore(s => s.contextMenu)
const storeApi = useSkillEditorStoreApi()
const { data: treeData } = useSkillAssetTreeData()
const handleClose = useCallback(() => {
storeApi.getState().setContextMenu(null)
}, [storeApi])
useClickAway(() => {
handleClose()
}, ref)
const targetNode = useMemo(() => {
if (!contextMenu?.nodeId || !treeData?.children)
return null
return findNodeById(treeData.children, contextMenu.nodeId)
}, [contextMenu?.nodeId, treeData?.children])
const isFolder = targetNode?.node_type === 'folder'
if (!contextMenu)
return null
return (
<div
ref={ref}
className="fixed z-[100]"
style={{
top: contextMenu.top,
left: contextMenu.left,
}}
>
{isFolder
? (
<FolderNodeMenu
nodeId={contextMenu.nodeId}
onClose={handleClose}
treeRef={treeRef}
/>
)
: (
<FileNodeMenu
nodeId={contextMenu.nodeId}
onClose={handleClose}
treeRef={treeRef}
/>
)}
</div>
)
}
export default React.memo(TreeContextMenu)