From d04dbcd2c1f46025573f02938b09797d598eea46 Mon Sep 17 00:00:00 2001 From: Chenlei Hu Date: Sun, 1 Sep 2024 14:03:15 -0400 Subject: [PATCH] [Major Refactor] Use TreeExplorer on nodeLibrarySidebarTab (#699) * Basic move * Add back node bookmark * Move node preview * Fix drag node to canvas * Restore click node to add to canvas * Split bookmark tree and library tree * Migrate rename and delete context menu * Fix expanded keys * Split components * Support extra menu items * Context menu only for folder * Migrate add folder * Handle drop * Store color customization * remove extra padding * Do not show context menu if no item * Hide divider if no bookmark * Sort bookmarks alphabetically default * nit * proper edit * Update test selectors * Auto expand on item drop * nit * Fix tests * Search also searches bookmarks tree * Add serach playwright test --- browser_tests/ComfyPage.ts | 10 +- browser_tests/menu.spec.ts | 20 +- src/components/common/TreeExplorer.vue | 62 +-- .../common/TreeExplorerTreeNode.vue | 18 +- src/components/graph/GraphCanvas.vue | 22 +- .../sidebar/tabs/NodeLibrarySidebarTab.vue | 371 ++++-------------- .../nodeLibrary/NodeBookmarkTreeExplorer.vue | 246 ++++++++++++ .../tabs/nodeLibrary/NodeTreeFolder.vue | 92 +---- .../sidebar/tabs/nodeLibrary/NodeTreeLeaf.vue | 152 ++++--- 9 files changed, 516 insertions(+), 477 deletions(-) create mode 100644 src/components/sidebar/tabs/nodeLibrary/NodeBookmarkTreeExplorer.vue diff --git a/browser_tests/ComfyPage.ts b/browser_tests/ComfyPage.ts index aa02583b2..7a8f2d90d 100644 --- a/browser_tests/ComfyPage.ts +++ b/browser_tests/ComfyPage.ts @@ -57,8 +57,12 @@ class NodeLibrarySidebarTab { ) } + get nodeLibrarySearchBoxInput() { + return this.page.locator('.node-lib-search-box input[type="text"]') + } + get nodeLibraryTree() { - return this.page.locator('.node-lib-tree') + return this.page.locator('.node-lib-tree-explorer') } get nodePreview() { @@ -83,7 +87,7 @@ class NodeLibrarySidebarTab { } folderSelector(folderName: string) { - return `.p-tree-node-content:has(> .node-lib-tree-node-label:has(.folder-label:has-text("${folderName}")))` + return `.p-tree-node-content:has(> .tree-explorer-node-label:has(.tree-folder .node-label:has-text("${folderName}")))` } getFolder(folderName: string) { @@ -91,7 +95,7 @@ class NodeLibrarySidebarTab { } nodeSelector(nodeName: string) { - return `.p-tree-node-content:has(> .node-lib-tree-node-label:has(.node-label:has-text("${nodeName}")))` + return `.p-tree-node-content:has(> .tree-explorer-node-label:has(.tree-leaf .node-label:has-text("${nodeName}")))` } getNode(nodeName: string) { diff --git a/browser_tests/menu.spec.ts b/browser_tests/menu.spec.ts index bbba49a8f..5aecebbe2 100644 --- a/browser_tests/menu.spec.ts +++ b/browser_tests/menu.spec.ts @@ -109,7 +109,7 @@ test.describe('Menu', () => { expect(await tab.getNode('KSampler (Advanced)').count()).toBe(2) // Hover on the bookmark node to display the preview - await comfyPage.page.hover('.node-tree-leaf.bookmark') + await comfyPage.page.hover('.node-lib-bookmark-tree-explorer .tree-leaf') expect(await comfyPage.page.isVisible('.node-lib-node-preview')).toBe( true ) @@ -145,10 +145,12 @@ 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') + expect(await tab.getFolder('bar').count()).toBe(1) expect(await comfyPage.getSetting('Comfy.NodeLibrary.Bookmarks')).toEqual( - ['foo/', 'foo/New Folder/'] + ['foo/', 'foo/bar/'] ) }) @@ -325,6 +327,20 @@ test.describe('Menu', () => { await comfyPage.getSetting('Comfy.NodeLibrary.BookmarksCustomization') ).toEqual({}) }) + + test('Can filter nodes in both trees', async ({ comfyPage }) => { + await comfyPage.setSetting('Comfy.NodeLibrary.Bookmarks', [ + 'foo/', + 'foo/KSampler (Advanced)', + 'KSampler' + ]) + + const tab = comfyPage.menu.nodeLibraryTab + await tab.nodeLibrarySearchBoxInput.fill('KSampler') + // Node search box is debounced and may take some time to update. + await comfyPage.page.waitForTimeout(1000) + expect(await tab.getNode('KSampler (Advanced)').count()).toBe(2) + }) }) test('Can change canvas zoom speed setting', async ({ comfyPage }) => { diff --git a/src/components/common/TreeExplorer.vue b/src/components/common/TreeExplorer.vue index 15e57e4da..a3e0e1181 100644 --- a/src/components/common/TreeExplorer.vue +++ b/src/components/common/TreeExplorer.vue @@ -4,6 +4,7 @@ :class="props.class" v-model:expandedKeys="expandedKeys" :value="renderedRoots" + selectionMode="single" :pt="{ nodeLabel: 'tree-explorer-node-label', nodeContent: ({ props }) => ({ @@ -40,25 +41,31 @@ import type { TreeExplorerNode } from '@/types/treeExplorerTypes' import type { MenuItem } from 'primevue/menuitem' -import { useTreeExpansion } from '@/hooks/treeHooks' +import { useI18n } from 'vue-i18n' +const expandedKeys = defineModel>('expandedKeys') +provide('expandedKeys', expandedKeys) const props = defineProps<{ roots: TreeExplorerNode[] class?: string - extraMenuItems?: MenuItem[] + extraMenuItems?: + | MenuItem[] + | ((targetNode: RenderedTreeExplorerNode) => MenuItem[]) }>() const emit = defineEmits<{ - (e: 'nodeClick', node: RenderedTreeExplorerNode): void + (e: 'nodeClick', node: RenderedTreeExplorerNode, event: MouseEvent): void (e: 'nodeDelete', node: RenderedTreeExplorerNode): void (e: 'contextMenu', node: RenderedTreeExplorerNode, event: MouseEvent): void }>() -const { expandedKeys, toggleNodeOnEvent } = useTreeExpansion() const renderedRoots = computed(() => { return props.roots.map(fillNodeInfo) }) const getTreeNodeIcon = (node: TreeExplorerNode) => { if (node.getIcon) { - return node.getIcon(node) + const icon = node.getIcon(node) + if (icon) { + return icon + } } else if (node.icon) { return node.icon } @@ -82,46 +89,57 @@ const fillNodeInfo = (node: TreeExplorerNode): RenderedTreeExplorerNode => { } } const onNodeContentClick = (e: MouseEvent, node: RenderedTreeExplorerNode) => { - if (!node.key) return - if (node.type === 'folder') { - toggleNodeOnEvent(e, node) - } - emit('nodeClick', node) + emit('nodeClick', node, e) } const menu = ref(null) const menuTargetNode = ref(null) provide('menuTargetNode', menuTargetNode) const renameEditingNode = ref(null) provide('renameEditingNode', renameEditingNode) + +const { t } = useI18n() +const renameCommand = (node: RenderedTreeExplorerNode) => { + renameEditingNode.value = node +} +const deleteCommand = (node: RenderedTreeExplorerNode) => { + node.handleDelete?.(node) + emit('nodeDelete', node) +} const menuItems = computed(() => [ { - label: 'Rename', + label: t('rename'), icon: 'pi pi-file-edit', - command: () => { - renameEditingNode.value = menuTargetNode.value - }, + command: () => renameCommand(menuTargetNode.value), visible: menuTargetNode.value?.handleRename !== undefined }, { - label: 'Delete', + label: t('delete'), icon: 'pi pi-trash', - command: () => { - menuTargetNode.value?.handleDelete?.(menuTargetNode.value) - emit('nodeDelete', menuTargetNode.value) - }, + command: () => deleteCommand(menuTargetNode.value), visible: menuTargetNode.value?.handleDelete !== undefined }, - ...(props.extraMenuItems || []) + ...(props.extraMenuItems + ? typeof props.extraMenuItems === 'function' + ? props.extraMenuItems(menuTargetNode.value) + : props.extraMenuItems + : []) ]) const handleContextMenu = (node: RenderedTreeExplorerNode, e: MouseEvent) => { menuTargetNode.value = node emit('contextMenu', node, e) - menu.value?.show(e) + if (menuItems.value.filter((item) => item.visible).length > 0) { + menu.value?.show(e) + } } +defineExpose({ + renameCommand, + deleteCommand +}) diff --git a/src/components/sidebar/tabs/nodeLibrary/NodeBookmarkTreeExplorer.vue b/src/components/sidebar/tabs/nodeLibrary/NodeBookmarkTreeExplorer.vue new file mode 100644 index 000000000..44e5b27a4 --- /dev/null +++ b/src/components/sidebar/tabs/nodeLibrary/NodeBookmarkTreeExplorer.vue @@ -0,0 +1,246 @@ + + + diff --git a/src/components/sidebar/tabs/nodeLibrary/NodeTreeFolder.vue b/src/components/sidebar/tabs/nodeLibrary/NodeTreeFolder.vue index 95629a17c..14cf8f67a 100644 --- a/src/components/sidebar/tabs/nodeLibrary/NodeTreeFolder.vue +++ b/src/components/sidebar/tabs/nodeLibrary/NodeTreeFolder.vue @@ -1,103 +1,42 @@ - + diff --git a/src/components/sidebar/tabs/nodeLibrary/NodeTreeLeaf.vue b/src/components/sidebar/tabs/nodeLibrary/NodeTreeLeaf.vue index 08c747814..623267add 100644 --- a/src/components/sidebar/tabs/nodeLibrary/NodeTreeLeaf.vue +++ b/src/components/sidebar/tabs/nodeLibrary/NodeTreeLeaf.vue @@ -1,83 +1,129 @@