From 5f51ed4bd7838a778d5f2279e42c12d2671f0cb2 Mon Sep 17 00:00:00 2001 From: space-nuko <24979496+space-nuko@users.noreply.github.com> Date: Thu, 1 Jun 2023 08:51:32 -0500 Subject: [PATCH 01/12] Check for existence of Notification safely --- src/lib/components/ComfyApp.ts | 8 +++++--- src/lib/notify.ts | 5 +++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/lib/components/ComfyApp.ts b/src/lib/components/ComfyApp.ts index 2c77775..e4c7625 100644 --- a/src/lib/components/ComfyApp.ts +++ b/src/lib/components/ComfyApp.ts @@ -728,9 +728,11 @@ export default class ComfyApp { } private requestPermissions() { - if (Notification.permission === "default") { - Notification.requestPermission() - .then((result) => console.log("Notification status:", result)); + if (window.Notification != null) { + if (window.Notification.permission === "default") { + window.Notification.requestPermission() + .then((result) => console.log("Notification status:", result)); + } } } diff --git a/src/lib/notify.ts b/src/lib/notify.ts index 80a0f2c..90caee9 100644 --- a/src/lib/notify.ts +++ b/src/lib/notify.ts @@ -92,6 +92,11 @@ function notifyToast(text: string, options: NotifyOptions) { } function notifyNative(text: string, options: NotifyOptions) { + if (window.Notification == null) { + console.warn("[notify] No Notification available on window") + return + } + if (document.hasFocus()) return; From 634d16a18244b9b23995df5ca1647932601754f3 Mon Sep 17 00:00:00 2001 From: space-nuko <24979496+space-nuko@users.noreply.github.com> Date: Thu, 1 Jun 2023 12:38:35 -0500 Subject: [PATCH 02/12] Show an X if PickFirst fails to find a good input --- src/lib/nodes/ComfyPickFirstNode.ts | 33 ++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/lib/nodes/ComfyPickFirstNode.ts b/src/lib/nodes/ComfyPickFirstNode.ts index 32f2566..1669dc8 100644 --- a/src/lib/nodes/ComfyPickFirstNode.ts +++ b/src/lib/nodes/ComfyPickFirstNode.ts @@ -40,17 +40,34 @@ export default class ComfyPickFirstNode extends ComfyGraphNode { } override onDrawBackground(ctx: CanvasRenderingContext2D) { - if (this.flags.collapsed || this.selected === -1) { + if (this.flags.collapsed) { return; } - ctx.fillStyle = "#AFB"; - var y = (this.selected) * LiteGraph.NODE_SLOT_HEIGHT + 6; - ctx.beginPath(); - ctx.moveTo(50, y); - ctx.lineTo(50, y + LiteGraph.NODE_SLOT_HEIGHT); - ctx.lineTo(34, y + LiteGraph.NODE_SLOT_HEIGHT * 0.5); - ctx.fill(); + if (this.selected === -1) { + // Draw an X + const y = LiteGraph.NODE_SLOT_HEIGHT + 6; + ctx.lineWidth = 5; + ctx.strokeStyle = "red"; + ctx.beginPath(); + + ctx.moveTo(50 - 15, y - 15); + ctx.lineTo(50 + 15, y + 15); + ctx.stroke(); + + ctx.moveTo(50 + 15, y - 15); + ctx.lineTo(50 - 15, y + 15); + ctx.stroke(); + } + else { + ctx.fillStyle = "#AFB"; + const y = (this.selected) * LiteGraph.NODE_SLOT_HEIGHT + 6; + ctx.beginPath(); + ctx.moveTo(50, y); + ctx.lineTo(50, y + LiteGraph.NODE_SLOT_HEIGHT); + ctx.lineTo(34, y + LiteGraph.NODE_SLOT_HEIGHT * 0.5); + ctx.fill(); + } }; override onConnectionsChange( From afd3c05d0b51adfe751a52193cf4c14f3d22987d Mon Sep 17 00:00:00 2001 From: space-nuko <24979496+space-nuko@users.noreply.github.com> Date: Thu, 1 Jun 2023 12:54:27 -0500 Subject: [PATCH 03/12] Count disconnected frontend nodes in upstream check Closes #103 --- src/lib/components/ComfyGraphErrorList.svelte | 11 +- src/lib/components/ComfyPromptSerializer.ts | 118 +++++++++--------- src/lib/nodes/ComfyPickFirstNode.ts | 11 +- 3 files changed, 72 insertions(+), 68 deletions(-) diff --git a/src/lib/components/ComfyGraphErrorList.svelte b/src/lib/components/ComfyGraphErrorList.svelte index 7680169..f8a669b 100644 --- a/src/lib/components/ComfyGraphErrorList.svelte +++ b/src/lib/components/ComfyGraphErrorList.svelte @@ -4,8 +4,8 @@ import Accordion from "./gradio/app/Accordion.svelte"; import uiState from '$lib/stores/uiState'; import type { ComfyNodeDefInputType } from "$lib/ComfyNodeDef"; - import type { INodeInputSlot, LGraphNode, Subgraph } from "@litegraph-ts/core"; - import { UpstreamNodeLocator } from "./ComfyPromptSerializer"; + import type { INodeInputSlot, LGraphNode, LLink, Subgraph } from "@litegraph-ts/core"; + import { UpstreamNodeLocator, getUpstreamLink } from "./ComfyPromptSerializer"; import JsonView from "./JsonView.svelte"; export let app: ComfyApp; @@ -35,7 +35,7 @@ const node = app.lCanvas.graph.getNodeByIdRecursive(error.nodeID); - const inputIndex =node.findInputSlotIndexByName(error.input.name); + const inputIndex = node.findInputSlotIndexByName(error.input.name); if (inputIndex === -1) { return } @@ -43,7 +43,10 @@ // TODO multiple tags? const tag: string | null = error.queueEntry.extraData.extra_pnginfo.comfyBoxPrompt.subgraphs[0]; - const test = (node: LGraphNode) => (node as any).isBackendNode + const test = (node: LGraphNode, currentLink: LLink) => { + const [nextGraph, nextLink, nextInputSlot, nextNode] = getUpstreamLink(node, currentLink) + return nextLink == null; + }; const nodeLocator = new UpstreamNodeLocator(test) const [_, foundLink, foundInputSlot, foundPrevNode] = nodeLocator.locateUpstream(node, inputIndex, tag); diff --git a/src/lib/components/ComfyPromptSerializer.ts b/src/lib/components/ComfyPromptSerializer.ts index 51808d4..cfb5786 100644 --- a/src/lib/components/ComfyPromptSerializer.ts +++ b/src/lib/components/ComfyPromptSerializer.ts @@ -71,62 +71,62 @@ export function isActiveBackendNode(node: LGraphNode, tag: string | null = null) return true; } -type UpstreamResult = [LGraph | null, LLink | null, number | null, LGraphNode | null]; +export type UpstreamResult = [LGraph | null, LLink | null, number | null, LGraphNode | null]; + +function followSubgraph(subgraph: Subgraph, link: LLink): UpstreamResult { + if (link.origin_id != subgraph.id) + throw new Error("Invalid link and graph output!") + + const innerGraphOutput = subgraph.getInnerGraphOutputByIndex(link.origin_slot) + if (innerGraphOutput == null) + throw new Error("No inner graph input!") + + const nextLink = innerGraphOutput.getInputLink(0) + return [innerGraphOutput.graph, nextLink, 0, innerGraphOutput]; +} + +function followGraphInput(graphInput: GraphInput, link: LLink): UpstreamResult { + if (link.origin_id != graphInput.id) + throw new Error("Invalid link and graph input!") + + const outerSubgraph = graphInput.getParentSubgraph(); + if (outerSubgraph == null) + throw new Error("No outer subgraph!") + + const outerInputIndex = outerSubgraph.inputs.findIndex(i => i.name === graphInput.nameInGraph) + if (outerInputIndex == null) + throw new Error("No outer input slot!") + + const nextLink = outerSubgraph.getInputLink(outerInputIndex) + return [outerSubgraph.graph, nextLink, outerInputIndex, outerSubgraph]; +} + +export function getUpstreamLink(parent: LGraphNode, currentLink: LLink): UpstreamResult { + if (parent.is(Subgraph)) { + console.debug("FollowSubgraph") + return followSubgraph(parent, currentLink); + } + else if (parent.is(GraphInput)) { + console.debug("FollowGraphInput") + return followGraphInput(parent, currentLink); + } + else if ("getUpstreamLink" in parent) { + const link = (parent as ComfyGraphNode).getUpstreamLink(); + return [parent.graph, link, link?.target_slot, parent]; + } + else if (parent.inputs.length === 1) { + // Only one input, so assume we can follow it backwards. + const link = parent.getInputLink(0); + if (link) { + return [parent.graph, link, 0, parent] + } + } + console.warn("[graphToPrompt] Frontend node does not support getUpstreamLink", parent.type) + return [null, null, null, null]; +} export class UpstreamNodeLocator { - constructor(private isTheTargetNode: (node: LGraphNode) => boolean) { - } - - private followSubgraph(subgraph: Subgraph, link: LLink): UpstreamResult { - if (link.origin_id != subgraph.id) - throw new Error("Invalid link and graph output!") - - const innerGraphOutput = subgraph.getInnerGraphOutputByIndex(link.origin_slot) - if (innerGraphOutput == null) - throw new Error("No inner graph input!") - - const nextLink = innerGraphOutput.getInputLink(0) - return [innerGraphOutput.graph, nextLink, 0, innerGraphOutput]; - } - - private followGraphInput(graphInput: GraphInput, link: LLink): UpstreamResult { - if (link.origin_id != graphInput.id) - throw new Error("Invalid link and graph input!") - - const outerSubgraph = graphInput.getParentSubgraph(); - if (outerSubgraph == null) - throw new Error("No outer subgraph!") - - const outerInputIndex = outerSubgraph.inputs.findIndex(i => i.name === graphInput.nameInGraph) - if (outerInputIndex == null) - throw new Error("No outer input slot!") - - const nextLink = outerSubgraph.getInputLink(outerInputIndex) - return [outerSubgraph.graph, nextLink, outerInputIndex, outerSubgraph]; - } - - private getUpstreamLink(parent: LGraphNode, currentLink: LLink): UpstreamResult { - if (parent.is(Subgraph)) { - console.debug("FollowSubgraph") - return this.followSubgraph(parent, currentLink); - } - else if (parent.is(GraphInput)) { - console.debug("FollowGraphInput") - return this.followGraphInput(parent, currentLink); - } - else if ("getUpstreamLink" in parent) { - const link = (parent as ComfyGraphNode).getUpstreamLink(); - return [parent.graph, link, link?.target_slot, parent]; - } - else if (parent.inputs.length === 1) { - // Only one input, so assume we can follow it backwards. - const link = parent.getInputLink(0); - if (link) { - return [parent.graph, link, 0, parent] - } - } - console.warn("[graphToPrompt] Frontend node does not support getUpstreamLink", parent.type) - return [null, null, null, null]; + constructor(private isTheTargetNode: (node: LGraphNode, currentLink: LLink) => boolean) { } /* @@ -146,8 +146,8 @@ export class UpstreamNodeLocator { let currentInputSlot = inputIndex; let currentNode = fromNode; - const shouldFollowParent = (parent: LGraphNode) => { - return isActiveNode(parent, tag) && !this.isTheTargetNode(parent); + const shouldFollowParent = (parent: LGraphNode, currentLink: LLink) => { + return isActiveNode(parent, tag) && !this.isTheTargetNode(parent, currentLink); } // If there are non-target nodes between us and another @@ -156,8 +156,8 @@ export class UpstreamNodeLocator { // will simply follow their single input, while branching // nodes have conditional logic that determines which link // to follow backwards. - while (shouldFollowParent(parent)) { - const [nextGraph, nextLink, nextInputSlot, nextNode] = this.getUpstreamLink(parent, currentLink); + while (shouldFollowParent(parent, currentLink)) { + const [nextGraph, nextLink, nextInputSlot, nextNode] = getUpstreamLink(parent, currentLink); currentInputSlot = nextInputSlot; currentNode = nextNode; @@ -183,7 +183,7 @@ export class UpstreamNodeLocator { } } - if (!isActiveNode(parent, tag) || !this.isTheTargetNode(parent) || currentLink == null) + if (!isActiveNode(parent, tag) || !this.isTheTargetNode(parent, currentLink) || currentLink == null) return [null, currentLink, currentInputSlot, currentNode]; return [parent, currentLink, currentInputSlot, currentNode] diff --git a/src/lib/nodes/ComfyPickFirstNode.ts b/src/lib/nodes/ComfyPickFirstNode.ts index 1669dc8..50d5875 100644 --- a/src/lib/nodes/ComfyPickFirstNode.ts +++ b/src/lib/nodes/ComfyPickFirstNode.ts @@ -3,7 +3,7 @@ import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode" import { Watch } from "@litegraph-ts/nodes-basic"; import { nextLetter } from "$lib/utils"; -export type PickFirstMode = "anyActiveLink" | "truthy" | "dataNonNull" +export type PickFirstMode = "anyActiveLink" | "dataTruthy" | "dataNonNull" export interface ComfyPickFirstNodeProperties extends ComfyGraphNodeProperties { mode: PickFirstMode @@ -12,7 +12,7 @@ export interface ComfyPickFirstNodeProperties extends ComfyGraphNodeProperties { export default class ComfyPickFirstNode extends ComfyGraphNode { override properties: ComfyPickFirstNodeProperties = { tags: [], - mode: "dataNonNull" + mode: "anyActiveLink" } static slotLayout: SlotLayout = { @@ -36,7 +36,7 @@ export default class ComfyPickFirstNode extends ComfyGraphNode { super(title); this.displayWidget = this.addWidget("text", "Value", "") this.displayWidget.disabled = true; - this.modeWidget = this.addWidget("combo", "Mode", this.properties.mode, null, { property: "mode", values: ["anyActiveLink", "truthy", "dataNonNull"] }) + this.modeWidget = this.addWidget("combo", "Mode", this.properties.mode, null, { property: "mode", values: ["anyActiveLink", "dataTruthy", "dataNonNull"] }) } override onDrawBackground(ctx: CanvasRenderingContext2D) { @@ -45,7 +45,7 @@ export default class ComfyPickFirstNode extends ComfyGraphNode { } if (this.selected === -1) { - // Draw an X + // Draw an X indicating nothing matched the selection criteria const y = LiteGraph.NODE_SLOT_HEIGHT + 6; ctx.lineWidth = 5; ctx.strokeStyle = "red"; @@ -60,6 +60,7 @@ export default class ComfyPickFirstNode extends ComfyGraphNode { ctx.stroke(); } else { + // Draw an arrow pointing to the selected input ctx.fillStyle = "#AFB"; const y = (this.selected) * LiteGraph.NODE_SLOT_HEIGHT + 6; ctx.beginPath(); @@ -130,7 +131,7 @@ export default class ComfyPickFirstNode extends ComfyGraphNode { else { if (this.properties.mode === "dataNonNull") return link.data != null; - else if (this.properties.mode === "truthy") + else if (this.properties.mode === "dataTruthy") return Boolean(link.data) else // anyActiveLink return true; From e8539add51f84a88bfa40a2f08bb5c34c171c77f Mon Sep 17 00:00:00 2001 From: space-nuko <24979496+space-nuko@users.noreply.github.com> Date: Thu, 1 Jun 2023 16:24:17 -0500 Subject: [PATCH 04/12] Fix missing index check --- src/lib/components/ComfyPromptSerializer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/ComfyPromptSerializer.ts b/src/lib/components/ComfyPromptSerializer.ts index cfb5786..ec21339 100644 --- a/src/lib/components/ComfyPromptSerializer.ts +++ b/src/lib/components/ComfyPromptSerializer.ts @@ -94,7 +94,7 @@ function followGraphInput(graphInput: GraphInput, link: LLink): UpstreamResult { throw new Error("No outer subgraph!") const outerInputIndex = outerSubgraph.inputs.findIndex(i => i.name === graphInput.nameInGraph) - if (outerInputIndex == null) + if (outerInputIndex === -1) throw new Error("No outer input slot!") const nextLink = outerSubgraph.getInputLink(outerInputIndex) From b1dd8a624223a154f62e444b4b356eb731121970 Mon Sep 17 00:00:00 2001 From: space-nuko <24979496+space-nuko@users.noreply.github.com> Date: Thu, 1 Jun 2023 18:43:45 -0500 Subject: [PATCH 05/12] Default workflow subgraph attribute --- src/lib/components/ComfyApp.ts | 6 +++++- src/lib/stores/layoutStates.ts | 7 +++++++ src/lib/stores/workflowState.ts | 6 ++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/lib/components/ComfyApp.ts b/src/lib/components/ComfyApp.ts index e4c7625..7078f29 100644 --- a/src/lib/components/ComfyApp.ts +++ b/src/lib/components/ComfyApp.ts @@ -941,7 +941,11 @@ export default class ComfyApp { if (workflow.attrs.queuePromptButtonRunWorkflow) { // Hold control to queue at the front const num = this.ctrlDown ? -1 : 0; - this.queuePrompt(workflow, num, 1); + let tag = null; + if (workflow.attrs.queuePromptButtonDefaultWorkflow) { + tag = workflow.attrs.queuePromptButtonDefaultWorkflow + } + this.queuePrompt(workflow, num, 1, tag); } } diff --git a/src/lib/stores/layoutStates.ts b/src/lib/stores/layoutStates.ts index 0dcd911..bae1f34 100644 --- a/src/lib/stores/layoutStates.ts +++ b/src/lib/stores/layoutStates.ts @@ -681,6 +681,13 @@ const ALL_ATTRIBUTES: AttributesSpecList = [ editable: true, defaultValue: true }, + { + name: "queuePromptButtonDefaultWorkflow", + type: "string", + location: "workflow", + editable: true, + defaultValue: "" + }, { name: "showDefaultNotifications", type: "boolean", diff --git a/src/lib/stores/workflowState.ts b/src/lib/stores/workflowState.ts index c7e0707..559a969 100644 --- a/src/lib/stores/workflowState.ts +++ b/src/lib/stores/workflowState.ts @@ -57,6 +57,12 @@ export type WorkflowAttributes = { */ queuePromptButtonRunWorkflow: boolean, + /* + * Default subgraph to run if `queuePromptButtonRunWorkflow` is `true`. Set + * to blank to run the default subgraph (tagless). + */ + queuePromptButtonDefaultWorkflow: string, + /* * If true, notifications will be shown when a prompt is queued and * completed. Set to false if you need more detailed control over the From 4923a78d7cf1d53f082ee9cab9a7fe0f60e2394c Mon Sep 17 00:00:00 2001 From: space-nuko <24979496+space-nuko@users.noreply.github.com> Date: Thu, 1 Jun 2023 18:44:02 -0500 Subject: [PATCH 06/12] Improvement for finding nodes with missing tags --- src/lib/ComfyGraphCanvas.ts | 21 +++-- src/lib/components/ComfyGraphErrorList.svelte | 80 +++++++++++++++---- 2 files changed, 82 insertions(+), 19 deletions(-) diff --git a/src/lib/ComfyGraphCanvas.ts b/src/lib/ComfyGraphCanvas.ts index 220d85e..ac04293 100644 --- a/src/lib/ComfyGraphCanvas.ts +++ b/src/lib/ComfyGraphCanvas.ts @@ -25,7 +25,7 @@ export default class ComfyGraphCanvas extends LGraphCanvas { activeErrors?: ComfyGraphErrors = null; blinkError: ComfyGraphErrorLocation | null = null; blinkErrorTime: number = 0; - highlightNodeAndInput: [LGraphNode, number] | null = null; + highlightNodeAndInput: [LGraphNode, number | null] | null = null; get comfyGraph(): ComfyGraph | null { return this.graph as ComfyGraph; @@ -133,6 +133,15 @@ export default class ComfyGraphCanvas extends LGraphCanvas { else if (isHighlightedNode) { color = "cyan"; thickness = 2 + + // Blink node if no input highlighted + if (this.highlightNodeAndInput[1] == null) { + if (this.blinkErrorTime > 0) { + if ((Math.floor(this.blinkErrorTime / 2)) % 2 === 0) { + color = null; + } + } + } } else if (ss.currentHoveredNodes.has(node.id)) { color = "lightblue"; @@ -172,9 +181,11 @@ export default class ComfyGraphCanvas extends LGraphCanvas { } if (draw) { const [node, inputSlot] = this.highlightNodeAndInput; - ctx.lineWidth = 2; - ctx.strokeStyle = color; - this.highlightNodeInput(node, inputSlot, ctx); + if (inputSlot != null) { + ctx.lineWidth = 2; + ctx.strokeStyle = color; + this.highlightNodeInput(node, inputSlot, ctx); + } } } } @@ -733,7 +744,7 @@ export default class ComfyGraphCanvas extends LGraphCanvas { this.selectNode(node); } - jumpToNodeAndInput(node: LGraphNode, slotIndex: number) { + jumpToNodeAndInput(node: LGraphNode, slotIndex: number | null) { this.jumpToNode(node); this.highlightNodeAndInput = [node, slotIndex]; this.blinkErrorTime = 20; diff --git a/src/lib/components/ComfyGraphErrorList.svelte b/src/lib/components/ComfyGraphErrorList.svelte index f8a669b..3822ec7 100644 --- a/src/lib/components/ComfyGraphErrorList.svelte +++ b/src/lib/components/ComfyGraphErrorList.svelte @@ -5,15 +5,35 @@ import uiState from '$lib/stores/uiState'; import type { ComfyNodeDefInputType } from "$lib/ComfyNodeDef"; import type { INodeInputSlot, LGraphNode, LLink, Subgraph } from "@litegraph-ts/core"; - import { UpstreamNodeLocator, getUpstreamLink } from "./ComfyPromptSerializer"; + import { UpstreamNodeLocator, getUpstreamLink, nodeHasTag } from "./ComfyPromptSerializer"; import JsonView from "./JsonView.svelte"; export let app: ComfyApp; export let errors: ComfyGraphErrors; + let missingTag = null; + let nodeToJumpTo = null; + let inputSlotToHighlight = null; + let _errors = null + + $: if (_errors != errors) { + _errors = errors; + if (errors.errors[0]) { + jumpToError(errors.errors[0]) + } + } + function closeList() { app.lCanvas.clearErrors(); $uiState.activeError = null; + clearState() + } + + function clearState() { + _errors = null; + missingTag = null; + nodeToJumpTo = null; + inputSlotToHighlight = null; } function getParentNode(error: ComfyGraphErrorLocation): Subgraph | null { @@ -24,11 +44,19 @@ return node.graph._subgraph_node } - function canJumpToDisconnectedInput(error: ComfyGraphErrorLocation): boolean { - return error.errorType === ComfyNodeErrorType.RequiredInputMissing && error.input != null; + function jumpToFoundNode() { + if (nodeToJumpTo == null) { + return + } + + app.lCanvas.jumpToNodeAndInput(nodeToJumpTo, inputSlotToHighlight); } - function jumpToDisconnectedInput(error: ComfyGraphErrorLocation) { + function detectDisconnected(error: ComfyGraphErrorLocation) { + missingTag = null; + nodeToJumpTo = null; + inputSlotToHighlight = null; + if (error.errorType !== ComfyNodeErrorType.RequiredInputMissing || error.input == null) { return } @@ -44,19 +72,32 @@ const tag: string | null = error.queueEntry.extraData.extra_pnginfo.comfyBoxPrompt.subgraphs[0]; const test = (node: LGraphNode, currentLink: LLink) => { + if (!nodeHasTag(node, tag, true)) + return true; + const [nextGraph, nextLink, nextInputSlot, nextNode] = getUpstreamLink(node, currentLink) return nextLink == null; }; const nodeLocator = new UpstreamNodeLocator(test) - const [_, foundLink, foundInputSlot, foundPrevNode] = nodeLocator.locateUpstream(node, inputIndex, tag); + const [foundNode, foundLink, foundInputSlot, foundPrevNode] = nodeLocator.locateUpstream(node, inputIndex, null); if (foundInputSlot != null && foundPrevNode != null) { - app.lCanvas.jumpToNodeAndInput(foundPrevNode, foundInputSlot); + if (!nodeHasTag(foundNode, tag, true)) { + nodeToJumpTo = foundNode + missingTag = tag; + inputSlotToHighlight = null; + } + else { + nodeToJumpTo = foundPrevNode; + inputSlotToHighlight = foundInputSlot; + } } } function jumpToError(error: ComfyGraphErrorLocation) { app.lCanvas.jumpToError(error); + + detectDisconnected(error); } function getInputTypeName(type: ComfyNodeDefInputType) { @@ -91,26 +132,37 @@