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 1b85843c9..8e34a05c6 100644 --- a/src/components/common/TreeExplorer.vue +++ b/src/components/common/TreeExplorer.vue @@ -43,14 +43,18 @@ 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 { + InjectKeyExpandedKeys, InjectKeyHandleEditLabelFunction, type RenderedTreeExplorerNode, type TreeExplorerNode } from '@/types/treeExplorerTypes' +import { combineTrees, findNodeByKey } from '@/utils/treeUtil' const expandedKeys = defineModel>('expandedKeys') +provide(InjectKeyExpandedKeys, expandedKeys) const selectionKeys = defineModel>('selectionKeys') // Tracks whether the caller has set the selectionKeys model. const storeSelectionKeys = selectionKeys.value !== undefined @@ -64,8 +68,23 @@ const emit = defineEmits<{ (e: 'nodeDelete', node: RenderedTreeExplorerNode): void (e: 'contextMenu', node: RenderedTreeExplorerNode, event: MouseEvent): void }>() + +const { + newFolderNode, + getAddFolderMenuItem, + handleFolderCreation, + addFolderCommand +} = useTreeFolderOperations( + /* expandNode */ (node: TreeExplorerNode) => { + expandedKeys.value[node.key] = true + } +) + const renderedRoot = computed(() => { - 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 +146,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 +170,7 @@ const deleteCommand = async (node: RenderedTreeExplorerNode) => { } const menuItems = computed(() => [ + getAddFolderMenuItem(menuTargetNode.value), { label: t('g.rename'), icon: 'pi pi-file-edit', @@ -194,7 +218,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)) + } }) 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 ) => [ - { - 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>( }, 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>( ) const treeExplorerRef = ref | null>(null) -const addNewBookmarkFolder = ( - parent?: RenderedTreeExplorerNode -) => { - 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..74e28963f 100644 --- a/src/components/sidebar/tabs/nodeLibrary/NodeTreeFolder.vue +++ b/src/components/sidebar/tabs/nodeLibrary/NodeTreeFolder.vue @@ -8,21 +8,27 @@