From 3240e7802f33c0a5ca3b04a0b24e52852114256d Mon Sep 17 00:00:00 2001
From: Chenlei Hu <hcl@comfy.org>
Date: Mon, 17 Mar 2025 12:48:06 -0400
Subject: [PATCH 1/4] Add support for create folder in TreeExplorer

---
 src/components/common/TreeExplorer.vue        | 20 ++++-
 .../tree/useTreeFolderOperations.ts           | 76 +++++++++++++++++++
 src/types/treeExplorerTypes.ts                |  6 +-
 src/utils/treeUtil.ts                         | 43 ++++++++++-
 4 files changed, 138 insertions(+), 7 deletions(-)
 create mode 100644 src/composables/tree/useTreeFolderOperations.ts

diff --git a/src/components/common/TreeExplorer.vue b/src/components/common/TreeExplorer.vue
index 1b85843c9..1581f6ee4 100644
--- a/src/components/common/TreeExplorer.vue
+++ b/src/components/common/TreeExplorer.vue
@@ -43,12 +43,15 @@ import { computed, provide, ref } from 'vue'
 import { useI18n } from 'vue-i18n'
 
 import TreeExplorerTreeNode from '@/components/common/TreeExplorerTreeNode.vue'
+import { useTreeFolderOperations } from '@/composables/tree/useTreeFolderOperations'
 import { useErrorHandling } from '@/composables/useErrorHandling'
+import { useTreeExpansion } from '@/composables/useTreeExpansion'
 import {
   InjectKeyHandleEditLabelFunction,
   type RenderedTreeExplorerNode,
   type TreeExplorerNode
 } from '@/types/treeExplorerTypes'
+import { combineTrees } from '@/utils/treeUtil'
 
 const expandedKeys = defineModel<Record<string, boolean>>('expandedKeys')
 const selectionKeys = defineModel<Record<string, boolean>>('selectionKeys')
@@ -64,8 +67,16 @@ const emit = defineEmits<{
   (e: 'nodeDelete', node: RenderedTreeExplorerNode): void
   (e: 'contextMenu', node: RenderedTreeExplorerNode, event: MouseEvent): void
 }>()
+
+const { expandNode } = useTreeExpansion(expandedKeys)
+const { newFolderNode, getAddFolderMenuItem, handleFolderCreation } =
+  useTreeFolderOperations(expandNode)
+
 const renderedRoot = computed<RenderedTreeExplorerNode>(() => {
-  return fillNodeInfo(props.root)
+  const renderedRoot = fillNodeInfo(props.root)
+  return newFolderNode.value
+    ? combineTrees(renderedRoot, newFolderNode.value)
+    : renderedRoot
 })
 const getTreeNodeIcon = (node: TreeExplorerNode) => {
   if (node.getIcon) {
@@ -127,7 +138,11 @@ const handleNodeLabelEdit = async (
 ) => {
   await errorHandling.wrapWithErrorHandlingAsync(
     async () => {
-      await node.handleRename(newName)
+      if (node.key === newFolderNode.value?.key) {
+        await handleFolderCreation(newName)
+      } else {
+        await node.handleRename(newName)
+      }
     },
     node.handleError,
     () => {
@@ -147,6 +162,7 @@ const deleteCommand = async (node: RenderedTreeExplorerNode) => {
 }
 const menuItems = computed<MenuItem[]>(() =>
   [
+    getAddFolderMenuItem(menuTargetNode.value),
     {
       label: t('g.rename'),
       icon: 'pi pi-file-edit',
diff --git a/src/composables/tree/useTreeFolderOperations.ts b/src/composables/tree/useTreeFolderOperations.ts
new file mode 100644
index 000000000..5f0a127b9
--- /dev/null
+++ b/src/composables/tree/useTreeFolderOperations.ts
@@ -0,0 +1,76 @@
+import { ref } from 'vue'
+import { useI18n } from 'vue-i18n'
+
+import type { RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
+
+/**
+ * Use this to handle folder operations in a tree.
+ * @param expandNode - The function to expand a node.
+ */
+export function useTreeFolderOperations(
+  expandNode: (node: RenderedTreeExplorerNode) => void
+) {
+  const { t } = useI18n()
+  const newFolderNode = ref<RenderedTreeExplorerNode | null>(null)
+  const addFolderTargetNode = ref<RenderedTreeExplorerNode | null>(null)
+
+  // Generate a unique temporary key for the new folder
+  const generateTempKey = (parentKey: string) => {
+    return `${parentKey}new_folder_${Date.now()}`
+  }
+
+  // Handle folder creation after name is confirmed
+  const handleFolderCreation = async (newName: string) => {
+    if (!newFolderNode.value || !addFolderTargetNode.value) return
+
+    try {
+      // Call the handleAddFolder method with the new folder name
+      await addFolderTargetNode.value?.handleAddFolder?.(newName)
+    } finally {
+      newFolderNode.value = null
+      addFolderTargetNode.value = null
+    }
+  }
+
+  /**
+   * The command to add a folder to a node via the context menu
+   * @param targetNode - The node where the folder will be added under
+   */
+  const addFolderCommand = (targetNode: RenderedTreeExplorerNode) => {
+    expandNode(targetNode)
+    newFolderNode.value = {
+      key: generateTempKey(targetNode.key),
+      label: '',
+      leaf: false,
+      children: [],
+      icon: 'pi pi-folder',
+      type: 'folder',
+      totalLeaves: 0,
+      badgeText: '',
+      isEditingLabel: true
+    }
+    addFolderTargetNode.value = targetNode
+  }
+
+  // Generate the "Add Folder" menu item
+  const getAddFolderMenuItem = (
+    targetNode: RenderedTreeExplorerNode | null
+  ) => {
+    return {
+      label: t('g.addFolder'),
+      icon: 'pi pi-folder-plus',
+      command: () => {
+        if (targetNode) addFolderCommand(targetNode)
+      },
+      visible: targetNode && !targetNode.leaf && !!targetNode.handleAddFolder,
+      isAsync: false
+    }
+  }
+
+  return {
+    newFolderNode,
+    addFolderCommand,
+    getAddFolderMenuItem,
+    handleFolderCreation
+  }
+}
diff --git a/src/types/treeExplorerTypes.ts b/src/types/treeExplorerTypes.ts
index cbbe2acdc..c3d63af48 100644
--- a/src/types/treeExplorerTypes.ts
+++ b/src/types/treeExplorerTypes.ts
@@ -19,10 +19,10 @@ export interface TreeExplorerNode<T = any> {
   ) => void | Promise<void>
   /** Function to handle deleting the node */
   handleDelete?: (this: TreeExplorerNode<T>) => void | Promise<void>
-  /** Function to handle adding a child node */
-  handleAddChild?: (
+  /** Function to handle adding a folder */
+  handleAddFolder?: (
     this: TreeExplorerNode<T>,
-    child: TreeExplorerNode<T>
+    folderName: string
   ) => void | Promise<void>
   /** Whether the node is draggable */
   draggable?: boolean
diff --git a/src/utils/treeUtil.ts b/src/utils/treeUtil.ts
index a8763be53..6190cd24a 100644
--- a/src/utils/treeUtil.ts
+++ b/src/utils/treeUtil.ts
@@ -105,7 +105,10 @@ export function sortedTree(
   return newNode
 }
 
-export const findNodeByKey = (root: TreeNode, key: string): TreeNode | null => {
+export const findNodeByKey = <T extends TreeNode>(
+  root: T,
+  key: string
+): T | null => {
   if (root.key === key) {
     return root
   }
@@ -113,10 +116,46 @@ export const findNodeByKey = (root: TreeNode, key: string): TreeNode | null => {
     return null
   }
   for (const child of root.children) {
-    const result = findNodeByKey(child, key)
+    const result = findNodeByKey(child as T, key)
     if (result) {
       return result
     }
   }
   return null
 }
+
+/**
+ * Deep clone a tree node and its children.
+ * @param node - The node to clone.
+ * @returns A deep clone of the node.
+ */
+export function cloneTree<T extends TreeNode>(node: T): T {
+  const clone: T = { ...node } as T
+
+  // Clone children recursively
+  if (node.children && node.children.length > 0) {
+    clone.children = node.children.map((child) => cloneTree(child as T))
+  }
+
+  return clone
+}
+
+/**
+ * Merge a subtree into the tree.
+ * @param root - The root of the tree.
+ * @param subtree - The subtree to merge.
+ * @returns A new tree with the subtree merged.
+ */
+export const combineTrees = <T extends TreeNode>(root: T, subtree: T): T => {
+  const newRoot = cloneTree(root)
+
+  const parentKey = subtree.key.slice(0, subtree.key.lastIndexOf('/'))
+  const parent = findNodeByKey(newRoot, parentKey)
+
+  if (parent) {
+    parent.children ??= []
+    parent.children.push(cloneTree(subtree))
+  }
+
+  return newRoot
+}

From 27da88fd85d508cd7eeac25a6dbe70e0b7fc50b7 Mon Sep 17 00:00:00 2001
From: Chenlei Hu <hcl@comfy.org>
Date: Mon, 17 Mar 2025 13:17:28 -0400
Subject: [PATCH 2/4] Migrate node library bookmark tree to use new folder
 feature

---
 src/components/common/TreeExplorer.vue        | 19 ++++++++---
 .../nodeLibrary/NodeBookmarkTreeExplorer.vue  | 33 ++++---------------
 .../tabs/nodeLibrary/NodeTreeFolder.vue       |  7 ++--
 .../tree/useTreeFolderOperations.ts           |  4 +--
 src/stores/nodeBookmarkStore.ts               | 12 +++----
 5 files changed, 33 insertions(+), 42 deletions(-)

diff --git a/src/components/common/TreeExplorer.vue b/src/components/common/TreeExplorer.vue
index 1581f6ee4..d9c074325 100644
--- a/src/components/common/TreeExplorer.vue
+++ b/src/components/common/TreeExplorer.vue
@@ -51,7 +51,7 @@ import {
   type RenderedTreeExplorerNode,
   type TreeExplorerNode
 } from '@/types/treeExplorerTypes'
-import { combineTrees } from '@/utils/treeUtil'
+import { combineTrees, findNodeByKey } from '@/utils/treeUtil'
 
 const expandedKeys = defineModel<Record<string, boolean>>('expandedKeys')
 const selectionKeys = defineModel<Record<string, boolean>>('selectionKeys')
@@ -69,8 +69,12 @@ const emit = defineEmits<{
 }>()
 
 const { expandNode } = useTreeExpansion(expandedKeys)
-const { newFolderNode, getAddFolderMenuItem, handleFolderCreation } =
-  useTreeFolderOperations(expandNode)
+const {
+  newFolderNode,
+  getAddFolderMenuItem,
+  handleFolderCreation,
+  addFolderCommand
+} = useTreeFolderOperations(expandNode)
 
 const renderedRoot = computed<RenderedTreeExplorerNode>(() => {
   const renderedRoot = fillNodeInfo(props.root)
@@ -210,7 +214,14 @@ const wrapCommandWithErrorHandler = (
 
 defineExpose({
   renameCommand,
-  deleteCommand
+  deleteCommand,
+  /**
+   * The command to add a folder to a node via the context menu
+   * @param targetNodeKey - The key of the node where the folder will be added under
+   */
+  addFolderCommand: (targetNodeKey: string) => {
+    addFolderCommand(findNodeByKey(renderedRoot.value, targetNodeKey))
+  }
 })
 </script>
 
diff --git a/src/components/sidebar/tabs/nodeLibrary/NodeBookmarkTreeExplorer.vue b/src/components/sidebar/tabs/nodeLibrary/NodeBookmarkTreeExplorer.vue
index e986bd810..3ef5c50eb 100644
--- a/src/components/sidebar/tabs/nodeLibrary/NodeBookmarkTreeExplorer.vue
+++ b/src/components/sidebar/tabs/nodeLibrary/NodeBookmarkTreeExplorer.vue
@@ -40,7 +40,6 @@ import type {
   TreeExplorerDragAndDropData,
   TreeExplorerNode
 } from '@/types/treeExplorerTypes'
-import { findNodeByKey } from '@/utils/treeUtil'
 
 const props = defineProps<{
   filteredNodeDefs: ComfyNodeDefImpl[]
@@ -94,14 +93,6 @@ const { t } = useI18n()
 const extraMenuItems = (
   menuTargetNode: RenderedTreeExplorerNode<ComfyNodeDefImpl>
 ) => [
-  {
-    label: t('g.newFolder'),
-    icon: 'pi pi-folder-plus',
-    command: () => {
-      addNewBookmarkFolder(menuTargetNode)
-    },
-    visible: !menuTargetNode?.leaf
-  },
   {
     label: t('g.customize'),
     icon: 'pi pi-palette',
@@ -152,6 +143,11 @@ const renderedBookmarkedRoot = computed<TreeExplorerNode<ComfyNodeDefImpl>>(
         },
         children: sortedChildren,
         draggable: node.leaf,
+        handleAddFolder(newName: string) {
+          if (newName !== '') {
+            nodeBookmarkStore.addNewBookmarkFolder(this.data, newName)
+          }
+        },
         renderDragPreview(container) {
           const vnode = h(NodePreview, { nodeDef: node.data })
           render(vnode, container)
@@ -197,25 +193,8 @@ const renderedBookmarkedRoot = computed<TreeExplorerNode<ComfyNodeDefImpl>>(
 )
 
 const treeExplorerRef = ref<InstanceType<typeof TreeExplorer> | null>(null)
-const addNewBookmarkFolder = (
-  parent?: RenderedTreeExplorerNode<ComfyNodeDefImpl>
-) => {
-  const newFolderKey =
-    'root/' + nodeBookmarkStore.addNewBookmarkFolder(parent?.data).slice(0, -1)
-  nextTick(() => {
-    treeExplorerRef.value?.renameCommand(
-      findNodeByKey(
-        renderedBookmarkedRoot.value,
-        newFolderKey
-      ) as RenderedTreeExplorerNode
-    )
-    if (parent) {
-      expandedKeys.value[parent.key] = true
-    }
-  })
-}
 defineExpose({
-  addNewBookmarkFolder
+  addNewBookmarkFolder: () => treeExplorerRef.value?.addFolderCommand('root')
 })
 
 const showCustomizationDialog = ref(false)
diff --git a/src/components/sidebar/tabs/nodeLibrary/NodeTreeFolder.vue b/src/components/sidebar/tabs/nodeLibrary/NodeTreeFolder.vue
index 74b43f1d4..9370a1f44 100644
--- a/src/components/sidebar/tabs/nodeLibrary/NodeTreeFolder.vue
+++ b/src/components/sidebar/tabs/nodeLibrary/NodeTreeFolder.vue
@@ -16,13 +16,16 @@ import { useNodeBookmarkStore } from '@/stores/nodeBookmarkStore'
 import { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
 import { RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
 
-const props = defineProps<{
+const { node } = defineProps<{
   node: RenderedTreeExplorerNode<ComfyNodeDefImpl>
 }>()
 
 const nodeBookmarkStore = useNodeBookmarkStore()
 const customization = computed<BookmarkCustomization | undefined>(() => {
-  return nodeBookmarkStore.bookmarksCustomization[props.node.data.nodePath]
+  const nodeDef = node.data
+  return nodeDef
+    ? nodeBookmarkStore.bookmarksCustomization[nodeDef.nodePath]
+    : undefined
 })
 
 const treeNodeElement = ref<HTMLElement | null>(null)
diff --git a/src/composables/tree/useTreeFolderOperations.ts b/src/composables/tree/useTreeFolderOperations.ts
index 5f0a127b9..8e8bf29c4 100644
--- a/src/composables/tree/useTreeFolderOperations.ts
+++ b/src/composables/tree/useTreeFolderOperations.ts
@@ -16,7 +16,7 @@ export function useTreeFolderOperations(
 
   // Generate a unique temporary key for the new folder
   const generateTempKey = (parentKey: string) => {
-    return `${parentKey}new_folder_${Date.now()}`
+    return `${parentKey}/new_folder_${Date.now()}`
   }
 
   // Handle folder creation after name is confirmed
@@ -57,7 +57,7 @@ export function useTreeFolderOperations(
     targetNode: RenderedTreeExplorerNode | null
   ) => {
     return {
-      label: t('g.addFolder'),
+      label: t('g.newFolder'),
       icon: 'pi pi-folder-plus',
       command: () => {
         if (targetNode) addFolderCommand(targetNode)
diff --git a/src/stores/nodeBookmarkStore.ts b/src/stores/nodeBookmarkStore.ts
index 14a7469b9..b54341c9a 100644
--- a/src/stores/nodeBookmarkStore.ts
+++ b/src/stores/nodeBookmarkStore.ts
@@ -73,14 +73,12 @@ export const useNodeBookmarkStore = defineStore('nodeBookmark', () => {
     )
   }
 
-  const addNewBookmarkFolder = (parent?: ComfyNodeDefImpl) => {
+  const addNewBookmarkFolder = (
+    parent: ComfyNodeDefImpl | undefined,
+    folderName: string
+  ) => {
     const parentPath = parent ? parent.nodePath : ''
-    let newFolderPath = parentPath + 'New Folder/'
-    let suffix = 1
-    while (bookmarks.value.some((b: string) => b.startsWith(newFolderPath))) {
-      newFolderPath = parentPath + `New Folder ${suffix}/`
-      suffix++
-    }
+    const newFolderPath = parentPath + folderName + '/'
     addBookmark(newFolderPath)
     return newFolderPath
   }

From 07622a4111f81dab6ca040f695e04b3f27d71f5a Mon Sep 17 00:00:00 2001
From: Chenlei Hu <hcl@comfy.org>
Date: Mon, 17 Mar 2025 13:53:14 -0400
Subject: [PATCH 3/4] Fix playwright test

---
 browser_tests/menu.spec.ts                     | 11 ++++++++---
 src/components/common/TreeExplorer.vue         |  2 ++
 .../tabs/nodeLibrary/NodeTreeFolder.vue        |  9 ++++++---
 src/composables/useTreeExpansion.ts            | 18 ++++--------------
 src/types/treeExplorerTypes.ts                 |  5 ++++-
 5 files changed, 24 insertions(+), 21 deletions(-)

diff --git a/browser_tests/menu.spec.ts b/browser_tests/menu.spec.ts
index 4af56ede6..72197aa38 100644
--- a/browser_tests/menu.spec.ts
+++ b/browser_tests/menu.spec.ts
@@ -119,7 +119,10 @@ test.describe('Menu', () => {
     test('Can add new bookmark folder', async ({ comfyPage }) => {
       const tab = comfyPage.menu.nodeLibraryTab
       await tab.newFolderButton.click()
-      await comfyPage.page.keyboard.press('Enter')
+      const textInput = comfyPage.page.locator('.editable-text input')
+      await textInput.waitFor({ state: 'visible' })
+      await textInput.fill('New Folder')
+      await textInput.press('Enter')
       expect(await tab.getFolder('New Folder').count()).toBe(1)
       expect(
         await comfyPage.getSetting('Comfy.NodeLibrary.Bookmarks.V2')
@@ -132,8 +135,10 @@ test.describe('Menu', () => {
 
       await tab.getFolder('foo').click({ button: 'right' })
       await comfyPage.page.getByLabel('New Folder').click()
-      await comfyPage.page.keyboard.type('bar')
-      await comfyPage.page.keyboard.press('Enter')
+      const textInput = comfyPage.page.locator('.editable-text input')
+      await textInput.waitFor({ state: 'visible' })
+      await textInput.fill('bar')
+      await textInput.press('Enter')
 
       expect(await tab.getFolder('bar').count()).toBe(1)
       expect(
diff --git a/src/components/common/TreeExplorer.vue b/src/components/common/TreeExplorer.vue
index d9c074325..372e2a411 100644
--- a/src/components/common/TreeExplorer.vue
+++ b/src/components/common/TreeExplorer.vue
@@ -47,6 +47,7 @@ import { useTreeFolderOperations } from '@/composables/tree/useTreeFolderOperati
 import { useErrorHandling } from '@/composables/useErrorHandling'
 import { useTreeExpansion } from '@/composables/useTreeExpansion'
 import {
+  InjectKeyExpandedKeys,
   InjectKeyHandleEditLabelFunction,
   type RenderedTreeExplorerNode,
   type TreeExplorerNode
@@ -54,6 +55,7 @@ import {
 import { combineTrees, findNodeByKey } from '@/utils/treeUtil'
 
 const expandedKeys = defineModel<Record<string, boolean>>('expandedKeys')
+provide(InjectKeyExpandedKeys, expandedKeys)
 const selectionKeys = defineModel<Record<string, boolean>>('selectionKeys')
 // Tracks whether the caller has set the selectionKeys model.
 const storeSelectionKeys = selectionKeys.value !== undefined
diff --git a/src/components/sidebar/tabs/nodeLibrary/NodeTreeFolder.vue b/src/components/sidebar/tabs/nodeLibrary/NodeTreeFolder.vue
index 9370a1f44..74e28963f 100644
--- a/src/components/sidebar/tabs/nodeLibrary/NodeTreeFolder.vue
+++ b/src/components/sidebar/tabs/nodeLibrary/NodeTreeFolder.vue
@@ -8,13 +8,16 @@
 </template>
 
 <script setup lang="ts">
-import { Ref, computed, inject, onMounted, onUnmounted, ref, watch } from 'vue'
+import { computed, inject, onMounted, onUnmounted, ref, watch } from 'vue'
 
 import TreeExplorerTreeNode from '@/components/common/TreeExplorerTreeNode.vue'
 import type { BookmarkCustomization } from '@/schemas/apiSchema'
 import { useNodeBookmarkStore } from '@/stores/nodeBookmarkStore'
 import { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
-import { RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
+import {
+  InjectKeyExpandedKeys,
+  type RenderedTreeExplorerNode
+} from '@/types/treeExplorerTypes'
 
 const { node } = defineProps<{
   node: RenderedTreeExplorerNode<ComfyNodeDefImpl>
@@ -59,7 +62,7 @@ onUnmounted(() => {
   }
 })
 
-const expandedKeys = inject<Ref<Record<string, boolean>>>('expandedKeys')
+const expandedKeys = inject(InjectKeyExpandedKeys)
 const handleItemDrop = (node: RenderedTreeExplorerNode) => {
   expandedKeys.value[node.key] = true
 }
diff --git a/src/composables/useTreeExpansion.ts b/src/composables/useTreeExpansion.ts
index 580b3bb00..9ede6654c 100644
--- a/src/composables/useTreeExpansion.ts
+++ b/src/composables/useTreeExpansion.ts
@@ -23,30 +23,20 @@ export function useTreeExpansion(expandedKeys: Ref<Record<string, boolean>>) {
   }
 
   const expandNode = (node: TreeNode) => {
-    if (
-      node.key &&
-      typeof node.key === 'string' &&
-      node.children &&
-      node.children.length
-    ) {
+    if (node.key && typeof node.key === 'string' && !node.leaf) {
       expandedKeys.value[node.key] = true
 
-      for (const child of node.children) {
+      for (const child of node.children ?? []) {
         expandNode(child)
       }
     }
   }
 
   const collapseNode = (node: TreeNode) => {
-    if (
-      node.key &&
-      typeof node.key === 'string' &&
-      node.children &&
-      node.children.length
-    ) {
+    if (node.key && typeof node.key === 'string' && !node.leaf) {
       delete expandedKeys.value[node.key]
 
-      for (const child of node.children) {
+      for (const child of node.children ?? []) {
         collapseNode(child)
       }
     }
diff --git a/src/types/treeExplorerTypes.ts b/src/types/treeExplorerTypes.ts
index c3d63af48..360f8e2d7 100644
--- a/src/types/treeExplorerTypes.ts
+++ b/src/types/treeExplorerTypes.ts
@@ -1,5 +1,5 @@
 import type { MenuItem } from 'primevue/menuitem'
-import type { InjectionKey } from 'vue'
+import type { InjectionKey, Ref } from 'vue'
 
 export interface TreeExplorerNode<T = any> {
   key: string
@@ -71,3 +71,6 @@ export type TreeExplorerDragAndDropData<T = any> = {
 export const InjectKeyHandleEditLabelFunction: InjectionKey<
   (node: RenderedTreeExplorerNode, newName: string) => void
 > = Symbol()
+
+export const InjectKeyExpandedKeys: InjectionKey<Ref<Record<string, boolean>>> =
+  Symbol()

From b02016411fbfe83d59e5e6572e5864fc259b5d2d Mon Sep 17 00:00:00 2001
From: Chenlei Hu <hcl@comfy.org>
Date: Mon, 17 Mar 2025 13:54:58 -0400
Subject: [PATCH 4/4] nit

---
 src/components/common/TreeExplorer.vue | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/components/common/TreeExplorer.vue b/src/components/common/TreeExplorer.vue
index 372e2a411..8e34a05c6 100644
--- a/src/components/common/TreeExplorer.vue
+++ b/src/components/common/TreeExplorer.vue
@@ -45,7 +45,6 @@ import { useI18n } from 'vue-i18n'
 import TreeExplorerTreeNode from '@/components/common/TreeExplorerTreeNode.vue'
 import { useTreeFolderOperations } from '@/composables/tree/useTreeFolderOperations'
 import { useErrorHandling } from '@/composables/useErrorHandling'
-import { useTreeExpansion } from '@/composables/useTreeExpansion'
 import {
   InjectKeyExpandedKeys,
   InjectKeyHandleEditLabelFunction,
@@ -70,13 +69,16 @@ const emit = defineEmits<{
   (e: 'contextMenu', node: RenderedTreeExplorerNode, event: MouseEvent): void
 }>()
 
-const { expandNode } = useTreeExpansion(expandedKeys)
 const {
   newFolderNode,
   getAddFolderMenuItem,
   handleFolderCreation,
   addFolderCommand
-} = useTreeFolderOperations(expandNode)
+} = useTreeFolderOperations(
+  /* expandNode */ (node: TreeExplorerNode) => {
+    expandedKeys.value[node.key] = true
+  }
+)
 
 const renderedRoot = computed<RenderedTreeExplorerNode>(() => {
   const renderedRoot = fillNodeInfo(props.root)