feat: add node replacement UI to Errors Tab

Integrate the existing node replacement functionality into the Errors
Tab, allowing users to replace missing nodes directly from the side
panel without opening the modal dialog.
New components:
- SwapNodesCard: container with guidance label and grouped rows
- SwapNodeGroupRow: per-type replacement row with expand/collapse,
  node instance list, locate button, and replace action
Bug fixes discovered during implementation:
- Fix stale canvas rendering after replacement by calling onNodeAdded
  to refresh VueNodeData (bypassed by replaceWithMapping)
- Guard initializeVueNodeLayout against duplicate layout creation
- Fix missing node list being overwritten by incomplete server 400
  response — replaced with full graph rescan via useMissingNodeScan
- Add removeMissingNodesByType to prune replaced types from error list
Cleanup:
- Remove dead code: buildMissingNodeHint, createMissingNodeTypeFromError
This commit is contained in:
jaeone94
2026-02-26 19:53:15 +09:00
parent 45ca1beea2
commit 0d58a92e34
14 changed files with 396 additions and 171 deletions

View File

@@ -1,48 +1,4 @@
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
import type { MissingNodeType } from '@/types/comfy'
import type { MissingNodeTypeExtraInfo } from '../types/missingNodeErrorTypes'
/**
* Builds a hint string from missing node metadata.
* Provides context about which node is missing (title, ID) when available.
*/
export function buildMissingNodeHint(
nodeTitle: string | null | undefined,
classType: string,
nodeId: string | undefined
): string | undefined {
const hasTitle = nodeTitle && nodeTitle !== classType
if (hasTitle && nodeId) {
return `"${nodeTitle}" (Node ID #${nodeId})`
} else if (hasTitle) {
return `"${nodeTitle}"`
} else if (nodeId) {
return `Node ID #${nodeId}`
}
return undefined
}
/**
* Creates a MissingNodeType from backend error extra_info.
* Used when the /prompt endpoint returns a missing_node_type error.
*/
export function createMissingNodeTypeFromError(
extraInfo: MissingNodeTypeExtraInfo
): MissingNodeType {
const classType = extraInfo.class_type ?? 'Unknown'
const nodeTitle = extraInfo.node_title ?? classType
const hint = buildMissingNodeHint(nodeTitle, classType, extraInfo.node_id)
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