diff --git a/web/extensions/core/groupNode.js b/web/extensions/core/groupNode.js index 4b4bf74f..6766f356 100644 --- a/web/extensions/core/groupNode.js +++ b/web/extensions/core/groupNode.js @@ -475,6 +475,16 @@ export class GroupNodeConfig { } static async registerFromWorkflow(groupNodes, missingNodeTypes) { + const clean = app.clean; + app.clean = function () { + for (const g in groupNodes) { + try { + LiteGraph.unregisterNodeType("workflow/" + g); + } catch (error) {} + } + app.clean = clean; + }; + for (const g in groupNodes) { const groupData = groupNodes[g]; @@ -482,7 +492,24 @@ export class GroupNodeConfig { for (const n of groupData.nodes) { // Find missing node types if (!(n.type in LiteGraph.registered_node_types)) { - missingNodeTypes.push(n.type); + missingNodeTypes.push({ + type: n.type, + hint: ` (In group node 'workflow/${g}')`, + }); + + missingNodeTypes.push({ + type: "workflow/" + g, + action: { + text: "Remove from workflow", + callback: (e) => { + delete groupNodes[g]; + e.target.textContent = "Removed"; + e.target.style.pointerEvents = "none"; + e.target.style.opacity = 0.7; + }, + }, + }); + hasMissing = true; } } diff --git a/web/scripts/app.js b/web/scripts/app.js index dc0f2c3c..b3a22f30 100644 --- a/web/scripts/app.js +++ b/web/scripts/app.js @@ -1519,14 +1519,36 @@ export class ComfyApp { } showMissingNodesError(missingNodeTypes, hasAddedNodes = true) { + let seenTypes = new Set(); + this.ui.dialog.show( - $el("div", [ + $el("div.comfy-missing-nodes", [ $el("span", { textContent: "When loading the graph, the following node types were not found: " }), $el( "ul", - Array.from(new Set(missingNodeTypes)).map((t) => $el("li", { textContent: t })) + Array.from(new Set(missingNodeTypes)).map((t) => { + let children = []; + if (typeof t === "object") { + if(seenTypes.has(t.type)) return null; + seenTypes.add(t.type); + children.push($el("span", { textContent: t.type })); + if (t.hint) { + children.push($el("span", { textContent: t.hint })); + } + if (t.action) { + children.push($el("button", { onclick: t.action.callback, textContent: t.action.text })); + } + } else { + if(seenTypes.has(t)) return null; + seenTypes.add(t); + children.push($el("span", { textContent: t })); + } + return $el("li", children); + }).filter(Boolean) ), - ...(hasAddedNodes ? [$el("span", { textContent: "Nodes that have failed to load will show as red on the graph." })] : []), + ...(hasAddedNodes + ? [$el("span", { textContent: "Nodes that have failed to load will show as red on the graph." })] + : []), ]) ); this.logging.addEntry("Comfy.App", "warn", { diff --git a/web/style.css b/web/style.css index 378fe0a4..630eea12 100644 --- a/web/style.css +++ b/web/style.css @@ -424,6 +424,11 @@ dialog::backdrop { height: var(--comfy-img-preview-height); } +.comfy-missing-nodes li button { + font-size: 12px; + margin-left: 5px; +} + /* Search box */ .litegraph.litesearchbox {