feat: read category from blueprint subgraph definition

Read category from definitions.subgraphs[0].category in blueprint
JSON files as a fallback default. Overrides from info.category or
explicit category params still take precedence.

Amp-Thread-ID: https://ampcode.com/threads/T-019c6f43-6212-7308-bea6-bfc35a486cbf
This commit is contained in:
bymyself
2026-02-20 21:54:40 -08:00
parent 15c98676e9
commit db86114d7d
2 changed files with 98 additions and 3 deletions

View File

@@ -315,6 +315,96 @@ describe('useSubgraphStore', () => {
})
})
describe('subgraph definition category', () => {
it('should use category from subgraph definition as default', async () => {
const mockGraphWithCategory = {
nodes: [{ type: '123' }],
definitions: {
subgraphs: [{ id: '123', category: 'Image Processing' }]
}
}
await mockFetch(
{},
{
categorized: {
name: 'Categorized Blueprint',
info: { node_pack: 'test_pack' },
data: JSON.stringify(mockGraphWithCategory)
}
}
)
const nodeDef = useNodeDefStore().nodeDefs.find(
(d) => d.name === 'SubgraphBlueprint.categorized'
)
expect(nodeDef).toBeDefined()
expect(nodeDef?.category).toBe('Subgraph Blueprints/Image Processing')
})
it('should use User override for user blueprints even with definition category', async () => {
const mockGraphWithCategory = {
nodes: [{ type: '123' }],
definitions: {
subgraphs: [{ id: '123', category: 'Image Processing' }]
}
}
await mockFetch({ 'user-bp.json': mockGraphWithCategory })
const nodeDef = useNodeDefStore().nodeDefs.find(
(d) => d.name === 'SubgraphBlueprint.user-bp'
)
expect(nodeDef).toBeDefined()
expect(nodeDef?.category).toBe('Subgraph Blueprints/User')
})
it('should fallback to bare Subgraph Blueprints when no category anywhere', async () => {
await mockFetch(
{},
{
no_cat_global: {
name: 'No Category Global',
info: { node_pack: 'test_pack' },
data: JSON.stringify(mockGraph)
}
}
)
const nodeDef = useNodeDefStore().nodeDefs.find(
(d) => d.name === 'SubgraphBlueprint.no_cat_global'
)
expect(nodeDef).toBeDefined()
expect(nodeDef?.category).toBe('Subgraph Blueprints')
})
it('should let overrides take precedence over definition category', async () => {
const mockGraphWithCategory = {
nodes: [{ type: '123' }],
definitions: {
subgraphs: [{ id: '123', category: 'Image Processing' }]
}
}
await mockFetch(
{},
{
bp_override: {
name: 'Override Blueprint',
info: {
node_pack: 'test_pack',
category: 'Custom Category'
},
data: JSON.stringify(mockGraphWithCategory)
}
}
)
const nodeDef = useNodeDefStore().nodeDefs.find(
(d) => d.name === 'SubgraphBlueprint.bp_override'
)
expect(nodeDef).toBeDefined()
expect(nodeDef?.category).toBe('Subgraph Blueprints/Custom Category')
})
})
describe('global blueprint filtering', () => {
function globalBlueprint(
overrides: Partial<GlobalSubgraphData['info']> = {}

View File

@@ -210,13 +210,13 @@ export const useSubgraphStore = defineStore('subgraph', () => {
const loaded = await blueprint.load()
const category = v.info.category
? `Subgraph Blueprints/${v.info.category}`
: 'Subgraph Blueprints'
: undefined
registerNodeDef(
loaded,
{
python_module: v.info.node_pack,
display_name: v.name,
category,
...(category && { category }),
search_aliases: v.info.search_aliases
},
k
@@ -280,6 +280,11 @@ export const useSubgraphStore = defineStore('subgraph', () => {
const description =
workflowExtra?.BlueprintDescription ?? 'User generated subgraph blueprint'
const search_aliases = workflowExtra?.BlueprintSearchAliases
const subgraphDefCategory =
workflow.initialState.definitions?.subgraphs?.[0]?.category
const category = subgraphDefCategory
? `Subgraph Blueprints/${subgraphDefCategory}`
: 'Subgraph Blueprints'
const nodedefv1: ComfyNodeDefV1 = {
input: { required: inputs },
output: subgraphNode.outputs.map((o) => `${o.type}`),
@@ -287,7 +292,7 @@ export const useSubgraphStore = defineStore('subgraph', () => {
name: typePrefix + name,
display_name: name,
description,
category: 'Subgraph Blueprints',
category,
output_node: false,
python_module: 'blueprint',
search_aliases,