diff --git a/web/app/components/workflow/skill/file-tree/index.tsx b/web/app/components/workflow/skill/file-tree/index.tsx index 81be17d851..46984d0a4a 100644 --- a/web/app/components/workflow/skill/file-tree/index.tsx +++ b/web/app/components/workflow/skill/file-tree/index.tsx @@ -49,6 +49,7 @@ const FileTree: React.FC = ({ className, searchTerm = '' }) => { const expandedFolderIds = useStore(s => s.expandedFolderIds) const activeTabId = useStore(s => s.activeTabId) + const selectedTreeNodeId = useStore(s => s.selectedTreeNodeId) const storeApi = useWorkflowStore() const treeChildren = treeData?.children ?? emptyTreeNodes @@ -79,6 +80,15 @@ const FileTree: React.FC = ({ className, searchTerm = '' }) => { node.toggle() }, [storeApi]) + const handleSelect = useCallback((nodes: NodeApi[]) => { + if (activeTabId) { + storeApi.getState().setSelectedTreeNodeId(activeTabId) + return + } + const selectedId = nodes[0]?.id ?? null + storeApi.getState().setSelectedTreeNodeId(selectedId) + }, [activeTabId, storeApi]) + const handleBlankAreaContextMenu = useCallback((e: React.MouseEvent) => { e.preventDefault() storeApi.getState().setContextMenu({ @@ -149,9 +159,10 @@ const FileTree: React.FC = ({ className, searchTerm = '' }) => { indent={20} overscanCount={5} openByDefault={false} - selection={activeTabId ?? undefined} + selection={activeTabId ?? selectedTreeNodeId ?? undefined} initialOpenState={initialOpensObject} onToggle={handleToggle} + onSelect={handleSelect} onActivate={handleActivate} onRename={handleRename} searchTerm={searchTerm} diff --git a/web/app/components/workflow/skill/hooks/use-sync-tree-with-active-tab.ts b/web/app/components/workflow/skill/hooks/use-sync-tree-with-active-tab.ts index 73887302f2..66127fd2d7 100644 --- a/web/app/components/workflow/skill/hooks/use-sync-tree-with-active-tab.ts +++ b/web/app/components/workflow/skill/hooks/use-sync-tree-with-active-tab.ts @@ -27,6 +27,8 @@ export function useSyncTreeWithActiveTab({ if (!activeTabId) return + storeApi.getState().setSelectedTreeNodeId(activeTabId) + const tree = treeRef.current if (!tree) return diff --git a/web/app/components/workflow/skill/sidebar-search-add.tsx b/web/app/components/workflow/skill/sidebar-search-add.tsx index 0cd1057f9c..d745b18360 100644 --- a/web/app/components/workflow/skill/sidebar-search-add.tsx +++ b/web/app/components/workflow/skill/sidebar-search-add.tsx @@ -66,13 +66,14 @@ const SidebarSearchAdd: FC = ({ onSearchChange }) => { const { data: treeData } = useSkillAssetTreeData() const activeTabId = useStore(s => s.activeTabId) + const selectedTreeNodeId = useStore(s => s.selectedTreeNodeId) const treeChildren = treeData?.children const targetFolderId = useMemo(() => { if (!treeChildren) return 'root' - return getTargetFolderIdFromSelection(activeTabId, treeChildren) - }, [activeTabId, treeChildren]) + return getTargetFolderIdFromSelection(activeTabId ?? selectedTreeNodeId, treeChildren) + }, [activeTabId, 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 3335ced60e..ddb4aeb96e 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 @@ -16,6 +16,7 @@ export const createFileTreeSlice: StateCreator< FileTreeSliceShape > = (set, get) => ({ expandedFolderIds: new Set(), + selectedTreeNodeId: null, pendingCreateNode: null, setExpandedFolderIds: (ids: Set) => { @@ -56,6 +57,10 @@ export const createFileTreeSlice: StateCreator< ) }, + setSelectedTreeNodeId: (nodeId) => { + set({ selectedTreeNodeId: 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 f4fc3b214b..909f71dc64 100644 --- a/web/app/components/workflow/store/workflow/skill-editor/index.ts +++ b/web/app/components/workflow/store/workflow/skill-editor/index.ts @@ -27,6 +27,7 @@ export const createSkillEditorSlice: StateCreator = (...a activeTabId: null, previewTabId: null, expandedFolderIds: new Set(), + selectedTreeNodeId: 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 e089037120..4ed9f908fc 100644 --- a/web/app/components/workflow/store/workflow/skill-editor/types.ts +++ b/web/app/components/workflow/store/workflow/skill-editor/types.ts @@ -28,6 +28,8 @@ export type FileTreeSliceShape = { revealFile: (ancestorFolderIds: string[]) => void setExpandedFromOpens: (opens: OpensObject) => void getOpensObject: () => OpensObject + selectedTreeNodeId: string | null + setSelectedTreeNodeId: (nodeId: string | null) => void pendingCreateNode: PendingCreateNode | null startCreateNode: (nodeType: PendingCreateNode['nodeType'], parentId: PendingCreateNode['parentId']) => void clearCreateNode: () => void