mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-28 02:34:10 +00:00
feat: show missing node packs in Errors Tab with install support (#9213)
## Summary Surfaces missing node pack information in the Errors Tab, grouped by registry pack, with one-click install support via ComfyUI Manager. ## Changes - **What**: Errors Tab now groups missing nodes by their registry pack and shows a `MissingPackGroupRow` with pack name, node/pack counts, and an Install button that triggers Manager installation. A `MissingNodeCard` shows individual unresolvable nodes that have no associated pack. `useErrorGroups` was extended to resolve missing node types to their registry packs using the `/api/workflow/missing_nodes` endpoint. `executionErrorStore` was refactored to track missing node types separately from execution errors and expose them reactively. - **Breaking**: None ## Review Focus - `useErrorGroups.ts` — the new `resolveMissingNodePacks` logic fetches pack metadata and maps node types to pack IDs; edge cases around partial resolution (some nodes have a pack, some don't) produce both `MissingPackGroupRow` and `MissingNodeCard` entries - `executionErrorStore.ts` — the store now separates `missingNodeTypes` state from `errors`; the deferred-warnings path in `app.ts` now calls `setMissingNodeTypes` so the Errors Tab is populated even when a workflow loads without executing ## Screenshots (if applicable) https://github.com/user-attachments/assets/97f8d009-0cac-4739-8740-fd3333b5a85b ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9213-feat-show-missing-node-packs-in-Errors-Tab-with-install-support-3126d73d36508197bc4bf8ebfd2125c8) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -56,6 +56,7 @@ describe('createMissingNodeTypeFromError', () => {
|
||||
})
|
||||
expect(result).toEqual({
|
||||
type: 'MyNodeClass',
|
||||
nodeId: '42',
|
||||
hint: '"My Custom Title" (Node ID #42)'
|
||||
})
|
||||
})
|
||||
@@ -68,6 +69,7 @@ describe('createMissingNodeTypeFromError', () => {
|
||||
})
|
||||
expect(result).toEqual({
|
||||
type: 'Unknown',
|
||||
nodeId: '42',
|
||||
hint: '"Some Title" (Node ID #42)'
|
||||
})
|
||||
})
|
||||
@@ -84,6 +86,7 @@ describe('createMissingNodeTypeFromError', () => {
|
||||
})
|
||||
expect(result).toEqual({
|
||||
type: 'MyNodeClass',
|
||||
nodeId: '123',
|
||||
hint: 'Node ID #123'
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import type { MissingNodeType } from '@/types/comfy'
|
||||
|
||||
import type { MissingNodeTypeExtraInfo } from '../types/missingNodeErrorTypes'
|
||||
@@ -33,5 +34,38 @@ export function createMissingNodeTypeFromError(
|
||||
const nodeTitle = extraInfo.node_title ?? classType
|
||||
const hint = buildMissingNodeHint(nodeTitle, classType, extraInfo.node_id)
|
||||
|
||||
return hint ? { type: classType, hint } : classType
|
||||
if (hint) {
|
||||
return {
|
||||
type: classType,
|
||||
...(extraInfo.node_id ? { nodeId: extraInfo.node_id } : {}),
|
||||
...(hint ? { hint } : {})
|
||||
}
|
||||
}
|
||||
return classType
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the custom node registry ID (cnr_id or aux_id) from a raw
|
||||
* properties bag.
|
||||
*
|
||||
* @param properties - The properties object to inspect
|
||||
* @returns The cnrId string, or undefined if not found
|
||||
*/
|
||||
export function getCnrIdFromProperties(
|
||||
properties: Record<string, unknown> | undefined | null
|
||||
): string | undefined {
|
||||
if (typeof properties?.cnr_id === 'string') return properties.cnr_id
|
||||
if (typeof properties?.aux_id === 'string') return properties.aux_id
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the custom node registry ID (cnr_id or aux_id) from a node's properties.
|
||||
* Returns undefined if neither property is present.
|
||||
*
|
||||
* @param node - The graph node to inspect
|
||||
* @returns The cnrId string, or undefined if not found
|
||||
*/
|
||||
export function getCnrIdFromNode(node: LGraphNode): string | undefined {
|
||||
return getCnrIdFromProperties(node.properties as Record<string, unknown>)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user