diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index cff3905e4..2e3e29b0c 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -1806,6 +1806,7 @@ RED.nodes = (function() { id: configNode.id, z: configNode.z, type: configNode.type, + changed: false, icon: configNode.icon, info: configNode.info, label: def.label, @@ -1854,8 +1855,8 @@ RED.nodes = (function() { y: parseFloat(node.y || 0), z: node.z, type: node.type, - info: node.info, changed: false, + info: node.info, _config: {}, _def: def }; @@ -1866,9 +1867,6 @@ RED.nodes = (function() { newNode.outputLabels = node.outputLabels; newNode.icon = node.icon; } - if (node.type === "junction") { - newNode.wires = node.wires || []; - } if (node.hasOwnProperty("l")) { newNode.l = node.l; } @@ -1879,11 +1877,10 @@ RED.nodes = (function() { newNode.g = node.g; } if (options.markChanged) { - newNode.changed = true + newNode.changed = true; } if (node.type === "group") { - newNode._def = RED.group.def; for (const d in newNode._def.defaults) { if (newNode._def.defaults.hasOwnProperty(d) && d !== "inputs" && d !== "outputs") { newNode[d] = node[d]; @@ -1893,46 +1890,25 @@ RED.nodes = (function() { newNode._config.x = node.x; newNode._config.y = node.y; if (node.hasOwnProperty("w")) { // Weight - newNode.w = node.w + newNode.w = node.w; } if (node.hasOwnProperty("h")) { // Height - newNode.h = node.h + newNode.h = node.h; } } else if (node.type === "junction") { newNode._def = { defaults: {} }; - newNode._config.x = node.x - newNode._config.y = node.y - newNode.inputs = 1 - newNode.outputs = 1 + newNode._config.x = node.x; + newNode._config.y = node.y; + newNode.wires = node.wires || []; + newNode.inputs = 1; + newNode.outputs = 1; newNode.w = 0; newNode.h = 0; } else if (node.type.substring(0, 7) === "subflow") { - const parentId = node.type.split(":")[1]; - /* - const subflow = subflow_denylist[parentId]||subflow_map[parentId]||getSubflow(parentId); - // TODO: Pourquoi ne pas l'avoir mis dans les tabs ? - if (!subflow){ - node._def = { - color:"#fee", - defaults: {}, - label: "unknown: "+n.type, - labelStyle: "red-ui-flow-node-label-italic", - outputs: n.outputs|| (n.wires && n.wires.length) || 0, - set: registry.getNodeSet("node-red/unknown") - } - } else { - // TODO: Normal que la copie utilise le Subflow parent ? - if (subflow_denylist[parentId] || createNewIds || options.importMap[n.id] === "copy") { - parentId = subflow.id; - node.type = "subflow:"+parentId; - node._def = registry.getNodeType(node.type); - delete node.i; - } - node.name = n.name; - node.outputs = subflow.out.length; - node.inputs = subflow.in.length; - node.env = n.env; - }*/ + newNode.name = node.name; + newNode.inputs = node.inputs; + newNode.outputs = node.outputs; + newNode.env = node.env; } else { newNode._config.x = node.x; newNode._config.y = node.y; @@ -2001,7 +1977,7 @@ RED.nodes = (function() { options = Object.assign({}, defaultOptions, options); const createNewIds = options.generateIds; - const createMissingWorkspace = options.addFlow; + const createNewWorkspace = options.addFlow; const reimport = (!createNewIds && !!options.reimport); // Checks and converts nodes into an Array if necessary @@ -2024,7 +2000,7 @@ RED.nodes = (function() { const existingNodes = []; const nodesToReplace = []; // Checks if the imported nodes contains duplicates or existing nodes. - originalNodes = originalNodes.filter(function(node) { + originalNodes = originalNodes.filter(function (node) { const id = node.id; // This is a temporary fix to help resolve corrupted flows caused by 0.20.0 where multiple @@ -2077,14 +2053,13 @@ RED.nodes = (function() { throw existingNodesError; } - // TODO: check the z of the subflow instance and check _that_ if it exists - // TODO: Handled activeWorkspace = 0 let activeWorkspace = RED.workspaces.active(); const activeSubflow = getSubflow(activeWorkspace); for (const node of originalNodes) { const group = /^subflow:(.+)$/.exec(node.type); if (group) { const subflowId = group[1]; + // NOTE: activeWorkspace can be equal to 0 if it's the initial load if (activeSubflow) { let error; if (subflowId === activeSubflow.id) { @@ -2114,27 +2089,28 @@ RED.nodes = (function() { initialLoad = JSON.parse(JSON.stringify(originalNodes)); } - const unknownTypes = identifyUnknowType(originalNodes, { emitNotification: isInitialLoad }); + const unknownTypes = identifyUnknowType(originalNodes, { emitNotification: !isInitialLoad }); const nodeZmap = {}; let recoveryWorkspace = null; - let missingWorkspace = null; + // If it's the initial load, create a recovery workspace if any nodes don't have `node.z` and assign to it. for (const node of originalNodes) { if (node.z) { nodeZmap[node.z] = nodeZmap[node.z] || []; nodeZmap[node.z].push(node); - } else if (isInitialLoad && node.hasOwnProperty('x') && node.hasOwnProperty('y')) { + } else if (isInitialLoad && node.hasOwnProperty("x") && node.hasOwnProperty("y")) { // Hit the rare issue where node z values get set to 0. // Repair the flow - but we really need to track that down. if (!recoveryWorkspace) { recoveryWorkspace = { - id: RED.nodes.id(), + id: getID(), type: "tab", disabled: false, label: RED._("clipboard.recoveredNodes"), info: RED._("clipboard.recoveredNodesInfo"), env: [] }; + addWorkspace(recoveryWorkspace); RED.workspaces.add(recoveryWorkspace); nodeZmap[recoveryWorkspace.id] = []; @@ -2144,9 +2120,6 @@ RED.nodes = (function() { } } - // TODO - const subflow_denylist = {}; - const newWorkspaces = []; if (recoveryWorkspace) { newWorkspaces.push(recoveryWorkspace); @@ -2154,7 +2127,7 @@ RED.nodes = (function() { type: "warning", fixed: true, buttons: [ - { text: RED._("common.label.close"), click: function() { notification.close(); } } + { text: RED._("common.label.close"), click: function () { notification.close(); } } ] }); } @@ -2162,6 +2135,7 @@ RED.nodes = (function() { const subflowMap = {}; const workspaceMap = {}; const newSubflows = []; + const subflowDenyList = {}; // Find all tabs and subflow tabs and add it to workspace // NOTE: Subflow tab not the instance for (const node of originalNodes) { @@ -2177,8 +2151,9 @@ RED.nodes = (function() { if (defaultWorkspace == null) { defaultWorkspace = node; } - if (activeWorkspace === 0) { // TODO: Why? - activeWorkspace = node.id; + // If it is the initial load, the value is equal to 0 + if (activeWorkspace === 0) { + activeWorkspace = defaultWorkspace.id; } if (createNewIds || options.importMap[node.id] === "copy") { node.id = getID(); @@ -2190,12 +2165,13 @@ RED.nodes = (function() { } else if (node.type === "subflow") { let matchingSubflow; - // TODO: Toujours lié à node.z ? + // TODO: Si l'id est différent on devrait l'importer if (!options.importMap[node.id]) { matchingSubflow = checkForMatchingSubflow(node, nodeZmap[node.id]); + console.log("SUBFLOW", matchingSubflow) } if (matchingSubflow) { - subflow_denylist[node.id] = matchingSubflow; + subflowDenyList[node.id] = matchingSubflow; } else { node.in.forEach(function(input, i) { input.type = "subflow"; @@ -2233,40 +2209,71 @@ RED.nodes = (function() { addWorkspace(defaultWorkspace); RED.workspaces.add(defaultWorkspace); newWorkspaces.push(defaultWorkspace); - activeWorkspace = RED.workspaces.active(); + activeWorkspace = defaultWorkspace.id; } const nodeMap = {}; const newNodes = []; const newGroups = []; const newJunctions = []; + let newWorkspace = null; // Find all Config Nodes, Groups, Junctions, Nodes and Subflow instances and add them // NOTE: Replaced Config Nodes and Subflow instances no longer appear below for (const node of originalNodes) { - const def = registry.getNodeType(node.type); - const isConfigNode = def?.category === "config"; const oldId = node.id; // TODO: remove workspace in next release+1 if (node.type === "workspace" || node.type === "tab" || node.type === "subflow") { continue; } - // TODO: Fixes weird thing with `node.z` + // Try to fix the node definition + let def = registry.getNodeType(node.type); + let isUnknownNode = false; + if (!def) { + // Group Node + if (node.type === "group") { + def = RED.group.def; + } + // Unknown Config Node + else if (!node.x && !node.y) { + isUnknownNode = true; + def = { + category: "config", + //defaults: {}, + set: registry.getNodeSet("node-red/unknown") + }; + // Unknown Node + } else { + isUnknownNode = true; + def = { + color: "#fee", + defaults: {}, + label: "unknown: " + node.type, + labelStyle: "red-ui-flow-node-label-italic", + outputs: node.outputs ?? node.wires?.length ?? 0, + set: registry.getNodeSet("node-red/unknown") + }; + } + } + + const isConfigNode = def?.category === "config"; + + // Fix `node.z` for undefined/not found/new one case if (createNewIds || options.importMap[oldId] === "copy") { // Config Node can have an undefined `node.z` if (!isConfigNode || (isConfigNode && node.z)) { - if (subflow_denylist[node.z]) { + if (subflowDenyList[node.z]) { continue; } else if (subflowMap[node.z]) { node.z = subflowMap[node.z].id; } else { node.z = workspaceMap[node.z]; if (!workspaces[node.z]) { - if (createMissingWorkspace) { - if (missingWorkspace === null) { - missingWorkspace = RED.workspaces.add(null, true); - newWorkspaces.push(missingWorkspace); + if (createNewWorkspace) { + if (newWorkspace === null) { + newWorkspace = RED.workspaces.add(null, true); + newWorkspaces.push(newWorkspace); } - node.z = missingWorkspace.id; + node.z = newWorkspace.id; } else { node.z = activeWorkspace; } @@ -2279,19 +2286,34 @@ RED.nodes = (function() { if (isConfigNode && !keepNodesCurrentZ && node.z && !workspaceMap[node.z] && !subflowMap[node.z]) { node.z = activeWorkspace; } else if (!isConfigNode && !keepNodesCurrentZ && (node.z == null || (!workspaceMap[node.z] && !subflowMap[node.z]))) { - // TODO: Encore ? - if (createMissingWorkspace) { - if (missingWorkspace === null) { - missingWorkspace = RED.workspaces.add(null,true); - newWorkspaces.push(missingWorkspace); + if (createNewWorkspace) { + if (newWorkspace === null) { + newWorkspace = RED.workspaces.add(null,true); + newWorkspaces.push(newWorkspace); } - node.z = missingWorkspace.id; + node.z = newWorkspace.id; } else { node.z = activeWorkspace; } } } + // Update the node definition for subflow instance + if (!isUnknownNode && node.type.substring(0, 7) === "subflow") { + const parentId = node.type.split(":")[1]; + const subflow = subflowDenyList[parentId] || subflowMap[parentId] || getSubflow(parentId); + + if (subflowDenyList[parentId] || createNewIds || options.importMap[node.id] === "copy") { + node.type = "subflow:" + subflow.id; + def = registry.getNodeType(node.type); + } + + node.inputs = subflow.in.length; + node.outputs = subflow.out.length; + } + + // Now the properties have been corrected, copy the node properties: + // Config Node if (isConfigNode) { // TODO: A quoi sert ce bloc ? Replace? @@ -2320,41 +2342,26 @@ RED.nodes = (function() { if (!existingConfigNode || existingConfigNode._def.exclusive) { //} || !compareNodes(existingConfigNode,n,true) || existingConfigNode.z !== n.z) { nodeMap[oldId] = copyConfigNode(node, def, options); } - //nodeMap[oldId] = copyConfigNode(node, def, options); // Node, Group, Junction or Subflow - } else if (def || node.type === "group") { - nodeMap[oldId] = copyNode(node, def, options); - // Unknown Node } else { - // Config Node - if (!node.x && !node.y) { - node._def = { - category: "config", - set: registry.getNodeSet("node-red/unknown") - }; - } else { - node._def = { - color: "#fee", - defaults: {}, - label: "unknown: " + node.type, - labelStyle: "red-ui-flow-node-label-italic", - outputs: node.outputs ?? node.wires?.length ?? 0, - set: registry.getNodeSet("node-red/unknown") - }; - } + nodeMap[oldId] = copyNode(node, def, options); + } + + // Unknown Node + // TODO: Error: Cannot find subflow defintion 148a957f98ce9770 used by subflow instance 6d7f8e702e60f976 + if (isUnknownNode && !node.type.startsWith("subflow")) { const propertiesNotCopyable = ["x", "y", "z", "id", "wires"]; - node._orig = Object.entries(node).reduce(function (orig, [prop, value]) { + nodeMap[oldId]._orig = Object.entries(node).reduce(function (orig, [prop, value]) { if (node.hasOwnProperty(prop) && !propertiesNotCopyable.includes(prop)) { orig[prop] = value; } return orig; }, {}); - node.name = node.type; - node.type = "unknown"; - nodeMap[oldId] = node; + nodeMap[oldId].name = node.type; + nodeMap[oldId].type = "unknown"; } - // Now the properties have been copied, change the `id` if it's a copy + // Now the node has been copied, change the `id` if it's a copy if (createNewIds || options.importMap[oldId] === "copy") { nodeMap[oldId].id = getID(); } @@ -2445,6 +2452,7 @@ RED.nodes = (function() { } } + // Add Links to Workspace for (const subflow of newSubflows) { subflow.in.forEach(function (input) { input.wires.forEach(function (wire) { @@ -2486,38 +2494,38 @@ RED.nodes = (function() { } // Order the groups to ensure they are outer-most to inner-most - var groupDepthMap = {}; + + const groupDepthMap = {}; const groupsId = newGroups.map(function (group) { return group.id; }); for (const group of newGroups) { + // Delete the group if it is not part of the import if (group.g && !groupsId.includes(group.g)) { delete group.g; } + // If the group does not contain a group, it's the outer-most if (!group.g) { groupDepthMap[group.id] = 0; } } - // TODO: C'est quoi ce brol ? - var changedDepth; + let changedDepth; do { changedDepth = false; - for (let i=0;i