mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
* knip: Don't ignore exports that are only used within a given file * knip: More pruning after rebase * knip: Vite plugin config fix * knip: vitest plugin config * knip: Playwright config, remove unnecessary ignores. * knip: Simplify project file enumeration. * knip: simplify the config file patterns ?(.optional_segment) * knip: tailwind v4 fix * knip: A little more, explain some of the deps. Should be good for this PR. * knip: remove unused disabling of classMembers. It's opt-in, which we should probably do. * knip: floating comments We should probably delete _one_ of these parallell trees, right? * knip: Add additional entrypoints * knip: Restore UserData that's exposed via the types for now. * knip: Add as an entry file even though knip says it's not necessary. * knip: re-export functions used by nodes (h/t @christian-byrne)
208 lines
6.3 KiB
TypeScript
208 lines
6.3 KiB
TypeScript
import _ from 'es-toolkit/compat'
|
|
import { defineStore } from 'pinia'
|
|
import { computed } from 'vue'
|
|
|
|
import type { BookmarkCustomization } from '@/schemas/apiSchema'
|
|
import type { TreeNode } from '@/types/treeExplorerTypes'
|
|
|
|
import { useNodeDefStore } from './nodeDefStore'
|
|
import { ComfyNodeDefImpl, createDummyFolderNodeDef } from './nodeDefStore'
|
|
import { buildNodeDefTree } from './nodeDefStore'
|
|
import { useSettingStore } from './settingStore'
|
|
|
|
const BOOKMARK_SETTING_ID = 'Comfy.NodeLibrary.Bookmarks.V2'
|
|
|
|
export const useNodeBookmarkStore = defineStore('nodeBookmark', () => {
|
|
const settingStore = useSettingStore()
|
|
const nodeDefStore = useNodeDefStore()
|
|
const bookmarks = computed<string[]>(() =>
|
|
settingStore.get(BOOKMARK_SETTING_ID)
|
|
)
|
|
|
|
const bookmarksSet = computed<Set<string>>(() => new Set(bookmarks.value))
|
|
|
|
const bookmarkedRoot = computed<TreeNode>(() =>
|
|
buildBookmarkTree(bookmarks.value)
|
|
)
|
|
|
|
// For a node in custom bookmark folders, check if its nodePath is in bookmarksSet
|
|
// For a node in the nodeDefStore, check if its name is bookmarked at top level
|
|
const isBookmarked = (node: ComfyNodeDefImpl) =>
|
|
bookmarksSet.value.has(node.nodePath) || bookmarksSet.value.has(node.name)
|
|
|
|
const toggleBookmark = async (node: ComfyNodeDefImpl) => {
|
|
if (isBookmarked(node)) {
|
|
await deleteBookmark(node.nodePath)
|
|
// Delete the bookmark at the top level if it exists
|
|
// This is used for clicking the bookmark button in the node library, i.e.
|
|
// the node is inside original/standard node library tree node
|
|
await deleteBookmark(node.name)
|
|
} else {
|
|
await addBookmark(node.name)
|
|
}
|
|
}
|
|
|
|
const buildBookmarkTree = (bookmarks: string[]) => {
|
|
const bookmarkNodes = bookmarks
|
|
.map((bookmark: string) => {
|
|
if (bookmark.endsWith('/')) return createDummyFolderNodeDef(bookmark)
|
|
|
|
const parts = bookmark.split('/')
|
|
const name = parts.pop() ?? ''
|
|
const category = parts.join('/')
|
|
const srcNodeDef = nodeDefStore.nodeDefsByName[name]
|
|
if (!srcNodeDef) {
|
|
return null
|
|
}
|
|
const nodeDef = _.clone(srcNodeDef)
|
|
nodeDef.category = category
|
|
return nodeDef
|
|
})
|
|
.filter((nodeDef) => nodeDef !== null)
|
|
return buildNodeDefTree(bookmarkNodes)
|
|
}
|
|
|
|
const addBookmark = async (nodePath: string) => {
|
|
await settingStore.set(BOOKMARK_SETTING_ID, [...bookmarks.value, nodePath])
|
|
}
|
|
|
|
const deleteBookmark = async (nodePath: string) => {
|
|
await settingStore.set(
|
|
BOOKMARK_SETTING_ID,
|
|
bookmarks.value.filter((b: string) => b !== nodePath)
|
|
)
|
|
}
|
|
|
|
const addNewBookmarkFolder = async (
|
|
parent: ComfyNodeDefImpl | undefined,
|
|
folderName: string
|
|
) => {
|
|
const parentPath = parent ? parent.nodePath : ''
|
|
const newFolderPath = parentPath + folderName + '/'
|
|
await addBookmark(newFolderPath)
|
|
return newFolderPath
|
|
}
|
|
|
|
const renameBookmarkFolder = async (
|
|
folderNode: ComfyNodeDefImpl,
|
|
newName: string
|
|
) => {
|
|
if (!folderNode.isDummyFolder) {
|
|
throw new Error('Cannot rename non-folder node')
|
|
}
|
|
|
|
if (newName.includes('/')) {
|
|
throw new Error('Folder name cannot contain "/"')
|
|
}
|
|
|
|
const newNodePath =
|
|
folderNode.category.split('/').slice(0, -1).concat(newName).join('/') +
|
|
'/'
|
|
|
|
if (newNodePath === folderNode.nodePath) {
|
|
return
|
|
}
|
|
|
|
if (bookmarks.value.some((b: string) => b.startsWith(newNodePath))) {
|
|
throw new Error(`Folder name "${newNodePath}" already exists`)
|
|
}
|
|
|
|
await settingStore.set(
|
|
BOOKMARK_SETTING_ID,
|
|
bookmarks.value.map((b: string) =>
|
|
b.startsWith(folderNode.nodePath)
|
|
? b.replace(folderNode.nodePath, newNodePath)
|
|
: b
|
|
)
|
|
)
|
|
await renameBookmarkCustomization(folderNode.nodePath, newNodePath)
|
|
}
|
|
|
|
const deleteBookmarkFolder = async (folderNode: ComfyNodeDefImpl) => {
|
|
if (!folderNode.isDummyFolder) {
|
|
throw new Error('Cannot delete non-folder node')
|
|
}
|
|
await settingStore.set(
|
|
BOOKMARK_SETTING_ID,
|
|
bookmarks.value.filter(
|
|
(b: string) =>
|
|
b !== folderNode.nodePath && !b.startsWith(folderNode.nodePath)
|
|
)
|
|
)
|
|
await deleteBookmarkCustomization(folderNode.nodePath)
|
|
}
|
|
|
|
const bookmarksCustomization = computed<
|
|
Record<string, BookmarkCustomization>
|
|
>(() => settingStore.get('Comfy.NodeLibrary.BookmarksCustomization'))
|
|
|
|
const updateBookmarkCustomization = async (
|
|
nodePath: string,
|
|
customization: BookmarkCustomization
|
|
) => {
|
|
const currentCustomization = bookmarksCustomization.value[nodePath] || {}
|
|
const newCustomization = { ...currentCustomization, ...customization }
|
|
|
|
// Remove attributes that are set to default values
|
|
if (newCustomization.icon === defaultBookmarkIcon) {
|
|
delete newCustomization.icon
|
|
}
|
|
if (newCustomization.color === defaultBookmarkColor) {
|
|
delete newCustomization.color
|
|
}
|
|
|
|
// If the customization is empty, remove it entirely
|
|
if (Object.keys(newCustomization).length === 0) {
|
|
await deleteBookmarkCustomization(nodePath)
|
|
} else {
|
|
await settingStore.set('Comfy.NodeLibrary.BookmarksCustomization', {
|
|
...bookmarksCustomization.value,
|
|
[nodePath]: newCustomization
|
|
})
|
|
}
|
|
}
|
|
|
|
const deleteBookmarkCustomization = async (nodePath: string) => {
|
|
await settingStore.set('Comfy.NodeLibrary.BookmarksCustomization', {
|
|
...bookmarksCustomization.value,
|
|
[nodePath]: undefined
|
|
} as Record<string, BookmarkCustomization>)
|
|
}
|
|
|
|
const renameBookmarkCustomization = async (
|
|
oldNodePath: string,
|
|
newNodePath: string
|
|
) => {
|
|
const updatedCustomization = { ...bookmarksCustomization.value }
|
|
if (updatedCustomization[oldNodePath]) {
|
|
updatedCustomization[newNodePath] = updatedCustomization[oldNodePath]
|
|
delete updatedCustomization[oldNodePath]
|
|
}
|
|
await settingStore.set(
|
|
'Comfy.NodeLibrary.BookmarksCustomization',
|
|
updatedCustomization
|
|
)
|
|
}
|
|
|
|
const defaultBookmarkIcon = 'pi-bookmark-fill'
|
|
const defaultBookmarkColor = '#a1a1aa'
|
|
|
|
return {
|
|
bookmarks,
|
|
bookmarkedRoot,
|
|
isBookmarked,
|
|
toggleBookmark,
|
|
addBookmark,
|
|
addNewBookmarkFolder,
|
|
renameBookmarkFolder,
|
|
deleteBookmarkFolder,
|
|
|
|
bookmarksCustomization,
|
|
updateBookmarkCustomization,
|
|
deleteBookmarkCustomization,
|
|
renameBookmarkCustomization,
|
|
defaultBookmarkIcon,
|
|
defaultBookmarkColor
|
|
}
|
|
})
|