From 1bcebd8293bcbf52ee713066898a1e6d0be30bde Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Fri, 20 Feb 2026 22:34:48 -0800 Subject: [PATCH] fix: display Blueprint badge instead of UUID for global subgraph blueprints (#9048) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem The node search box badge displays long UUID strings (e.g., `comfyui-ltx-video-0fbc55c6-...`) for global/core blueprints, while user-created subgraphs correctly show "Blueprint" as the badge. ![image](https://github.com/user-attachments/assets/placeholder-before.png) ## Root Cause In `loadGlobalBlueprint`, global blueprints set `python_module: v.info.node_pack` which contains UUID-like strings. The `getNodeSource()` function processes `python_module` to determine badge text, but UUID strings don't match any known pattern, resulting in ugly badge text. ## Solution - Change global blueprints to use `python_module: 'blueprint'` so they display "Blueprint" badge like user blueprints - Add `isGlobal` boolean flag to `ComfyNodeDef` schema to distinguish global from user blueprints - Update `isGlobalBlueprint()` to check the new `isGlobal` flag instead of `python_module !== 'blueprint'` ## Changes | File | Change | |------|--------| | `src/schemas/nodeDefSchema.ts` | Add optional `isGlobal?: boolean` field | | `src/stores/nodeDefStore.ts` | Add `isGlobal` field to `ComfyNodeDefImpl` class | | `src/stores/subgraphStore.ts` | Use `python_module: 'blueprint'` + `isGlobal: true` for global blueprints; update `isGlobalBlueprint()` check | ## Testing - [x] Existing unit tests pass - [x] TypeScript compiles without errors - [x] Lint passes Fixes COM-15168 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9048-fix-display-Blueprint-badge-instead-of-UUID-for-global-subgraph-blueprints-30e6d73d3650813cac27e02f8f2088df) by [Unito](https://www.unito.io) --- src/schemas/nodeDefSchema.ts | 4 ++- src/stores/nodeDefStore.ts | 3 ++ src/stores/subgraphStore.test.ts | 48 ++++++++++++++++++++++++++++++++ src/stores/subgraphStore.ts | 6 ++-- 4 files changed, 57 insertions(+), 4 deletions(-) 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 {