diff --git a/src/components/sidebar/tabs/NodeLibrarySidebarTab.vue b/src/components/sidebar/tabs/NodeLibrarySidebarTab.vue
index 7b1385604f..152302e205 100644
--- a/src/components/sidebar/tabs/NodeLibrarySidebarTab.vue
+++ b/src/components/sidebar/tabs/NodeLibrarySidebarTab.vue
@@ -20,6 +20,14 @@
@click="alphabeticalSort = !alphabeticalSort"
v-tooltip.bottom="$t('sideToolbar.nodeLibraryTab.sortOrder')"
/>
+
| null>(null)
const searchFilter = ref(null)
const alphabeticalSort = ref(false)
+const groupBySource = ref(false)
+
+const createSourceKey = (nodeDef: ComfyNodeDefImpl) => {
+ const sourcePath = nodeDef.python_module.split('.')
+ const pathWithoutCategory = nodeDef.nodePath.split('/').slice(1)
+ return [...sourcePath, ...pathWithoutCategory]
+}
+
+watch(groupBySource, (newValue) => {
+ if (newValue) {
+ nodeDefStore.setKeyFunction(createSourceKey)
+ } else {
+ nodeDefStore.setKeyFunction(null)
+ }
+})
const searchQuery = ref('')
@@ -194,4 +217,9 @@ const onRemoveFilter = (filterAndValue) => {
}
handleSearch(searchQuery.value)
}
+
+// This can be added if the persistent state is not desirable:
+// onBeforeUnmount(() => {
+// nodeDefStore.setKeyFunction(null)
+// })
diff --git a/src/locales/en/main.json b/src/locales/en/main.json
index 8fd22e1e31..854b4a33d5 100644
--- a/src/locales/en/main.json
+++ b/src/locales/en/main.json
@@ -234,7 +234,8 @@
"openWorkflow": "Open workflow in local file system",
"newBlankWorkflow": "Create a new blank workflow",
"nodeLibraryTab": {
- "sortOrder": "Sort Order"
+ "sortOrder": "Sort Order",
+ "groupingType": "Grouping Type"
},
"modelLibrary": "Model Library",
"downloads": "Downloads",
diff --git a/src/stores/nodeDefStore.ts b/src/stores/nodeDefStore.ts
index f6acc73226..60dbc44544 100644
--- a/src/stores/nodeDefStore.ts
+++ b/src/stores/nodeDefStore.ts
@@ -305,9 +305,13 @@ export const SYSTEM_NODE_DEFS: Record = {
}
}
-export function buildNodeDefTree(nodeDefs: ComfyNodeDefImpl[]): TreeNode {
- return buildTree(nodeDefs, (nodeDef: ComfyNodeDefImpl) =>
+export function buildNodeDefTree(
+ nodeDefs: ComfyNodeDefImpl[],
+ keyFunction: (nodeDef: ComfyNodeDefImpl) => string[] = (nodeDef) =>
nodeDef.nodePath.split('/')
+): TreeNode {
+ return buildTree(nodeDefs, (nodeDef: ComfyNodeDefImpl) =>
+ keyFunction(nodeDef)
)
}
@@ -326,12 +330,16 @@ export function createDummyFolderNodeDef(folderPath: string): ComfyNodeDefImpl {
} as ComfyNodeDef)
}
+const getCategoryKeys = (nodeDef: ComfyNodeDefImpl) =>
+ nodeDef.nodePath.split('/')
+
export const useNodeDefStore = defineStore('nodeDef', () => {
const nodeDefsByName = ref>({})
const nodeDefsByDisplayName = ref>({})
const showDeprecated = ref(false)
const showExperimental = ref(false)
+ const keyFunction = ref(getCategoryKeys)
const nodeDefs = computed(() => Object.values(nodeDefsByName.value))
const nodeDataTypes = computed(() => {
const types = new Set()
@@ -355,7 +363,13 @@ export const useNodeDefStore = defineStore('nodeDef', () => {
const nodeSearchService = computed(
() => new NodeSearchService(visibleNodeDefs.value)
)
- const nodeTree = computed(() => buildNodeDefTree(visibleNodeDefs.value))
+ const nodeTree = computed(() =>
+ buildNodeDefTree(visibleNodeDefs.value, keyFunction.value)
+ )
+
+ function setKeyFunction(callback: (nodeDef: ComfyNodeDefImpl) => string[]) {
+ keyFunction.value = callback ?? getCategoryKeys
+ }
function updateNodeDefs(nodeDefs: ComfyNodeDef[]) {
const newNodeDefsByName: Record = {}
@@ -398,7 +412,8 @@ export const useNodeDefStore = defineStore('nodeDef', () => {
updateNodeDefs,
addNodeDef,
- fromLGraphNode
+ fromLGraphNode,
+ setKeyFunction
}
})