From 57b138d866741e859c2861cc120acfbe7bc7de1e Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Sun, 15 Sep 2024 14:01:00 +0900 Subject: [PATCH 01/36] basic/empty model library sidebar tab in-progress --- src/App.vue | 9 ++ .../sidebar/tabs/ModelLibrarySidebarTab.vue | 113 ++++++++++++++++++ src/i18n.ts | 2 + 3 files changed, 124 insertions(+) create mode 100644 src/components/sidebar/tabs/ModelLibrarySidebarTab.vue diff --git a/src/App.vue b/src/App.vue index b0f8755fb..23dd1f2b1 100644 --- a/src/App.vue +++ b/src/App.vue @@ -24,6 +24,7 @@ import { useSettingStore } from './stores/settingStore' import { useI18n } from 'vue-i18n' import { useWorkspaceStore } from './stores/workspaceStateStore' import NodeLibrarySidebarTab from './components/sidebar/tabs/NodeLibrarySidebarTab.vue' +import ModelLibrarySidebarTab from './components/sidebar/tabs/ModelLibrarySidebarTab.vue' import GlobalDialog from './components/dialog/GlobalDialog.vue' import GlobalToast from './components/toast/GlobalToast.vue' import UnloadWindowConfirmDialog from './components/dialog/UnloadWindowConfirmDialog.vue' @@ -100,6 +101,14 @@ const init = () => { component: markRaw(NodeLibrarySidebarTab), type: 'vue' }) + app.extensionManager.registerSidebarTab({ + id: 'model-library', + icon: 'pi pi-folder-open', + title: t('sideToolbar.modelLibrary'), + tooltip: t('sideToolbar.modelLibrary'), + component: markRaw(ModelLibrarySidebarTab), + type: 'vue' + }) } const queuePendingTaskCountStore = useQueuePendingTaskCountStore() diff --git a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue new file mode 100644 index 000000000..578ab59c6 --- /dev/null +++ b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue @@ -0,0 +1,113 @@ + + + + + + + diff --git a/src/i18n.ts b/src/i18n.ts index 6bd2fa3be..f60a44cad 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -37,6 +37,7 @@ const messages = { settings: 'Settings', searchSettings: 'Search Settings', searchNodes: 'Search Nodes', + searchModels: 'Search Models', noResultsFound: 'No Results Found', searchFailedMessage: "We couldn't find any settings matching your search. Try adjusting your search terms.", @@ -50,6 +51,7 @@ const messages = { nodeLibraryTab: { sortOrder: 'Sort Order' }, + modelLibrary: 'Model Library', queueTab: { showFlatList: 'Show Flat List', backToAllTasks: 'Back to All Tasks', From 9df8e33c6aed623774a288a6a559eb494ecf8416 Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Sun, 15 Sep 2024 15:28:04 +0900 Subject: [PATCH 02/36] make it actually list out models --- .../sidebar/tabs/ModelLibrarySidebarTab.vue | 13 +++++------ .../tabs/modelLibrary/ModelTreeFolder.vue | 18 +++++++++++++++ .../tabs/modelLibrary/ModelTreeLeaf.vue | 22 +++++++++++++++++++ src/stores/modelStore.ts | 2 +- 4 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 src/components/sidebar/tabs/modelLibrary/ModelTreeFolder.vue create mode 100644 src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue diff --git a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue index 578ab59c6..6e7b1d510 100644 --- a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue +++ b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue @@ -20,7 +20,7 @@ @nodeClick="handleNodeClick" > @@ -33,6 +33,7 @@ import SearchBox from '@/components/common/SearchBox.vue' import TreeExplorer from '@/components/common/TreeExplorer.vue' import SidebarTabTemplate from '@/components/sidebar/tabs/SidebarTabTemplate.vue' +import ModelTreeLeaf from '@/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue' import { ComfyModelDef, useModelStore } from '@/stores/modelStore' import { useTreeExpansion } from '@/hooks/treeHooks' import type { @@ -50,11 +51,9 @@ const { expandNode, toggleNodeOnEvent } = useTreeExpansion(expandedKeys) const root: ComputedRef = computed(() => { const models = modelStore.modelStoreMap['checkpoints'] - if (!models) { - return null - } - return buildTree(Object.values(models.models), (model: ComfyModelDef) => - model.name.split('/') + const modelList = models ? Object.values(models.models) : [] + return buildTree(modelList, (model: ComfyModelDef) => + model.name.replaceAll('\\', '/').split('/') ) }) @@ -73,7 +72,7 @@ const renderedRoot = computed>(() => { data: node.data, getIcon: (node: TreeExplorerNode) => { if (node.leaf) { - return 'pi pi-circle-fill' + return 'pi pi-file' } }, children, diff --git a/src/components/sidebar/tabs/modelLibrary/ModelTreeFolder.vue b/src/components/sidebar/tabs/modelLibrary/ModelTreeFolder.vue new file mode 100644 index 000000000..b288bd772 --- /dev/null +++ b/src/components/sidebar/tabs/modelLibrary/ModelTreeFolder.vue @@ -0,0 +1,18 @@ + + + diff --git a/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue b/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue new file mode 100644 index 000000000..3a2ee9167 --- /dev/null +++ b/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/src/stores/modelStore.ts b/src/stores/modelStore.ts index 490bad010..ccc83f241 100644 --- a/src/stores/modelStore.ts +++ b/src/stores/modelStore.ts @@ -45,7 +45,7 @@ export class ComfyModelDef { constructor(name: string, directory: string) { this.name = name - this.title = name + this.title = name.replaceAll('\\', '/').split('/').pop() this.directory = directory } From 1a9e9b915ad5a44f642d3856be7d173c9b564b7b Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Sun, 15 Sep 2024 15:33:10 +0900 Subject: [PATCH 03/36] extremely primitive search impl --- .../sidebar/tabs/ModelLibrarySidebarTab.vue | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue index 6e7b1d510..13ae3dc4a 100644 --- a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue +++ b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue @@ -51,7 +51,13 @@ const { expandNode, toggleNodeOnEvent } = useTreeExpansion(expandedKeys) const root: ComputedRef = computed(() => { const models = modelStore.modelStoreMap['checkpoints'] - const modelList = models ? Object.values(models.models) : [] + let modelList = models ? Object.values(models.models) : [] + if (searchQuery.value) { + const search = searchQuery.value.toLocaleLowerCase() + modelList = modelList.filter(m => { + return m.name.toLocaleLowerCase().includes(search); + }); + } return buildTree(modelList, (model: ComfyModelDef) => model.name.replaceAll('\\', '/').split('/') ) @@ -84,9 +90,6 @@ const renderedRoot = computed>(() => { const handleSearch = (query: string) => { // TODO - nextTick(() => { - expandNode(renderedRoot.value) - }) } const handleNodeClick = ( From 2f7ff2e53dd9446bedd6777095eda3cb5327bf7f Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Sun, 15 Sep 2024 15:53:24 +0900 Subject: [PATCH 04/36] list out available folders (incomplete list atm) --- .../sidebar/tabs/ModelLibrarySidebarTab.vue | 46 +++++++++++++++---- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue index 13ae3dc4a..2c26306d4 100644 --- a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue +++ b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue @@ -49,18 +49,37 @@ const searchQuery = ref('') const expandedKeys = ref>({}) const { expandNode, toggleNodeOnEvent } = useTreeExpansion(expandedKeys) +const rootFolders = ['checkpoints', 'loras', 'vae', 'controlnet'] + const root: ComputedRef = computed(() => { - const models = modelStore.modelStoreMap['checkpoints'] - let modelList = models ? Object.values(models.models) : [] + let modelList: ComfyModelDef[] = [] + for (let folder of rootFolders) { + const models = modelStore.modelStoreMap[folder] + if (models) { + modelList.push(...Object.values(models.models)) + } + } if (searchQuery.value) { const search = searchQuery.value.toLocaleLowerCase() - modelList = modelList.filter(m => { - return m.name.toLocaleLowerCase().includes(search); + modelList = modelList.filter((model: ComfyModelDef) => { + return model.name.toLocaleLowerCase().includes(search) }); } - return buildTree(modelList, (model: ComfyModelDef) => - model.name.replaceAll('\\', '/').split('/') - ) + const tree: TreeNode = buildTree(modelList, (model: ComfyModelDef) => { + return [model.directory, ...model.name.replaceAll('\\', '/').split('/')] + }) + for (let folder of rootFolders) { + if (!tree.children.some(c => c.label == folder)) { + const node: TreeNode = { + key: `root/${folder}`, + label: folder, + leaf: false, + children: [] + } + tree.children.push(node) + } + } + return tree }) // Trigger the async operation to fetch models @@ -69,11 +88,20 @@ modelStore.getModelsInFolderCached('checkpoints') const renderedRoot = computed>(() => { const fillNodeInfo = (node: TreeNode): TreeExplorerNode => { const children = node.children?.map(fillNodeInfo) - const model: ComfyModelDef = node.leaf ? node.data : null + const model: ComfyModelDef | null = node.leaf ? node.data : null + if (model && model.name.endsWith('\0')) { + return { + key: node.key, + label: '', + leaf: false, + data: null, + children: [] + } + } return { key: node.key, - label: node.leaf ? model.title : node.label, + label: model ? model.title : node.label, leaf: node.leaf, data: node.data, getIcon: (node: TreeExplorerNode) => { From 486db95941b2c532fd799aa3b4b6d1164e1c7de7 Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Sun, 15 Sep 2024 15:56:03 +0900 Subject: [PATCH 05/36] load list dynamically --- src/components/sidebar/tabs/ModelLibrarySidebarTab.vue | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue index 2c26306d4..be09dcb2f 100644 --- a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue +++ b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue @@ -82,9 +82,6 @@ const root: ComputedRef = computed(() => { return tree }) -// Trigger the async operation to fetch models -modelStore.getModelsInFolderCached('checkpoints') - const renderedRoot = computed>(() => { const fillNodeInfo = (node: TreeNode): TreeExplorerNode => { const children = node.children?.map(fillNodeInfo) @@ -127,6 +124,12 @@ const handleNodeClick = ( if (node.leaf) { // TODO } else { + const folderPath = node.key.split('/').slice(1).join('/') + if (folderPath && !folderPath.includes('/')) { + // trigger (async) load of model data for this folder + // TODO: Append a temporary loading icon if needed? + modelStore.getModelsInFolderCached(folderPath) + } toggleNodeOnEvent(e, node) } } From 07cacec939ca3f20020e7eeb1f331d465c754fea Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Sun, 15 Sep 2024 16:02:19 +0900 Subject: [PATCH 06/36] nice lil loading icon --- .../sidebar/tabs/ModelLibrarySidebarTab.vue | 28 ++++++++----------- src/i18n.ts | 1 + 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue index be09dcb2f..5fac5e826 100644 --- a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue +++ b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue @@ -31,6 +31,7 @@ From 45fdb394e9ff70f625295e174559b93a04908db1 Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Sun, 15 Sep 2024 16:03:19 +0900 Subject: [PATCH 08/36] run autoformatter --- .../sidebar/tabs/ModelLibrarySidebarTab.vue | 17 ++++++++--------- .../sidebar/tabs/modelLibrary/ModelTreeLeaf.vue | 3 +-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue index 5fac5e826..da10578b2 100644 --- a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue +++ b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue @@ -1,7 +1,6 @@ + diff --git a/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue b/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue index 5d372a027..a4fd78474 100644 --- a/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue +++ b/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue @@ -1,15 +1,87 @@ From 9d9d776cfa0a610abed327e729a1c3d82a705139 Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Tue, 17 Sep 2024 14:19:03 +0900 Subject: [PATCH 18/36] update model store tests --- tests-ui/tests/store/modelStore.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests-ui/tests/store/modelStore.test.ts b/tests-ui/tests/store/modelStore.test.ts index d488f2ddd..8d6d5c2ae 100644 --- a/tests-ui/tests/store/modelStore.test.ts +++ b/tests-ui/tests/store/modelStore.test.ts @@ -69,7 +69,8 @@ describe('useModelStore', () => { const folderStore = await store.getModelsInFolderCached('checkpoints') const model = folderStore.models['noinfo.safetensors'] await model.load() - expect(model.title).toBe('noinfo.safetensors') + expect(model.name).toBe('noinfo.safetensors') + expect(model.title).toBe('noinfo') expect(model.architecture_id).toBe('') expect(model.author).toBe('') expect(model.description).toBe('') From f3a4e61a5dd28f1a19c010f1b44a91871c8af462 Mon Sep 17 00:00:00 2001 From: "Alex \"mcmonkey\" Goodwin" Date: Tue, 17 Sep 2024 14:59:08 +0900 Subject: [PATCH 19/36] initial image icon for model lib --- .../sidebar/tabs/ModelLibrarySidebarTab.vue | 3 ++ .../tabs/modelLibrary/ModelTreeLeaf.vue | 37 ++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue index 0d4ef350f..e01a3b2ab 100644 --- a/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue +++ b/src/components/sidebar/tabs/ModelLibrarySidebarTab.vue @@ -102,6 +102,9 @@ const renderedRoot = computed>(() => { data: node.data, getIcon: (node: TreeExplorerNode) => { if (node.leaf) { + if (node.data && node.data.image) { + return '' + } return 'pi pi-file' } }, diff --git a/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue b/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue index a4fd78474..edf255aec 100644 --- a/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue +++ b/src/components/sidebar/tabs/modelLibrary/ModelTreeLeaf.vue @@ -1,6 +1,17 @@