diff --git a/web/app/components/workflow/skill/file-tree/index.tsx b/web/app/components/workflow/skill/file-tree/index.tsx index bae0ecdf18..9be54560ad 100644 --- a/web/app/components/workflow/skill/file-tree/index.tsx +++ b/web/app/components/workflow/skill/file-tree/index.tsx @@ -72,7 +72,7 @@ const FileTree: React.FC = ({ className }) => { handleRootDragOver, handleRootDrop, resetRootDragCounter, - } = useRootFileDrop({ treeChildren }) + } = useRootFileDrop() // Root dropzone highlight (when dragging to root, not to a specific folder) const isRootDropzone = dragOverFolderId === ROOT_ID @@ -200,8 +200,8 @@ const FileTree: React.FC = ({ className }) => { }, [treeChildren]) const renderTreeNode = useCallback((props: NodeRendererProps) => { - return - }, [treeChildren]) + return + }, []) useSyncTreeWithActiveTab({ treeRef, diff --git a/web/app/components/workflow/skill/file-tree/tree-node.tsx b/web/app/components/workflow/skill/file-tree/tree-node.tsx index ed71e357ea..8896d9e6bd 100644 --- a/web/app/components/workflow/skill/file-tree/tree-node.tsx +++ b/web/app/components/workflow/skill/file-tree/tree-node.tsx @@ -20,11 +20,9 @@ import TreeEditInput from './tree-edit-input' import TreeGuideLines from './tree-guide-lines' import { TreeNodeIcon } from './tree-node-icon' -type TreeNodeProps = NodeRendererProps & { - treeChildren: TreeNodeData[] -} +type TreeNodeProps = NodeRendererProps -const TreeNode = ({ node, style, dragHandle, treeChildren }: TreeNodeProps) => { +const TreeNode = ({ node, style, dragHandle }: TreeNodeProps) => { const { t } = useTranslation('workflow') const isFolder = node.data.node_type === 'folder' const isSelected = node.isSelected @@ -77,7 +75,7 @@ const TreeNode = ({ node, style, dragHandle, treeChildren }: TreeNodeProps) => { } = useTreeNodeHandlers({ node }) // Get file drop visual state (for external file uploads) - const { isDragOver: isFileDragOver, isBlinking, dragHandlers } = useFolderFileDrop({ node, treeChildren }) + const { isDragOver: isFileDragOver, isBlinking, dragHandlers } = useFolderFileDrop({ node }) // Combine internal drag target (willReceiveDrop) with external file drag (isFileDragOver) const isDragOver = isFileDragOver || (isFolder && node.willReceiveDrop) diff --git a/web/app/components/workflow/skill/hooks/use-folder-file-drop.ts b/web/app/components/workflow/skill/hooks/use-folder-file-drop.ts index 552c78a2ee..678b872cf3 100644 --- a/web/app/components/workflow/skill/hooks/use-folder-file-drop.ts +++ b/web/app/components/workflow/skill/hooks/use-folder-file-drop.ts @@ -4,11 +4,10 @@ import type { NodeApi } from 'react-arborist' import type { TreeNodeData } from '../type' -import type { AppAssetTreeView } from '@/types/app-asset' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useStore } from '@/app/components/workflow/store' -import { isDragEvent } from '../utils/drag-utils' -import { useUnifiedDrag } from './use-unified-drag' +import { isFileDrag } from '../utils/drag-utils' +import { useFileDrop } from './use-file-drop' type UseFolderFileDropReturn = { isDragOver: boolean @@ -27,15 +26,14 @@ const AUTO_EXPAND_DELAY_MS = 2000 type UseFolderFileDropOptions = { node: NodeApi - treeChildren: AppAssetTreeView[] } -export function useFolderFileDrop({ node, treeChildren: _treeChildren }: UseFolderFileDropOptions): UseFolderFileDropReturn { +export function useFolderFileDrop({ node }: UseFolderFileDropOptions): UseFolderFileDropReturn { const isFolder = node.data.node_type === 'folder' const dragOverFolderId = useStore(s => s.dragOverFolderId) const isDragOver = isFolder && dragOverFolderId === node.data.id - const { handleDragOver, handleDrop } = useUnifiedDrag() + const { handleDragOver, handleDrop } = useFileDrop() const expandTimerRef = useRef(null) const blinkTimerRef = useRef(null) @@ -86,7 +84,7 @@ export function useFolderFileDrop({ node, treeChildren: _treeChildren }: UseFold }, [clearExpandTimer]) const handleFolderDragEnter = useCallback((e: React.DragEvent) => { - if (!isFolder || !isDragEvent(e)) + if (!isFolder || !isFileDrag(e)) return dragCounterRef.current += 1 if (dragCounterRef.current === 1) @@ -94,13 +92,13 @@ export function useFolderFileDrop({ node, treeChildren: _treeChildren }: UseFold }, [isFolder, scheduleAutoExpand]) const handleFolderDragOver = useCallback((e: React.DragEvent) => { - if (!isFolder || !isDragEvent(e)) + if (!isFolder || !isFileDrag(e)) return handleDragOver(e, { folderId: node.data.id, isFolder: true }) }, [handleDragOver, isFolder, node.data.id]) const handleFolderDragLeave = useCallback((e: React.DragEvent) => { - if (!isFolder || !isDragEvent(e)) + if (!isFolder || !isFileDrag(e)) return dragCounterRef.current = Math.max(dragCounterRef.current - 1, 0) if (dragCounterRef.current === 0) diff --git a/web/app/components/workflow/skill/hooks/use-root-file-drop.ts b/web/app/components/workflow/skill/hooks/use-root-file-drop.ts index 3f5be0bfcd..f7bb8b4d72 100644 --- a/web/app/components/workflow/skill/hooks/use-root-file-drop.ts +++ b/web/app/components/workflow/skill/hooks/use-root-file-drop.ts @@ -2,10 +2,9 @@ // Root-level file drop handler with drag counter to handle nested DOM events -import type { AppAssetTreeView } from '@/types/app-asset' import { useCallback, useRef } from 'react' -import { isDragEvent } from '../utils/drag-utils' -import { useUnifiedDrag } from './use-unified-drag' +import { isFileDrag } from '../utils/drag-utils' +import { useFileDrop } from './use-file-drop' type UseRootFileDropReturn = { handleRootDragEnter: (e: React.DragEvent) => void @@ -15,16 +14,12 @@ type UseRootFileDropReturn = { resetRootDragCounter: () => void } -type UseRootFileDropOptions = { - treeChildren: AppAssetTreeView[] -} - -export function useRootFileDrop({ treeChildren: _treeChildren }: UseRootFileDropOptions): UseRootFileDropReturn { - const { handleDragOver, handleDragLeave, handleDrop } = useUnifiedDrag() +export function useRootFileDrop(): UseRootFileDropReturn { + const { handleDragOver, handleDragLeave, handleDrop } = useFileDrop() const dragCounterRef = useRef(0) const handleRootDragEnter = useCallback((e: React.DragEvent) => { - if (!isDragEvent(e)) + if (!isFileDrag(e)) return dragCounterRef.current += 1 }, []) @@ -34,7 +29,7 @@ export function useRootFileDrop({ treeChildren: _treeChildren }: UseRootFileDrop }, [handleDragOver]) const handleRootDragLeave = useCallback((e: React.DragEvent) => { - if (!isDragEvent(e)) + if (!isFileDrag(e)) return dragCounterRef.current = Math.max(dragCounterRef.current - 1, 0) if (dragCounterRef.current === 0) diff --git a/web/app/components/workflow/skill/hooks/use-unified-drag.ts b/web/app/components/workflow/skill/hooks/use-unified-drag.ts deleted file mode 100644 index d4f967fb6d..0000000000 --- a/web/app/components/workflow/skill/hooks/use-unified-drag.ts +++ /dev/null @@ -1,40 +0,0 @@ -'use client' - -// Unified drag handler for external file uploads -// Internal node drag-move is now handled by react-arborist's built-in drag system - -import { useCallback } from 'react' -import { isFileDrag } from '../utils/drag-utils' -import { useFileDrop } from './use-file-drop' - -type DragTarget = { - folderId: string | null - isFolder: boolean -} - -export function useUnifiedDrag() { - const fileDrop = useFileDrop() - - // Only handle external file drags - internal node drags are handled by react-arborist - const handleDragOver = useCallback((e: React.DragEvent, target: DragTarget) => { - if (isFileDrag(e)) - fileDrop.handleDragOver(e, target) - }, [fileDrop]) - - const handleDragLeave = useCallback((e: React.DragEvent) => { - if (isFileDrag(e)) - fileDrop.handleDragLeave(e) - }, [fileDrop]) - - const handleDrop = useCallback((e: React.DragEvent, targetFolderId: string | null) => { - if (isFileDrag(e)) - return fileDrop.handleDrop(e, targetFolderId) - }, [fileDrop]) - - return { - handleDragOver, - handleDragLeave, - handleDrop, - isUploading: fileDrop.isUploading, - } -}