Mainly refactor the copy of subflow + slight cleanup

This commit is contained in:
GogoVega 2024-06-16 17:48:55 +02:00
parent e5db6661c3
commit 507038947d
No known key found for this signature in database
GPG Key ID: E1E048B63AC5AC2B

View File

@ -1806,6 +1806,7 @@ RED.nodes = (function() {
id: configNode.id, id: configNode.id,
z: configNode.z, z: configNode.z,
type: configNode.type, type: configNode.type,
changed: false,
icon: configNode.icon, icon: configNode.icon,
info: configNode.info, info: configNode.info,
label: def.label, label: def.label,
@ -1854,8 +1855,8 @@ RED.nodes = (function() {
y: parseFloat(node.y || 0), y: parseFloat(node.y || 0),
z: node.z, z: node.z,
type: node.type, type: node.type,
info: node.info,
changed: false, changed: false,
info: node.info,
_config: {}, _config: {},
_def: def _def: def
}; };
@ -1866,9 +1867,6 @@ RED.nodes = (function() {
newNode.outputLabels = node.outputLabels; newNode.outputLabels = node.outputLabels;
newNode.icon = node.icon; newNode.icon = node.icon;
} }
if (node.type === "junction") {
newNode.wires = node.wires || [];
}
if (node.hasOwnProperty("l")) { if (node.hasOwnProperty("l")) {
newNode.l = node.l; newNode.l = node.l;
} }
@ -1879,11 +1877,10 @@ RED.nodes = (function() {
newNode.g = node.g; newNode.g = node.g;
} }
if (options.markChanged) { if (options.markChanged) {
newNode.changed = true newNode.changed = true;
} }
if (node.type === "group") { if (node.type === "group") {
newNode._def = RED.group.def;
for (const d in newNode._def.defaults) { for (const d in newNode._def.defaults) {
if (newNode._def.defaults.hasOwnProperty(d) && d !== "inputs" && d !== "outputs") { if (newNode._def.defaults.hasOwnProperty(d) && d !== "inputs" && d !== "outputs") {
newNode[d] = node[d]; newNode[d] = node[d];
@ -1893,46 +1890,25 @@ RED.nodes = (function() {
newNode._config.x = node.x; newNode._config.x = node.x;
newNode._config.y = node.y; newNode._config.y = node.y;
if (node.hasOwnProperty("w")) { // Weight if (node.hasOwnProperty("w")) { // Weight
newNode.w = node.w newNode.w = node.w;
} }
if (node.hasOwnProperty("h")) { // Height if (node.hasOwnProperty("h")) { // Height
newNode.h = node.h newNode.h = node.h;
} }
} else if (node.type === "junction") { } else if (node.type === "junction") {
newNode._def = { defaults: {} }; newNode._def = { defaults: {} };
newNode._config.x = node.x newNode._config.x = node.x;
newNode._config.y = node.y newNode._config.y = node.y;
newNode.inputs = 1 newNode.wires = node.wires || [];
newNode.outputs = 1 newNode.inputs = 1;
newNode.outputs = 1;
newNode.w = 0; newNode.w = 0;
newNode.h = 0; newNode.h = 0;
} else if (node.type.substring(0, 7) === "subflow") { } else if (node.type.substring(0, 7) === "subflow") {
const parentId = node.type.split(":")[1]; newNode.name = node.name;
/* newNode.inputs = node.inputs;
const subflow = subflow_denylist[parentId]||subflow_map[parentId]||getSubflow(parentId); newNode.outputs = node.outputs;
// TODO: Pourquoi ne pas l'avoir mis dans les tabs ? newNode.env = node.env;
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;
}*/
} else { } else {
newNode._config.x = node.x; newNode._config.x = node.x;
newNode._config.y = node.y; newNode._config.y = node.y;
@ -2001,7 +1977,7 @@ RED.nodes = (function() {
options = Object.assign({}, defaultOptions, options); options = Object.assign({}, defaultOptions, options);
const createNewIds = options.generateIds; const createNewIds = options.generateIds;
const createMissingWorkspace = options.addFlow; const createNewWorkspace = options.addFlow;
const reimport = (!createNewIds && !!options.reimport); const reimport = (!createNewIds && !!options.reimport);
// Checks and converts nodes into an Array if necessary // Checks and converts nodes into an Array if necessary
@ -2024,7 +2000,7 @@ RED.nodes = (function() {
const existingNodes = []; const existingNodes = [];
const nodesToReplace = []; const nodesToReplace = [];
// Checks if the imported nodes contains duplicates or existing nodes. // Checks if the imported nodes contains duplicates or existing nodes.
originalNodes = originalNodes.filter(function(node) { originalNodes = originalNodes.filter(function (node) {
const id = node.id; const id = node.id;
// This is a temporary fix to help resolve corrupted flows caused by 0.20.0 where multiple // 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; 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(); let activeWorkspace = RED.workspaces.active();
const activeSubflow = getSubflow(activeWorkspace); const activeSubflow = getSubflow(activeWorkspace);
for (const node of originalNodes) { for (const node of originalNodes) {
const group = /^subflow:(.+)$/.exec(node.type); const group = /^subflow:(.+)$/.exec(node.type);
if (group) { if (group) {
const subflowId = group[1]; const subflowId = group[1];
// NOTE: activeWorkspace can be equal to 0 if it's the initial load
if (activeSubflow) { if (activeSubflow) {
let error; let error;
if (subflowId === activeSubflow.id) { if (subflowId === activeSubflow.id) {
@ -2114,27 +2089,28 @@ RED.nodes = (function() {
initialLoad = JSON.parse(JSON.stringify(originalNodes)); initialLoad = JSON.parse(JSON.stringify(originalNodes));
} }
const unknownTypes = identifyUnknowType(originalNodes, { emitNotification: isInitialLoad }); const unknownTypes = identifyUnknowType(originalNodes, { emitNotification: !isInitialLoad });
const nodeZmap = {}; const nodeZmap = {};
let recoveryWorkspace = null; 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) { for (const node of originalNodes) {
if (node.z) { if (node.z) {
nodeZmap[node.z] = nodeZmap[node.z] || []; nodeZmap[node.z] = nodeZmap[node.z] || [];
nodeZmap[node.z].push(node); 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. // Hit the rare issue where node z values get set to 0.
// Repair the flow - but we really need to track that down. // Repair the flow - but we really need to track that down.
if (!recoveryWorkspace) { if (!recoveryWorkspace) {
recoveryWorkspace = { recoveryWorkspace = {
id: RED.nodes.id(), id: getID(),
type: "tab", type: "tab",
disabled: false, disabled: false,
label: RED._("clipboard.recoveredNodes"), label: RED._("clipboard.recoveredNodes"),
info: RED._("clipboard.recoveredNodesInfo"), info: RED._("clipboard.recoveredNodesInfo"),
env: [] env: []
}; };
addWorkspace(recoveryWorkspace); addWorkspace(recoveryWorkspace);
RED.workspaces.add(recoveryWorkspace); RED.workspaces.add(recoveryWorkspace);
nodeZmap[recoveryWorkspace.id] = []; nodeZmap[recoveryWorkspace.id] = [];
@ -2144,9 +2120,6 @@ RED.nodes = (function() {
} }
} }
// TODO
const subflow_denylist = {};
const newWorkspaces = []; const newWorkspaces = [];
if (recoveryWorkspace) { if (recoveryWorkspace) {
newWorkspaces.push(recoveryWorkspace); newWorkspaces.push(recoveryWorkspace);
@ -2154,7 +2127,7 @@ RED.nodes = (function() {
type: "warning", type: "warning",
fixed: true, fixed: true,
buttons: [ 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 subflowMap = {};
const workspaceMap = {}; const workspaceMap = {};
const newSubflows = []; const newSubflows = [];
const subflowDenyList = {};
// Find all tabs and subflow tabs and add it to workspace // Find all tabs and subflow tabs and add it to workspace
// NOTE: Subflow tab not the instance // NOTE: Subflow tab not the instance
for (const node of originalNodes) { for (const node of originalNodes) {
@ -2177,8 +2151,9 @@ RED.nodes = (function() {
if (defaultWorkspace == null) { if (defaultWorkspace == null) {
defaultWorkspace = node; defaultWorkspace = node;
} }
if (activeWorkspace === 0) { // TODO: Why? // If it is the initial load, the value is equal to 0
activeWorkspace = node.id; if (activeWorkspace === 0) {
activeWorkspace = defaultWorkspace.id;
} }
if (createNewIds || options.importMap[node.id] === "copy") { if (createNewIds || options.importMap[node.id] === "copy") {
node.id = getID(); node.id = getID();
@ -2190,12 +2165,13 @@ RED.nodes = (function() {
} else if (node.type === "subflow") { } else if (node.type === "subflow") {
let matchingSubflow; let matchingSubflow;
// TODO: Toujours lié à node.z ? // TODO: Si l'id est différent on devrait l'importer
if (!options.importMap[node.id]) { if (!options.importMap[node.id]) {
matchingSubflow = checkForMatchingSubflow(node, nodeZmap[node.id]); matchingSubflow = checkForMatchingSubflow(node, nodeZmap[node.id]);
console.log("SUBFLOW", matchingSubflow)
} }
if (matchingSubflow) { if (matchingSubflow) {
subflow_denylist[node.id] = matchingSubflow; subflowDenyList[node.id] = matchingSubflow;
} else { } else {
node.in.forEach(function(input, i) { node.in.forEach(function(input, i) {
input.type = "subflow"; input.type = "subflow";
@ -2233,40 +2209,71 @@ RED.nodes = (function() {
addWorkspace(defaultWorkspace); addWorkspace(defaultWorkspace);
RED.workspaces.add(defaultWorkspace); RED.workspaces.add(defaultWorkspace);
newWorkspaces.push(defaultWorkspace); newWorkspaces.push(defaultWorkspace);
activeWorkspace = RED.workspaces.active(); activeWorkspace = defaultWorkspace.id;
} }
const nodeMap = {}; const nodeMap = {};
const newNodes = []; const newNodes = [];
const newGroups = []; const newGroups = [];
const newJunctions = []; const newJunctions = [];
let newWorkspace = null;
// Find all Config Nodes, Groups, Junctions, Nodes and Subflow instances and add them // Find all Config Nodes, Groups, Junctions, Nodes and Subflow instances and add them
// NOTE: Replaced Config Nodes and Subflow instances no longer appear below // NOTE: Replaced Config Nodes and Subflow instances no longer appear below
for (const node of originalNodes) { for (const node of originalNodes) {
const def = registry.getNodeType(node.type);
const isConfigNode = def?.category === "config";
const oldId = node.id; const oldId = node.id;
// TODO: remove workspace in next release+1 // TODO: remove workspace in next release+1
if (node.type === "workspace" || node.type === "tab" || node.type === "subflow") { continue; } 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") { if (createNewIds || options.importMap[oldId] === "copy") {
// Config Node can have an undefined `node.z` // Config Node can have an undefined `node.z`
if (!isConfigNode || (isConfigNode && node.z)) { if (!isConfigNode || (isConfigNode && node.z)) {
if (subflow_denylist[node.z]) { if (subflowDenyList[node.z]) {
continue; continue;
} else if (subflowMap[node.z]) { } else if (subflowMap[node.z]) {
node.z = subflowMap[node.z].id; node.z = subflowMap[node.z].id;
} else { } else {
node.z = workspaceMap[node.z]; node.z = workspaceMap[node.z];
if (!workspaces[node.z]) { if (!workspaces[node.z]) {
if (createMissingWorkspace) { if (createNewWorkspace) {
if (missingWorkspace === null) { if (newWorkspace === null) {
missingWorkspace = RED.workspaces.add(null, true); newWorkspace = RED.workspaces.add(null, true);
newWorkspaces.push(missingWorkspace); newWorkspaces.push(newWorkspace);
} }
node.z = missingWorkspace.id; node.z = newWorkspace.id;
} else { } else {
node.z = activeWorkspace; node.z = activeWorkspace;
} }
@ -2279,19 +2286,34 @@ RED.nodes = (function() {
if (isConfigNode && !keepNodesCurrentZ && node.z && !workspaceMap[node.z] && !subflowMap[node.z]) { if (isConfigNode && !keepNodesCurrentZ && node.z && !workspaceMap[node.z] && !subflowMap[node.z]) {
node.z = activeWorkspace; node.z = activeWorkspace;
} else if (!isConfigNode && !keepNodesCurrentZ && (node.z == null || (!workspaceMap[node.z] && !subflowMap[node.z]))) { } else if (!isConfigNode && !keepNodesCurrentZ && (node.z == null || (!workspaceMap[node.z] && !subflowMap[node.z]))) {
// TODO: Encore ? if (createNewWorkspace) {
if (createMissingWorkspace) { if (newWorkspace === null) {
if (missingWorkspace === null) { newWorkspace = RED.workspaces.add(null,true);
missingWorkspace = RED.workspaces.add(null,true); newWorkspaces.push(newWorkspace);
newWorkspaces.push(missingWorkspace);
} }
node.z = missingWorkspace.id; node.z = newWorkspace.id;
} else { } else {
node.z = activeWorkspace; 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 // Config Node
if (isConfigNode) { if (isConfigNode) {
// TODO: A quoi sert ce bloc ? Replace? // 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) { 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);
} }
//nodeMap[oldId] = copyConfigNode(node, def, options);
// Node, Group, Junction or Subflow // Node, Group, Junction or Subflow
} else if (def || node.type === "group") {
nodeMap[oldId] = copyNode(node, def, options);
// Unknown Node
} else { } else {
// Config Node nodeMap[oldId] = copyNode(node, def, options);
if (!node.x && !node.y) { }
node._def = {
category: "config", // Unknown Node
set: registry.getNodeSet("node-red/unknown") // TODO: Error: Cannot find subflow defintion 148a957f98ce9770 used by subflow instance 6d7f8e702e60f976
}; if (isUnknownNode && !node.type.startsWith("subflow")) {
} 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")
};
}
const propertiesNotCopyable = ["x", "y", "z", "id", "wires"]; 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)) { if (node.hasOwnProperty(prop) && !propertiesNotCopyable.includes(prop)) {
orig[prop] = value; orig[prop] = value;
} }
return orig; return orig;
}, {}); }, {});
node.name = node.type; nodeMap[oldId].name = node.type;
node.type = "unknown"; nodeMap[oldId].type = "unknown";
nodeMap[oldId] = node;
} }
// 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") { if (createNewIds || options.importMap[oldId] === "copy") {
nodeMap[oldId].id = getID(); nodeMap[oldId].id = getID();
} }
@ -2445,6 +2452,7 @@ RED.nodes = (function() {
} }
} }
// Add Links to Workspace
for (const subflow of newSubflows) { for (const subflow of newSubflows) {
subflow.in.forEach(function (input) { subflow.in.forEach(function (input) {
input.wires.forEach(function (wire) { input.wires.forEach(function (wire) {
@ -2486,38 +2494,38 @@ RED.nodes = (function() {
} }
// Order the groups to ensure they are outer-most to inner-most // 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; }); const groupsId = newGroups.map(function (group) { return group.id; });
for (const group of newGroups) { for (const group of newGroups) {
// Delete the group if it is not part of the import
if (group.g && !groupsId.includes(group.g)) { if (group.g && !groupsId.includes(group.g)) {
delete group.g; delete group.g;
} }
// If the group does not contain a group, it's the outer-most
if (!group.g) { if (!group.g) {
groupDepthMap[group.id] = 0; groupDepthMap[group.id] = 0;
} }
} }
// TODO: C'est quoi ce brol ? let changedDepth;
var changedDepth;
do { do {
changedDepth = false; changedDepth = false;
for (let i=0;i<newGroups.length;i++) { for (const group of newGroups) {
const n = newGroups[i]; if (group.g) {
if (n.g) { if (groupDepthMap[group.id] !== groupDepthMap[group.g] + 1) {
if (groupDepthMap[n.id] !== groupDepthMap[n.g] + 1) { groupDepthMap[group.id] = groupDepthMap[group.g] + 1;
groupDepthMap[n.id] = groupDepthMap[n.g] + 1;
changedDepth = true; changedDepth = true;
} }
} }
} }
} while(changedDepth); } while(changedDepth);
console.log("GROUP", groupDepthMap); newGroups.sort(function (a, b) {
newGroups.sort(function(a, b) {
return (groupDepthMap[a.id] - groupDepthMap[b.id]); return (groupDepthMap[a.id] - groupDepthMap[b.id]);
}); });
// Add Groups to Workspace
for (const index in newGroups) { for (const index in newGroups) {
if (newGroups.indexOf(newGroups[index]) !== -1) { if (newGroups.indexOf(newGroups[index]) !== -1) {
newGroups[index] = addGroup(newGroups[index]); newGroups[index] = addGroup(newGroups[index]);
@ -2525,6 +2533,7 @@ RED.nodes = (function() {
} }
} }
// Add Junctions to Workspace
for (const index in newJunctions) { for (const index in newJunctions) {
if (newJunctions.indexOf(newJunctions[index]) !== -1) { if (newJunctions.indexOf(newJunctions[index]) !== -1) {
newJunctions[index] = addJunction(newJunctions[index]); newJunctions[index] = addJunction(newJunctions[index]);
@ -2589,7 +2598,7 @@ RED.nodes = (function() {
junctions: newJunctions, junctions: newJunctions,
workspaces: newWorkspaces, workspaces: newWorkspaces,
subflows: newSubflows, subflows: newSubflows,
missingWorkspace: missingWorkspace, missingWorkspace: newWorkspace,
removedNodes: removedNodes removedNodes: removedNodes
}; };
} }