Merge dd702d4020537648df177ad60d6df8418ccbf8d1 into 2feb290ae3c6cd88c16e4c27c2006a569e0146e2

This commit is contained in:
Gauthier Dandele 2025-02-25 11:05:18 +01:00 committed by GitHub
commit 4ca9d9c8ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 117 additions and 97 deletions

View File

@ -490,6 +490,13 @@ RED.history = (function() {
} }
} }
}); });
} else if (i === "color" && ev.node.type === "subflow") {
// Handle the Subflow definition color change
RED.utils.clearNodeColorCache();
const subflowDef = RED.nodes.getType("subflow:" + ev.node.id);
if (subflowDef) {
subflowDef.color = ev.changes[i] || "#DDAA99";
}
} }
if (i === "credentials" && ev.changes[i]) { if (i === "credentials" && ev.changes[i]) {
// Reset - Only want to keep the changes // Reset - Only want to keep the changes
@ -556,6 +563,10 @@ RED.history = (function() {
if (node) { if (node) {
node.changed = n.changed; node.changed = n.changed;
node.dirty = true; node.dirty = true;
if (ev.changes && ev.changes.hasOwnProperty('color')) {
node._colorChanged = true;
}
} }
}); });
} }

View File

@ -295,8 +295,8 @@ RED.editor = (function() {
* Called when the node's properties have changed. * Called when the node's properties have changed.
* Marks the node as dirty and needing a size check. * Marks the node as dirty and needing a size check.
* Removes any links to non-existant outputs. * Removes any links to non-existant outputs.
* @param node - the node that has been updated * @param {object} node - the node that has been updated
* @param outputMap - (optional) a map of old->new port numbers if wires should be moved * @param {object} [outputMap] - (optional) a map of old->new port numbers if wires should be moved
* @returns {array} the links that were removed due to this update * @returns {array} the links that were removed due to this update
*/ */
function updateNodeProperties(node, outputMap) { function updateNodeProperties(node, outputMap) {
@ -1778,17 +1778,19 @@ RED.editor = (function() {
function showEditSubflowDialog(subflow, defaultTab) { function showEditSubflowDialog(subflow, defaultTab) {
if (buildingEditDialog) { return } if (buildingEditDialog) { return }
buildingEditDialog = true; buildingEditDialog = true;
var editing_node = subflow;
var activeEditPanes = [];
editStack.push(subflow); editStack.push(subflow);
RED.view.state(RED.state.EDITING); RED.view.state(RED.state.EDITING);
var trayOptions = {
let editingNode = subflow;
let activeEditPanes = [];
const trayOptions = {
title: getEditStackTitle(), title: getEditStackTitle(),
buttons: [ buttons: [
{ {
id: "node-dialog-cancel", id: "node-dialog-cancel",
text: RED._("common.label.cancel"), text: RED._("common.label.cancel"),
click: function() { click: function () {
RED.tray.close(); RED.tray.close();
} }
}, },
@ -1796,39 +1798,32 @@ RED.editor = (function() {
id: "node-dialog-ok", id: "node-dialog-ok",
class: "primary", class: "primary",
text: RED._("common.label.done"), text: RED._("common.label.done"),
click: function() { click: function () {
var i; const wasDirty = RED.nodes.dirty();
var editState = { const editState = {
changes: {}, changes: {},
changed: false, changed: false,
outputMap: null outputMap: null
} };
var wasDirty = RED.nodes.dirty();
activeEditPanes.forEach(function(pane) { // Search for changes in edit boxes (panes)
// NOTE: no `oneditsave` for Subflow def
activeEditPanes.forEach(function (pane) {
if (pane.apply) { if (pane.apply) {
pane.apply.call(pane, editState); pane.apply.call(pane, editState);
} }
}) });
var newName = $("#subflow-input-name").val(); // Search for env changes (not handled in properties pane)
const oldEnv = editingNode.env;
const newEnv = RED.subflow.exportSubflowTemplateEnv($("#node-input-env-container").editableList("items"));
if (newName != editing_node.name) { if (newEnv && newEnv.length > 0) {
editState.changes['name'] = editing_node.name; newEnv.forEach(function (prop) {
editing_node.name = newName;
editState.changed = true;
}
var old_env = editing_node.env;
var new_env = RED.subflow.exportSubflowTemplateEnv($("#node-input-env-container").editableList("items"));
if (new_env && new_env.length > 0) {
new_env.forEach(function(prop) {
if (prop.type === "cred") { if (prop.type === "cred") {
editing_node.credentials = editing_node.credentials || {_:{}}; editingNode.credentials = editingNode.credentials || { _: {} };
editing_node.credentials[prop.name] = prop.value; editingNode.credentials[prop.name] = prop.value;
editing_node.credentials['has_'+prop.name] = (prop.value !== ""); editingNode.credentials['has_' + prop.name] = (prop.value !== "");
if (prop.value !== '__PWRD__') { if (prop.value !== '__PWRD__') {
editState.changed = true; editState.changed = true;
} }
@ -1836,51 +1831,59 @@ RED.editor = (function() {
} }
}); });
} }
let envToRemove = new Set()
if (!isSameObj(old_env, new_env)) { const envToRemove = new Set();
if (!isSameObj(oldEnv, newEnv)) {
// Get a list of env properties that have been removed // Get a list of env properties that have been removed
// by comparing old_env and new_env // by comparing oldEnv and newEnv
if (old_env) { if (oldEnv) {
old_env.forEach(env => { envToRemove.add(env.name) }) oldEnv.forEach((env) => { envToRemove.add(env.name) });
} }
if (new_env) { if (newEnv) {
new_env.forEach(env => { newEnv.forEach((env) => {
envToRemove.delete(env.name) envToRemove.delete(env.name)
}) });
} }
editState.changes.env = editing_node.env; editState.changes.env = oldEnv;
editing_node.env = new_env; editingNode.env = newEnv;
editState.changed = true; editState.changed = true;
} }
if (editState.changed) { if (editState.changed) {
let wasChanged = editing_node.changed; const wasChanged = editingNode.changed;
editing_node.changed = true; const subflowInstances = [];
validateNode(editing_node); const instanceHistoryEvents = [];
let subflowInstances = [];
let instanceHistoryEvents = [] // Marks the Subflow has changed and validate it
RED.nodes.eachNode(function(n) { editingNode.changed = true;
if (n.type == "subflow:"+editing_node.id) { validateNode(editingNode);
// Update each Subflow instances
RED.nodes.eachNode(function (n) {
if (n.type == "subflow:" + editingNode.id) {
subflowInstances.push({ subflowInstances.push({
id:n.id, id: n.id,
changed:n.changed changed: n.changed
}) });
n._def.color = editing_node.color;
n.changed = true; n.changed = true;
n.dirty = true; n.dirty = true;
if (editState.changes.hasOwnProperty("color")) {
// Redraw the node color
n._colorChanged = true;
}
if (n.env) { if (n.env) {
const oldEnv = n.env const oldEnv = n.env;
const newEnv = [] const newEnv = [];
let envChanged = false let envChanged = false;
n.env.forEach((env, index) => { n.env.forEach((env, index) => {
if (envToRemove.has(env.name)) { if (envToRemove.has(env.name)) {
envChanged = true envChanged = true;
} else { } else {
newEnv.push(env) newEnv.push(env);
} }
}) });
if (envChanged) { if (envChanged) {
instanceHistoryEvents.push({ instanceHistoryEvents.push({
t: 'edit', t: 'edit',
@ -1888,99 +1891,103 @@ RED.editor = (function() {
changes: { env: oldEnv }, changes: { env: oldEnv },
dirty: n.dirty, dirty: n.dirty,
changed: n.changed changed: n.changed
}) });
n.env = newEnv n.env = newEnv;
} }
} }
updateNodeProperties(n); updateNodeProperties(n);
validateNode(n); validateNode(n);
} }
}); });
RED.events.emit("subflows:change",editing_node);
RED.nodes.dirty(true);
let historyEvent = { let historyEvent = {
t:'edit', t: 'edit',
node:editing_node, node: editingNode,
changes:editState.changes, changes: editState.changes,
dirty:wasDirty, dirty: wasDirty,
changed:wasChanged, changed: wasChanged,
subflow: { subflow: {
instances:subflowInstances instances: subflowInstances
} }
}; };
if (instanceHistoryEvents.length > 0) { if (instanceHistoryEvents.length > 0) {
historyEvent = { historyEvent = {
t: 'multi', t: 'multi',
events: [ historyEvent, ...instanceHistoryEvents ], events: [ historyEvent, ...instanceHistoryEvents ],
dirty: wasDirty dirty: wasDirty
} };
} }
RED.events.emit("subflows:change", editingNode);
RED.history.push(historyEvent); RED.history.push(historyEvent);
RED.nodes.dirty(true);
} }
editing_node.dirty = true;
editingNode.dirty = true;
RED.tray.close(); RED.tray.close();
} }
} }
], ],
resize: function(dimensions) { resize: function (dimensions) {
$(".red-ui-tray-content").height(dimensions.height - 50); $(".red-ui-tray-content").height(dimensions.height - 50);
var form = $(".red-ui-tray-content form").height(dimensions.height - 50 - 40); const form = $(".red-ui-tray-content form").height(dimensions.height - 50 - 40);
var size = {width:form.width(),height:form.height()}; const size = { width: form.width(), height: form.height() };
activeEditPanes.forEach(function(pane) { activeEditPanes.forEach(function (pane) {
if (pane.resize) { if (pane.resize) {
pane.resize.call(pane, size); pane.resize.call(pane, size);
} }
}) });
}, },
open: function(tray, done) { open: function (tray, done) {
var trayFooter = tray.find(".red-ui-tray-footer"); const trayBody = tray.find('.red-ui-tray-body');
var trayFooterLeft = $("<div/>", { const trayFooter = tray.find(".red-ui-tray-footer");
class: "red-ui-tray-footer-left"
}).appendTo(trayFooter)
var trayBody = tray.find('.red-ui-tray-body');
trayBody.parent().css('overflow','hidden');
trayBody.parent().css('overflow', 'hidden');
const trayFooterLeft = $("<div/>", { class: "red-ui-tray-footer-left" }).appendTo(trayFooter);
$('<span style="margin-left: 10px"><i class="fa fa-info-circle"></i> <i id="red-ui-editor-subflow-user-count"></i></span>').appendTo(trayFooterLeft); $('<span style="margin-left: 10px"><i class="fa fa-info-circle"></i> <i id="red-ui-editor-subflow-user-count"></i></span>').appendTo(trayFooterLeft);
if (editing_node) { if (editingNode) {
RED.sidebar.info.refresh(editing_node); RED.sidebar.info.refresh(editingNode);
} }
var nodeEditPanes = [ const nodeEditPanes = [
'editor-tab-properties', 'editor-tab-properties',
'editor-tab-subflow-module', 'editor-tab-subflow-module',
'editor-tab-description', 'editor-tab-description',
'editor-tab-appearance' 'editor-tab-appearance'
]; ];
prepareEditDialog(trayBody, nodeEditPanes, subflow, subflow._def, "subflow-input", defaultTab, function (_activeEditPanes) {
prepareEditDialog(trayBody, nodeEditPanes, subflow, subflow._def, "node-input", defaultTab, function(_activeEditPanes) {
activeEditPanes = _activeEditPanes; activeEditPanes = _activeEditPanes;
$("#subflow-input-name").val(subflow.name);
RED.text.bidi.prepareInput($("#subflow-input-name"));
trayBody.i18n(); trayBody.i18n();
trayFooter.i18n(); trayFooter.i18n();
buildingEditDialog = false; buildingEditDialog = false;
done(); done();
}); });
}, },
close: function() { close: function () {
if (RED.view.state() != RED.state.IMPORT_DRAGGING) { if (RED.view.state() != RED.state.IMPORT_DRAGGING) {
RED.view.state(RED.state.DEFAULT); RED.view.state(RED.state.DEFAULT);
} }
RED.sidebar.info.refresh(editing_node);
RED.sidebar.info.refresh(editingNode);
RED.workspaces.refresh(); RED.workspaces.refresh();
activeEditPanes.forEach(function(pane) { activeEditPanes.forEach(function (pane) {
if (pane.close) { if (pane.close) {
pane.close.call(pane); pane.close.call(pane);
} }
}) });
editStack.pop(); editStack.pop();
editing_node = null; // TODO: useless?
editingNode = null;
}, },
show: function() { show: function () {}
}
} }
RED.tray.show(trayOptions); RED.tray.show(trayOptions);
} }

View File

@ -26,6 +26,8 @@
if (node._def.category === "config" && nodeType !== "group") { if (node._def.category === "config" && nodeType !== "group") {
this.inputClass = "node-config-input"; this.inputClass = "node-config-input";
formStyle = "node-config-dialog-edit-form"; formStyle = "node-config-dialog-edit-form";
} else if (node.type === "subflow") {
this.inputClass = "subflow-input";
} }
RED.editor.buildEditForm(container,formStyle,nodeType,i18nNamespace,node); RED.editor.buildEditForm(container,formStyle,nodeType,i18nNamespace,node);
}, },

View File

@ -562,7 +562,7 @@ RED.palette = (function() {
} }
} }
paletteNode.css("backgroundColor", sf.color); paletteNode.css("backgroundColor", RED.utils.getNodeColor("subflow", sf._def));
} }
function refreshFilter() { function refreshFilter() {