diff --git a/web/app/components/workflow/skill/file-tree/index.tsx b/web/app/components/workflow/skill/file-tree/index.tsx index 1700e01a76..654ae4e766 100644 --- a/web/app/components/workflow/skill/file-tree/index.tsx +++ b/web/app/components/workflow/skill/file-tree/index.tsx @@ -99,17 +99,18 @@ const FileTree: React.FC = ({ className, searchTerm = '' }) => { }, [storeApi]) const handleSelect = useCallback((nodes: NodeApi[]) => { - if (activeTabId) { - storeApi.getState().setSelectedTreeNodeId(activeTabId) - return - } const selectedId = nodes[0]?.id ?? null storeApi.getState().setSelectedTreeNodeId(selectedId) - storeApi.getState().setCreateTargetNodeId(selectedId) - }, [activeTabId, storeApi]) + }, [storeApi]) + + // Clicking blank area clears selection for root-level creation + const handleBlankAreaClick = useCallback(() => { + storeApi.getState().setSelectedTreeNodeId(null) + }, [storeApi]) const handleBlankAreaContextMenu = useCallback((e: React.MouseEvent) => { e.preventDefault() + storeApi.getState().setSelectedTreeNodeId(null) storeApi.getState().setContextMenu({ top: e.clientY, left: e.clientX, @@ -169,6 +170,7 @@ const FileTree: React.FC = ({ className, searchTerm = '' }) => { // Root dropzone highlight - dashed border without layout shift isRootDropzone && 'relative rounded-lg bg-state-accent-hover after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:border-[1.5px] after:border-dashed after:border-state-accent-solid after:content-[\'\']', )} + onClick={handleBlankAreaClick} onContextMenu={handleBlankAreaContextMenu} onDragEnter={handleRootDragEnter} onDragOver={handleRootDragOver} @@ -186,7 +188,7 @@ const FileTree: React.FC = ({ className, searchTerm = '' }) => { indent={20} overscanCount={5} openByDefault={false} - selection={activeTabId ?? selectedTreeNodeId ?? undefined} + selection={selectedTreeNodeId ?? undefined} initialOpenState={initialOpensObject} onToggle={handleToggle} onSelect={handleSelect} diff --git a/web/app/components/workflow/skill/hooks/use-tree-node-handlers.ts b/web/app/components/workflow/skill/hooks/use-tree-node-handlers.ts index 5ceed83f8b..437cd4cc3c 100644 --- a/web/app/components/workflow/skill/hooks/use-tree-node-handlers.ts +++ b/web/app/components/workflow/skill/hooks/use-tree-node-handlers.ts @@ -49,13 +49,12 @@ export function useTreeNodeHandlers({ const handleClick = useCallback((e: React.MouseEvent) => { e.stopPropagation() - storeApi.getState().setCreateTargetNodeId(node.data.id) - node.select() + node.select() // This triggers Tree's onSelect → setSelectedTreeNodeId if (isFolder) throttledToggle() else handleFileClick() - }, [handleFileClick, isFolder, node, storeApi, throttledToggle]) + }, [handleFileClick, isFolder, node, throttledToggle]) const handleDoubleClick = useCallback((e: React.MouseEvent) => { e.stopPropagation() @@ -74,7 +73,8 @@ export function useTreeNodeHandlers({ e.preventDefault() e.stopPropagation() - storeApi.getState().setCreateTargetNodeId(node.data.id) + // Select the node for highlight + creation target + storeApi.getState().setSelectedTreeNodeId(node.data.id) storeApi.getState().setContextMenu({ top: e.clientY, left: e.clientX, diff --git a/web/app/components/workflow/skill/sidebar-search-add.tsx b/web/app/components/workflow/skill/sidebar-search-add.tsx index 6607a4198c..637601fbe0 100644 --- a/web/app/components/workflow/skill/sidebar-search-add.tsx +++ b/web/app/components/workflow/skill/sidebar-search-add.tsx @@ -65,15 +65,14 @@ const SidebarSearchAdd: FC = ({ onSearchChange }) => { }, [debouncedSearchValue, onSearchChange]) const { data: treeData } = useSkillAssetTreeData() - const activeTabId = useStore(s => s.activeTabId) - const createTargetNodeId = useStore(s => s.createTargetNodeId) + const selectedTreeNodeId = useStore(s => s.selectedTreeNodeId) const treeChildren = treeData?.children const targetFolderId = useMemo(() => { if (!treeChildren) return 'root' - return getTargetFolderIdFromSelection(createTargetNodeId ?? activeTabId, treeChildren) - }, [activeTabId, createTargetNodeId, treeChildren]) + return getTargetFolderIdFromSelection(selectedTreeNodeId, treeChildren) + }, [selectedTreeNodeId, treeChildren]) const menuOffset = useMemo(() => ({ mainAxis: 4 }), []) const { diff --git a/web/app/components/workflow/store/workflow/skill-editor/file-tree-slice.ts b/web/app/components/workflow/store/workflow/skill-editor/file-tree-slice.ts index 15e53cfc15..c2aac992ac 100644 --- a/web/app/components/workflow/store/workflow/skill-editor/file-tree-slice.ts +++ b/web/app/components/workflow/store/workflow/skill-editor/file-tree-slice.ts @@ -17,7 +17,6 @@ export const createFileTreeSlice: StateCreator< > = (set, get) => ({ expandedFolderIds: new Set(), selectedTreeNodeId: null, - createTargetNodeId: null, pendingCreateNode: null, setExpandedFolderIds: (ids: Set) => { @@ -62,10 +61,6 @@ export const createFileTreeSlice: StateCreator< set({ selectedTreeNodeId: nodeId }) }, - setCreateTargetNodeId: (nodeId) => { - set({ createTargetNodeId: nodeId }) - }, - startCreateNode: (nodeType, parentId) => { set({ pendingCreateNode: { diff --git a/web/app/components/workflow/store/workflow/skill-editor/index.ts b/web/app/components/workflow/store/workflow/skill-editor/index.ts index 4d08d524bb..909f71dc64 100644 --- a/web/app/components/workflow/store/workflow/skill-editor/index.ts +++ b/web/app/components/workflow/store/workflow/skill-editor/index.ts @@ -28,7 +28,6 @@ export const createSkillEditorSlice: StateCreator = (...a previewTabId: null, expandedFolderIds: new Set(), selectedTreeNodeId: null, - createTargetNodeId: null, pendingCreateNode: null, dirtyContents: new Map(), fileMetadata: new Map>(), diff --git a/web/app/components/workflow/store/workflow/skill-editor/types.ts b/web/app/components/workflow/store/workflow/skill-editor/types.ts index d1445ca150..31e239b024 100644 --- a/web/app/components/workflow/store/workflow/skill-editor/types.ts +++ b/web/app/components/workflow/store/workflow/skill-editor/types.ts @@ -30,8 +30,6 @@ export type FileTreeSliceShape = { getOpensObject: () => OpensObject selectedTreeNodeId: string | null setSelectedTreeNodeId: (nodeId: string | null) => void - createTargetNodeId: string | null - setCreateTargetNodeId: (nodeId: string | null) => void pendingCreateNode: PendingCreateNode | null startCreateNode: (nodeType: PendingCreateNode['nodeType'], parentId: PendingCreateNode['parentId']) => void clearCreateNode: () => void