mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-27 09:45:13 +00:00
feat: wire essentials_category for Essentials tab display (#9091)
## Summary Wire `essentials_category` through from backend to the Essentials tab UI. Creates a single source of truth for node categorization and ordering. ### Changes **New file — `src/constants/essentialsNodes.ts`:** - Single source of truth: `ESSENTIALS_NODES` (ordered nodes per category), `ESSENTIALS_CATEGORIES` (folder display order), `ESSENTIALS_CATEGORY_MAP` (flat lookup), `TOOLKIT_NOVEL_NODE_NAMES` (telemetry), `TOOLKIT_BLUEPRINT_MODULES` **Refactored files:** - `src/types/nodeSource.ts`: Removed inline `ESSENTIALS_CATEGORY_MOCK`, imports `ESSENTIALS_CATEGORY_MAP` from centralized constants - `src/services/nodeOrganizationService.ts`: Removed inline `NODE_ORDER_BY_FOLDER`, imports `ESSENTIALS_NODES` and `ESSENTIALS_CATEGORIES` - `src/constants/toolkitNodes.ts`: Re-exports from `essentialsNodes.ts` instead of maintaining a separate list **Subgraph passthrough:** - `src/stores/subgraphStore.ts`: Passes `essentials_category` from `GlobalSubgraphData` and extracts it from `definitions.subgraphs[0]` as fallback - `src/platform/workflow/validation/schemas/workflowSchema.ts`: Added `essentials_category` to `SubgraphDefinitionBase` and `zSubgraphDefinition` **Tests:** - `src/constants/essentialsNodes.test.ts`: 6 tests validating no duplicates, complete coverage, basics exclusion - `src/stores/subgraphStore.test.ts`: 2 tests for essentials_category passthrough All 43 relevant tests pass. Typecheck, lint, format clean. **Depends on:** Comfy-Org/ComfyUI#12573 Fixes COM-15221 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9091-feat-wire-essentials_category-for-Essentials-tab-display-30f6d73d3650814ab3d4c06b451c273b) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
@@ -515,6 +515,104 @@ describe('useSubgraphStore', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('essentials_category passthrough', () => {
|
||||
it('should prefer GlobalSubgraphData essentials_category over definition fallback', async () => {
|
||||
const graphWithEssentials = {
|
||||
...mockGraph,
|
||||
definitions: {
|
||||
subgraphs: [
|
||||
{
|
||||
...mockGraph.definitions?.subgraphs?.[0],
|
||||
essentials_category: 'Image Tools'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
await mockFetch(
|
||||
{},
|
||||
{
|
||||
bp_precedence: {
|
||||
name: 'Precedence Blueprint',
|
||||
info: { node_pack: 'test_pack' },
|
||||
data: JSON.stringify(graphWithEssentials),
|
||||
essentials_category: 'Video Generation'
|
||||
}
|
||||
}
|
||||
)
|
||||
const nodeDef = useNodeDefStore().nodeDefs.find(
|
||||
(d) => d.name === 'SubgraphBlueprint.bp_precedence'
|
||||
)
|
||||
expect(nodeDef?.essentials_category).toBe('video generation')
|
||||
})
|
||||
|
||||
it('should pass essentials_category from GlobalSubgraphData to node def', async () => {
|
||||
await mockFetch(
|
||||
{},
|
||||
{
|
||||
bp_essentials: {
|
||||
name: 'Test Essentials Blueprint',
|
||||
info: { node_pack: 'test_pack', category: 'Test Category' },
|
||||
data: JSON.stringify(mockGraph),
|
||||
essentials_category: 'Image Generation'
|
||||
}
|
||||
}
|
||||
)
|
||||
const nodeDef = useNodeDefStore().nodeDefs.find(
|
||||
(d) => d.name === 'SubgraphBlueprint.bp_essentials'
|
||||
)
|
||||
expect(nodeDef).toBeDefined()
|
||||
expect(nodeDef?.essentials_category).toBe('image generation')
|
||||
})
|
||||
|
||||
it('should extract essentials_category from subgraph definition as fallback', async () => {
|
||||
const graphWithEssentials = {
|
||||
...mockGraph,
|
||||
definitions: {
|
||||
subgraphs: [
|
||||
{
|
||||
...mockGraph.definitions?.subgraphs?.[0],
|
||||
essentials_category: 'Image Tools'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
await mockFetch(
|
||||
{},
|
||||
{
|
||||
bp_fallback: {
|
||||
name: 'Fallback Blueprint',
|
||||
info: { node_pack: 'test_pack' },
|
||||
data: JSON.stringify(graphWithEssentials)
|
||||
}
|
||||
}
|
||||
)
|
||||
const nodeDef = useNodeDefStore().nodeDefs.find(
|
||||
(d) => d.name === 'SubgraphBlueprint.bp_fallback'
|
||||
)
|
||||
expect(nodeDef).toBeDefined()
|
||||
expect(nodeDef?.essentials_category).toBe('image tools')
|
||||
})
|
||||
|
||||
it('should normalize title-cased essentials_category to canonical form', async () => {
|
||||
await mockFetch(
|
||||
{},
|
||||
{
|
||||
bp_3d: {
|
||||
name: 'Test 3D Blueprint',
|
||||
info: { node_pack: 'test_pack', category: 'Test Category' },
|
||||
data: JSON.stringify(mockGraph),
|
||||
essentials_category: '3d'
|
||||
}
|
||||
}
|
||||
)
|
||||
const nodeDef = useNodeDefStore().nodeDefs.find(
|
||||
(d) => d.name === 'SubgraphBlueprint.bp_3d'
|
||||
)
|
||||
expect(nodeDef).toBeDefined()
|
||||
expect(nodeDef?.essentials_category).toBe('3D')
|
||||
})
|
||||
})
|
||||
|
||||
describe('global blueprint filtering', () => {
|
||||
function globalBlueprint(
|
||||
overrides: Partial<GlobalSubgraphData['info']> = {}
|
||||
|
||||
@@ -222,6 +222,9 @@ export const useSubgraphStore = defineStore('subgraph', () => {
|
||||
{
|
||||
display_name: v.name,
|
||||
...(category && { category }),
|
||||
...(v.essentials_category && {
|
||||
essentials_category: v.essentials_category
|
||||
}),
|
||||
search_aliases: v.info.search_aliases,
|
||||
isGlobal: true
|
||||
},
|
||||
@@ -291,6 +294,8 @@ export const useSubgraphStore = defineStore('subgraph', () => {
|
||||
const search_aliases = workflowExtra?.BlueprintSearchAliases
|
||||
const subgraphDefCategory =
|
||||
workflow.initialState.definitions?.subgraphs?.[0]?.category
|
||||
const subgraphDefEssentialsCategory =
|
||||
workflow.initialState.definitions?.subgraphs?.[0]?.essentials_category
|
||||
const category = subgraphDefCategory
|
||||
? `Subgraph Blueprints/${subgraphDefCategory}`
|
||||
: 'Subgraph Blueprints'
|
||||
@@ -305,6 +310,7 @@ export const useSubgraphStore = defineStore('subgraph', () => {
|
||||
output_node: false,
|
||||
python_module: 'blueprint',
|
||||
search_aliases,
|
||||
essentials_category: subgraphDefEssentialsCategory,
|
||||
...overrides
|
||||
}
|
||||
const nodeDefImpl = new ComfyNodeDefImpl(nodedefv1)
|
||||
|
||||
Reference in New Issue
Block a user