mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-06 08:00:05 +00:00
[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
This commit is contained in:
@@ -1,103 +1,42 @@
|
||||
<template>
|
||||
<div
|
||||
:class="[
|
||||
'node-tree-folder',
|
||||
{ bookmark: props.isBookmarkFolder, 'can-drop': canDrop }
|
||||
]"
|
||||
ref="container"
|
||||
>
|
||||
<span class="folder-label">
|
||||
<slot name="folder-label" :node="props.node">
|
||||
{{ props.node.label }}
|
||||
</slot>
|
||||
</span>
|
||||
<Badge
|
||||
:value="props.node.totalNodes"
|
||||
severity="secondary"
|
||||
:style="{ marginLeft: '0.5rem' }"
|
||||
/>
|
||||
<div ref="container" class="node-lib-node-container">
|
||||
<TreeExplorerTreeNode
|
||||
:node="node"
|
||||
@item-dropped="handleItemDrop"
|
||||
></TreeExplorerTreeNode>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import TreeExplorerTreeNode from '@/components/common/TreeExplorerTreeNode.vue'
|
||||
import { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
|
||||
import { useNodeBookmarkStore } from '@/stores/nodeBookmarkStore'
|
||||
import type { CanvasDragAndDropData } from '@/types/litegraphTypes'
|
||||
import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'
|
||||
import Badge from 'primevue/badge'
|
||||
import type { TreeNode } from 'primevue/treenode'
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { computed, inject, onMounted, onUnmounted, Ref, ref, watch } from 'vue'
|
||||
import type { BookmarkCustomization } from '@/types/apiTypes'
|
||||
import { RenderedTreeExplorerNode } from '@/types/treeExplorerTypes'
|
||||
|
||||
const props = defineProps<{
|
||||
node: TreeNode
|
||||
isBookmarkFolder: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'itemDropped', node: TreeNode): void
|
||||
node: RenderedTreeExplorerNode<ComfyNodeDefImpl>
|
||||
}>()
|
||||
|
||||
const nodeBookmarkStore = useNodeBookmarkStore()
|
||||
|
||||
const customization = computed<BookmarkCustomization | undefined>(() => {
|
||||
return nodeBookmarkStore.bookmarksCustomization[props.node.data.nodePath]
|
||||
})
|
||||
|
||||
const addNodeToBookmarkFolder = (node: ComfyNodeDefImpl) => {
|
||||
if (!props.node.data) {
|
||||
console.error('Bookmark folder does not have data!')
|
||||
return
|
||||
}
|
||||
if (nodeBookmarkStore.isBookmarked(node)) {
|
||||
nodeBookmarkStore.toggleBookmark(node)
|
||||
}
|
||||
|
||||
const folderNodeDef = props.node.data as ComfyNodeDefImpl
|
||||
const nodePath = folderNodeDef.category + '/' + node.display_name
|
||||
nodeBookmarkStore.addBookmark(nodePath)
|
||||
}
|
||||
|
||||
const container = ref<HTMLElement | null>(null)
|
||||
const canDrop = ref(false)
|
||||
|
||||
const treeNodeElement = ref<HTMLElement | null>(null)
|
||||
const iconElement = ref<HTMLElement | null>(null)
|
||||
|
||||
let dropTargetCleanup = () => {}
|
||||
let stopWatchCustomization: (() => void) | null = null
|
||||
|
||||
const container = ref<HTMLElement | null>(null)
|
||||
onMounted(() => {
|
||||
if (!props.isBookmarkFolder) return
|
||||
|
||||
treeNodeElement.value = container.value?.closest(
|
||||
'.p-tree-node-content'
|
||||
) as HTMLElement
|
||||
dropTargetCleanup = dropTargetForElements({
|
||||
element: treeNodeElement.value,
|
||||
onDrop: (event) => {
|
||||
const dndData = event.source.data as CanvasDragAndDropData
|
||||
if (dndData.type === 'add-node') {
|
||||
addNodeToBookmarkFolder(dndData.data)
|
||||
canDrop.value = false
|
||||
emit('itemDropped', props.node)
|
||||
}
|
||||
},
|
||||
onDragEnter: (event) => {
|
||||
const dndData = event.source.data as CanvasDragAndDropData
|
||||
if (dndData.type === 'add-node') {
|
||||
canDrop.value = true
|
||||
}
|
||||
},
|
||||
onDragLeave: (event) => {
|
||||
canDrop.value = false
|
||||
}
|
||||
})
|
||||
|
||||
iconElement.value = treeNodeElement.value.querySelector(
|
||||
':scope > .p-tree-node-icon'
|
||||
) as HTMLElement
|
||||
|
||||
updateIconColor()
|
||||
|
||||
// Start watching after the component is mounted
|
||||
@@ -111,16 +50,13 @@ const updateIconColor = () => {
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
dropTargetCleanup()
|
||||
if (stopWatchCustomization) {
|
||||
stopWatchCustomization()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.node-tree-folder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
const expandedKeys = inject<Ref<Record<string, boolean>>>('expandedKeys')
|
||||
const handleItemDrop = (node: RenderedTreeExplorerNode) => {
|
||||
expandedKeys.value[node.key] = true
|
||||
}
|
||||
</style>
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user