diff --git a/src/schemas/nodeDefSchema.ts b/src/schemas/nodeDefSchema.ts index 97d0dc6e5..466711fa2 100644 --- a/src/schemas/nodeDefSchema.ts +++ b/src/schemas/nodeDefSchema.ts @@ -298,7 +298,9 @@ export const zComfyNodeDef = z.object({ */ price_badge: zPriceBadge.optional(), /** Category for the Essentials tab. If set, the node appears in Essentials. */ - essentials_category: z.string().optional() + essentials_category: z.string().optional(), + /** Whether the blueprint is a global/installed blueprint (not user-created). */ + isGlobal: z.boolean().optional() }) export const zAutogrowOptions = z.object({ diff --git a/src/stores/nodeDefStore.ts b/src/stores/nodeDefStore.ts index 86419e109..3b9553981 100644 --- a/src/stores/nodeDefStore.ts +++ b/src/stores/nodeDefStore.ts @@ -89,6 +89,8 @@ export class ComfyNodeDefImpl readonly search_aliases?: string[] /** Category for the Essentials tab. If set, the node appears in Essentials. */ readonly essentials_category?: string + /** Whether the blueprint is a global/installed blueprint (not user-created). */ + readonly isGlobal?: boolean // V2 fields readonly inputs: Record @@ -165,6 +167,7 @@ export class ComfyNodeDefImpl obj.name, obj.essentials_category ) + this.isGlobal = obj.isGlobal // Initialize V2 fields const defV2 = transformNodeDefV1ToV2(obj) diff --git a/src/stores/subgraphStore.test.ts b/src/stores/subgraphStore.test.ts index 92457598d..a354a1996 100644 --- a/src/stores/subgraphStore.test.ts +++ b/src/stores/subgraphStore.test.ts @@ -177,6 +177,54 @@ describe('useSubgraphStore', () => { expect(store.isGlobalBlueprint('nonexistent')).toBe(false) }) + describe('blueprint badge display', () => { + it('should set isGlobal flag on global blueprints', async () => { + await mockFetch( + {}, + { + global_bp: { + name: 'Global Blueprint', + info: { node_pack: 'some-uuid-string' }, + data: JSON.stringify(mockGraph) + } + } + ) + const nodeDef = useNodeDefStore().nodeDefs.find( + (d) => d.name === 'SubgraphBlueprint.global_bp' + ) + expect(nodeDef).toBeDefined() + expect(nodeDef?.isGlobal).toBe(true) + }) + + it('should not set isGlobal flag on user blueprints', async () => { + await mockFetch({ 'user-blueprint.json': mockGraph }) + const nodeDef = useNodeDefStore().nodeDefs.find( + (d) => d.name === 'SubgraphBlueprint.user-blueprint' + ) + expect(nodeDef).toBeDefined() + expect(nodeDef?.isGlobal).toBeUndefined() + }) + + it('should use blueprint python_module for global blueprints to show Blueprint badge', async () => { + await mockFetch( + {}, + { + global_bp: { + name: 'Global Blueprint', + info: { node_pack: 'comfyui-ltx-video-0fbc55c6-long-uuid' }, + data: JSON.stringify(mockGraph) + } + } + ) + const nodeDef = useNodeDefStore().nodeDefs.find( + (d) => d.name === 'SubgraphBlueprint.global_bp' + ) + expect(nodeDef).toBeDefined() + expect(nodeDef?.python_module).toBe('blueprint') + expect(nodeDef?.nodeSource.displayText).toBe('Blueprint') + }) + }) + describe('search_aliases support', () => { it('should include search_aliases from workflow extra', async () => { const mockGraphWithAliases = { diff --git a/src/stores/subgraphStore.ts b/src/stores/subgraphStore.ts index c911e19df..7bf3b078f 100644 --- a/src/stores/subgraphStore.ts +++ b/src/stores/subgraphStore.ts @@ -214,10 +214,10 @@ export const useSubgraphStore = defineStore('subgraph', () => { registerNodeDef( loaded, { - python_module: v.info.node_pack, display_name: v.name, category, - search_aliases: v.info.search_aliases + search_aliases: v.info.search_aliases, + isGlobal: true }, k ) @@ -410,7 +410,7 @@ export const useSubgraphStore = defineStore('subgraph', () => { function isGlobalBlueprint(name: string): boolean { const nodeDef = subgraphDefCache.value.get(name) - return nodeDef !== undefined && nodeDef.python_module !== 'blueprint' + return nodeDef !== undefined && nodeDef.isGlobal === true } return {