Make Fix node (recreate) work inside a subgraph

"Fix node (recreate)" looked a node's links, and the nodes at their
other end, up in app.graph, the root graph. A subgraph keeps its own
links and nodes, so inside a subgraph the lookup found nothing: the
entry threw "Cannot read properties of undefined" and, because the
original is removed only afterwards, left the wired original and an
unwired replacement on the canvas.

- Read links and nodes from the graph the node is in
- Reconnect a link that starts at an input of the subgraph, or ends at
  one of its outputs, through that slot; those two are not nodes of
  the graph
- For such a link, skip an input the new node does not have, as
  connect() does for a link from a node
- Add a CHANGELOG entry

Follow-up to #3443. The manager-v4 port carries the browser test.
This commit is contained in:
Dr.Lt.Data
2026-11-14 06:06:33 +09:00
parent c075eaface
commit 44d7f7a16a
2 changed files with 31 additions and 6 deletions
+8
View File
@@ -2,6 +2,14 @@
## Unreleased
### Fix node (recreate) works inside a subgraph
`Fix node (recreate)` on a node inside a subgraph stopped with an error and left
two copies of the node: the original, still wired, and an unwired replacement.
It read the node's links from the root graph; it now reads them from the graph
the node is in, and keeps the links to the inputs and outputs of the subgraph as
well.
### Notice retrieval verifies the TLS certificate
The notice in the Manager menu is fetched from GitHub with certificate
+23 -6
View File
@@ -92,6 +92,9 @@ function connect_inputs(nearest_inputs, node) {
}
function node_info_copy(src, dest, connect_both, copy_shape) {
// The graph the node is in. A subgraph keeps its own links and nodes.
const graph = src.graph;
// copy input connections
for(let i in src.inputs) {
let input = src.inputs[i];
@@ -100,9 +103,17 @@ function node_info_copy(src, dest, connect_both, copy_shape) {
dest.convertWidgetToInput(destWidget);
}
if(input.link) {
let link = app.graph.links[input.link];
let src_node = app.graph.getNodeById(link.origin_id);
src_node.connect(link.origin_slot, dest, input.name);
let link = graph.links[input.link];
if(link.origin_id === graph.inputNode?.id) {
// The link starts at an input of the subgraph, which is not a node of the graph.
let dest_input = dest.inputs[dest.findInputSlot(input.name)];
if(dest_input)
graph.inputNode.slots[link.origin_slot].connect(dest_input, dest);
}
else {
let src_node = graph.getNodeById(link.origin_id);
src_node.connect(link.origin_slot, dest, input.name);
}
}
}
@@ -114,7 +125,7 @@ function node_info_copy(src, dest, connect_both, copy_shape) {
if(output.links) {
let links = [];
for(let j in output.links) {
links.push(app.graph.links[output.links[j]]);
links.push(graph.links[output.links[j]]);
}
output_links[output.name] = links;
}
@@ -125,8 +136,14 @@ function node_info_copy(src, dest, connect_both, copy_shape) {
if(links) {
for(let j in links) {
let link = links[j];
let target_node = app.graph.getNodeById(link.target_id);
dest.connect(parseInt(i), target_node, link.target_slot);
if(link.target_id === graph.outputNode?.id) {
// The link ends at an output of the subgraph.
graph.outputNode.slots[link.target_slot].connect(dest.outputs[i], dest);
}
else {
let target_node = graph.getNodeById(link.target_id);
dest.connect(parseInt(i), target_node, link.target_slot);
}
}
}
}