1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Merge pull request #4087 from node-red/junction-loops

Prevent loops being created with junction nodes
This commit is contained in:
Nick O'Leary 2023-03-02 21:18:21 +00:00 committed by GitHub
commit 40b506b7b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 27 additions and 4 deletions

View File

@ -1090,6 +1090,11 @@ RED.nodes = (function() {
return false; return false;
} }
function getDownstreamNodes(node) {
const downstreamLinks = nodeLinks[node.id].out
const downstreamNodes = new Set(downstreamLinks.map(l => l.target))
return Array.from(downstreamNodes)
}
function getAllDownstreamNodes(node) { function getAllDownstreamNodes(node) {
return getAllFlowNodes(node,'down').filter(function(n) { return n !== node }); return getAllFlowNodes(node,'down').filter(function(n) { return n !== node });
} }
@ -3086,6 +3091,7 @@ RED.nodes = (function() {
getAllFlowNodes: getAllFlowNodes, getAllFlowNodes: getAllFlowNodes,
getAllUpstreamNodes: getAllUpstreamNodes, getAllUpstreamNodes: getAllUpstreamNodes,
getAllDownstreamNodes: getAllDownstreamNodes, getAllDownstreamNodes: getAllDownstreamNodes,
getDownstreamNodes: getDownstreamNodes,
getNodeIslands: getNodeIslands, getNodeIslands: getNodeIslands,
createExportableNodeSet: createExportableNodeSet, createExportableNodeSet: createExportableNodeSet,
createCompleteNodeSet: createCompleteNodeSet, createCompleteNodeSet: createCompleteNodeSet,

View File

@ -82,15 +82,15 @@ RED.contextMenu = (function () {
dirty: true, dirty: true,
moved: true moved: true
} }
const junction = RED.nodes.addJunction(nn);
const historyEvent = { const historyEvent = {
dirty: RED.nodes.dirty(), dirty: RED.nodes.dirty(),
t: 'add', t: 'add',
junctions: [nn] junctions: [junction]
} }
RED.nodes.addJunction(nn);
RED.history.push(historyEvent); RED.history.push(historyEvent);
RED.nodes.dirty(true); RED.nodes.dirty(true);
RED.view.select({nodes: [nn] }); RED.view.select({nodes: [junction] });
RED.view.redraw(true) RED.view.redraw(true)
}, },
disabled: !canEdit disabled: !canEdit

View File

@ -3095,8 +3095,25 @@ RED.view = (function() {
(drag_line.portType === PORT_TYPE_INPUT && mouseup_node.type === "subflow" && (mouseup_node.direction === "status" || mouseup_node.direction === "out")) || (drag_line.portType === PORT_TYPE_INPUT && mouseup_node.type === "subflow" && (mouseup_node.direction === "status" || mouseup_node.direction === "out")) ||
(drag_line.portType === PORT_TYPE_OUTPUT && mouseup_node.type === "subflow" && mouseup_node.direction === "in") (drag_line.portType === PORT_TYPE_OUTPUT && mouseup_node.type === "subflow" && mouseup_node.direction === "in")
)) { )) {
let hasJunctionLoop = false
if (link.source.type === 'junction' && link.target.type === 'junction') {
// This is joining two junctions together. We want to avoid creating a loop
// of pure junction nodes as there is no way to break out of it.
const visited = new Set()
let toVisit = [link.target]
while (toVisit.length > 0) {
const next = toVisit.shift()
if (next === link.source) {
hasJunctionLoop = true
break
}
visited.add(next)
toVisit = toVisit.concat(RED.nodes.getDownstreamNodes(next).filter(n => n.type === 'junction' && !visited.has(n)))
}
}
var existingLink = RED.nodes.filterLinks({source:src,target:dst,sourcePort: src_port}).length !== 0; var existingLink = RED.nodes.filterLinks({source:src,target:dst,sourcePort: src_port}).length !== 0;
if (!existingLink) { if (!hasJunctionLoop && !existingLink) {
RED.nodes.addLink(link); RED.nodes.addLink(link);
addedLinks.push(link); addedLinks.push(link);
} }