').text(def.set.module)
+ container.append(row1Name, row2Module)
+
+ return {
+ value: def.type,
+ name: def.type,
+ enabled: def.set.enabled ?? true,
+ local: def.set.local,
+ title: def.set.id, // tooltip e.g. "node-red-contrib-foo/bar"
+ module: def.set.module,
+ icon: container[0].outerHTML.trim(), // the typeInput will interpret this as html text and render it in the anchor
+ }
+ })
+ this._optionsCache = configNodes
+ return configNodes
+ }
}
};
+
// For a type with options, check value is a valid selection
// If !opt.multiple, returns the valid option object
// if opt.multiple, returns an array of valid option objects
// If not valid, returns null;
function isOptionValueValid(opt, currentVal) {
+ let _options = opt.options
+ if (typeof _options === "function") {
+ _options = _options.call(this)
+ }
if (!opt.multiple) {
- for (var i=0;i
'}
}).sort(function(A,B) {
if (A.value === RED.settings.context.default) {
@@ -449,13 +725,17 @@
return A.value.localeCompare(B.value);
}
})
- if (contextOptions.length < 2) {
+ if (contextStoreOptions.length < 2) {
allOptions.flow.options = [];
allOptions.global.options = [];
} else {
- allOptions.flow.options = contextOptions;
- allOptions.global.options = contextOptions;
+ allOptions.flow.options = contextStoreOptions;
+ allOptions.global.options = contextStoreOptions;
}
+ // Translate timestamp options
+ allOptions.date.options.forEach(opt => {
+ opt.label = RED._("typedInput.date.format." + (opt.value || 'timestamp'), {defaultValue: opt.label})
+ })
}
nlsd = true;
var that = this;
@@ -544,7 +824,7 @@
that.element.trigger('paste',evt);
});
this.input.on('keydown', function(evt) {
- if (that.typeMap[that.propertyType].autoComplete) {
+ if (that.typeMap[that.propertyType].autoComplete || that.input.hasClass('red-ui-autoComplete')) {
return
}
if (evt.keyCode >= 37 && evt.keyCode <= 40) {
@@ -838,7 +1118,9 @@
if (this.optionMenu) {
this.optionMenu.remove();
}
- this.menu.remove();
+ if (this.menu) {
+ this.menu.remove();
+ }
this.uiSelect.remove();
},
types: function(types) {
@@ -871,7 +1153,7 @@
this.menu = this._createMenu(this.typeList,{},function(v) { that.type(v) });
if (currentType && !this.typeMap.hasOwnProperty(currentType)) {
if (!firstCall) {
- this.type(this.typeList[0].value);
+ this.type(this.typeList[0]?.value || ""); // permit empty typeList
}
} else {
this.propertyType = null;
@@ -908,6 +1190,11 @@
var selectedOption = [];
var valueToCheck = value;
if (opt.options) {
+ let _options = opt.options
+ if (typeof opt.options === "function") {
+ _options = opt.options.call(this)
+ }
+
if (opt.hasValue && opt.parse) {
var parts = opt.parse(value);
if (this.options.debug) { console.log(this.identifier,"new parse",parts) }
@@ -921,8 +1208,8 @@
checkValues = valueToCheck.split(",");
}
checkValues.forEach(function(valueToCheck) {
- for (var i=0;i'+
''+
''+
- ''+
+ ''+
'').prependTo(".red-ui-header-toolbar");
const mainMenuItems = [
{id:"deploymenu-item-full",toggle:"deploy-type",icon:"red/images/deploy-full.svg",label:RED._("deploy.full"),sublabel:RED._("deploy.fullDesc"),selected: true, onselect:function(s) { if(s){changeDeploymentType("full")}}},
@@ -112,53 +114,80 @@ RED.deploy = (function() {
RED.actions.add("core:set-deploy-type-to-modified-nodes",function() { RED.menu.setSelected("deploymenu-item-node",true); });
}
-
+ window.addEventListener('beforeunload', function (event) {
+ if (RED.nodes.dirty()) {
+ event.preventDefault();
+ event.stopImmediatePropagation()
+ event.returnValue = RED._("deploy.confirm.undeployedChanges");
+ return
+ }
+ })
RED.events.on('workspace:dirty',function(state) {
+ if (RED.settings.user?.permissions === 'read') {
+ return
+ }
if (state.dirty) {
- window.onbeforeunload = function() {
- return RED._("deploy.confirm.undeployedChanges");
- }
+ // window.onbeforeunload = function() {
+ // return
+ // }
$("#red-ui-header-button-deploy").removeClass("disabled");
} else {
- window.onbeforeunload = null;
+ // window.onbeforeunload = null;
$("#red-ui-header-button-deploy").addClass("disabled");
}
});
- var activeNotifyMessage;
RED.comms.subscribe("notification/runtime-deploy",function(topic,msg) {
- if (!activeNotifyMessage) {
- var currentRev = RED.nodes.version();
- if (currentRev === null || deployInflight || currentRev === msg.revision) {
- return;
- }
- var message = $('').text(RED._('deploy.confirm.backgroundUpdate'));
- activeNotifyMessage = RED.notify(message,{
- modal: true,
- fixed: true,
- buttons: [
- {
- text: RED._('deploy.confirm.button.ignore'),
- click: function() {
- activeNotifyMessage.close();
- activeNotifyMessage = null;
- }
- },
- {
- text: RED._('deploy.confirm.button.review'),
- class: "primary",
- click: function() {
- activeNotifyMessage.close();
- var nns = RED.nodes.createCompleteNodeSet();
- resolveConflict(nns,false);
- activeNotifyMessage = null;
- }
+ var currentRev = RED.nodes.version();
+ if (currentRev === null || deployInflight || currentRev === msg.revision) {
+ return;
+ }
+ if (activeBackgroundDeployNotification?.hidden && !activeBackgroundDeployNotification?.closed) {
+ activeBackgroundDeployNotification.showNotification()
+ return
+ }
+ const message = $('
').text(RED._('deploy.confirm.backgroundUpdate'));
+ const options = {
+ id: 'background-update',
+ type: 'compact',
+ modal: false,
+ fixed: true,
+ timeout: 10000,
+ buttons: [
+ {
+ text: RED._('deploy.confirm.button.review'),
+ class: "primary",
+ click: function() {
+ activeBackgroundDeployNotification.hideNotification();
+ var nns = RED.nodes.createCompleteNodeSet();
+ resolveConflict(nns,false);
}
- ]
- });
+ }
+ ]
+ }
+ if (!activeBackgroundDeployNotification || activeBackgroundDeployNotification.closed) {
+ activeBackgroundDeployNotification = RED.notify(message, options)
+ } else {
+ activeBackgroundDeployNotification.update(message, options)
}
});
+
+
+ updateLockedState()
+ RED.events.on('login', updateLockedState)
+ }
+
+ function updateLockedState() {
+ if (RED.settings.user?.permissions === 'read') {
+ $(".red-ui-deploy-button-group").addClass("readOnly");
+ $("#red-ui-header-button-deploy").addClass("disabled");
+ } else {
+ $(".red-ui-deploy-button-group").removeClass("readOnly");
+ if (RED.nodes.dirty()) {
+ $("#red-ui-header-button-deploy").removeClass("disabled");
+ }
+ }
}
function getNodeInfo(node) {
@@ -213,7 +242,11 @@ RED.deploy = (function() {
class: "primary disabled",
click: function() {
if (!$("#red-ui-deploy-dialog-confirm-deploy-review").hasClass('disabled')) {
- RED.diff.showRemoteDiff();
+ RED.diff.showRemoteDiff(null, {
+ onmerge: function () {
+ activeBackgroundDeployNotification.close()
+ }
+ });
conflictNotification.close();
}
}
@@ -226,6 +259,7 @@ RED.deploy = (function() {
if (!$("#red-ui-deploy-dialog-confirm-deploy-merge").hasClass('disabled')) {
RED.diff.mergeDiff(currentDiff);
conflictNotification.close();
+ activeBackgroundDeployNotification.close()
}
}
}
@@ -238,6 +272,7 @@ RED.deploy = (function() {
click: function() {
save(true,activeDeploy);
conflictNotification.close();
+ activeBackgroundDeployNotification.close()
}
})
}
@@ -248,21 +283,17 @@ RED.deploy = (function() {
buttons: buttons
});
- var now = Date.now();
RED.diff.getRemoteDiff(function(diff) {
- var ellapsed = Math.max(1000 - (Date.now()-now), 0);
currentDiff = diff;
- setTimeout(function() {
- conflictCheck.hide();
- var d = Object.keys(diff.conflicts);
- if (d.length === 0) {
- conflictAutoMerge.show();
- $("#red-ui-deploy-dialog-confirm-deploy-merge").removeClass('disabled')
- } else {
- conflictManualMerge.show();
- }
- $("#red-ui-deploy-dialog-confirm-deploy-review").removeClass('disabled')
- },ellapsed);
+ conflictCheck.hide();
+ var d = Object.keys(diff.conflicts);
+ if (d.length === 0) {
+ conflictAutoMerge.show();
+ $("#red-ui-deploy-dialog-confirm-deploy-merge").removeClass('disabled')
+ } else {
+ conflictManualMerge.show();
+ }
+ $("#red-ui-deploy-dialog-confirm-deploy-review").removeClass('disabled')
})
}
function cropList(list) {
diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/diff.js b/packages/node_modules/@node-red/editor-client/src/js/ui/diff.js
index 3f73e29aa..ebdf683e3 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/diff.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/diff.js
@@ -1,5 +1,4 @@
RED.diff = (function() {
-
var currentDiff = {};
var diffVisible = false;
var diffList;
@@ -62,12 +61,14 @@ RED.diff = (function() {
addedCount:0,
deletedCount:0,
changedCount:0,
+ movedCount:0,
unchangedCount: 0
},
remote: {
addedCount:0,
deletedCount:0,
changedCount:0,
+ movedCount:0,
unchangedCount: 0
},
conflicts: 0
@@ -138,7 +139,7 @@ RED.diff = (function() {
$(this).parent().toggleClass('collapsed');
});
- createNodePropertiesTable(def,tab,localTabNode,remoteTabNode,conflicts).appendTo(div);
+ createNodePropertiesTable(def,tab,localTabNode,remoteTabNode).appendTo(div);
selectState = "";
if (conflicts[tab.id]) {
flowStats.conflicts++;
@@ -208,19 +209,26 @@ RED.diff = (function() {
var localStats = $('',{class:"red-ui-diff-list-flow-stats"}).appendTo(localCell);
$('').text(RED._('diff.nodeCount',{count:localNodeCount})).appendTo(localStats);
- if (flowStats.conflicts + flowStats.local.addedCount + flowStats.local.changedCount + flowStats.local.deletedCount > 0) {
+ if (flowStats.conflicts + flowStats.local.addedCount + flowStats.local.changedCount + flowStats.local.movedCount + flowStats.local.deletedCount > 0) {
$(' [ ').appendTo(localStats);
if (flowStats.conflicts > 0) {
$(' '+flowStats.conflicts+'').appendTo(localStats);
}
if (flowStats.local.addedCount > 0) {
- $(' '+flowStats.local.addedCount+'').appendTo(localStats);
+ const cell = $(' '+flowStats.local.addedCount+'').appendTo(localStats);
+ RED.popover.tooltip(cell, RED._('diff.type.added'))
}
if (flowStats.local.changedCount > 0) {
- $(' '+flowStats.local.changedCount+'').appendTo(localStats);
+ const cell = $(' '+flowStats.local.changedCount+'').appendTo(localStats);
+ RED.popover.tooltip(cell, RED._('diff.type.changed'))
+ }
+ if (flowStats.local.movedCount > 0) {
+ const cell = $(' '+flowStats.local.movedCount+'').appendTo(localStats);
+ RED.popover.tooltip(cell, RED._('diff.type.moved'))
}
if (flowStats.local.deletedCount > 0) {
- $(' '+flowStats.local.deletedCount+'').appendTo(localStats);
+ const cell = $(' '+flowStats.local.deletedCount+'').appendTo(localStats);
+ RED.popover.tooltip(cell, RED._('diff.type.deleted'))
}
$(' ] ').appendTo(localStats);
}
@@ -246,19 +254,26 @@ RED.diff = (function() {
}
var remoteStats = $('',{class:"red-ui-diff-list-flow-stats"}).appendTo(remoteCell);
$('').text(RED._('diff.nodeCount',{count:remoteNodeCount})).appendTo(remoteStats);
- if (flowStats.conflicts + flowStats.remote.addedCount + flowStats.remote.changedCount + flowStats.remote.deletedCount > 0) {
+ if (flowStats.conflicts + flowStats.remote.addedCount + flowStats.remote.changedCount + flowStats.remote.movedCount + flowStats.remote.deletedCount > 0) {
$(' [ ').appendTo(remoteStats);
if (flowStats.conflicts > 0) {
$(' '+flowStats.conflicts+'').appendTo(remoteStats);
}
if (flowStats.remote.addedCount > 0) {
- $(' '+flowStats.remote.addedCount+'').appendTo(remoteStats);
+ const cell = $(' '+flowStats.remote.addedCount+'').appendTo(remoteStats);
+ RED.popover.tooltip(cell, RED._('diff.type.added'))
}
if (flowStats.remote.changedCount > 0) {
- $(' '+flowStats.remote.changedCount+'').appendTo(remoteStats);
+ const cell = $(' '+flowStats.remote.changedCount+'').appendTo(remoteStats);
+ RED.popover.tooltip(cell, RED._('diff.type.changed'))
+ }
+ if (flowStats.remote.movedCount > 0) {
+ const cell = $(' '+flowStats.remote.movedCount+'').appendTo(remoteStats);
+ RED.popover.tooltip(cell, RED._('diff.type.moved'))
}
if (flowStats.remote.deletedCount > 0) {
- $(' '+flowStats.remote.deletedCount+'').appendTo(remoteStats);
+ const cell = $(' '+flowStats.remote.deletedCount+'').appendTo(remoteStats);
+ RED.popover.tooltip(cell, RED._('diff.type.deleted'))
}
$(' ] ').appendTo(remoteStats);
}
@@ -293,7 +308,7 @@ RED.diff = (function() {
if (options.mode === "merge") {
diffPanel.addClass("red-ui-diff-panel-merge");
}
- var diffList = createDiffTable(diffPanel, diff);
+ var diffList = createDiffTable(diffPanel, diff, options);
var localDiff = diff.localDiff;
var remoteDiff = diff.remoteDiff;
@@ -516,7 +531,6 @@ RED.diff = (function() {
var hasChanges = false; // exists in original and local/remote but with changes
var unChanged = true; // existing in original,local,remote unchanged
- var localChanged = false;
if (localDiff.added[node.id]) {
stats.local.addedCount++;
@@ -535,12 +549,20 @@ RED.diff = (function() {
unChanged = false;
}
if (localDiff.changed[node.id]) {
- stats.local.changedCount++;
+ if (localDiff.positionChanged[node.id]) {
+ stats.local.movedCount++
+ } else {
+ stats.local.changedCount++;
+ }
hasChanges = true;
unChanged = false;
}
if (remoteDiff && remoteDiff.changed[node.id]) {
- stats.remote.changedCount++;
+ if (remoteDiff.positionChanged[node.id]) {
+ stats.remote.movedCount++
+ } else {
+ stats.remote.changedCount++;
+ }
hasChanges = true;
unChanged = false;
}
@@ -605,27 +627,32 @@ RED.diff = (function() {
localNodeDiv.addClass("red-ui-diff-status-moved");
var localMovedMessage = "";
if (node.z === localN.z) {
- localMovedMessage = RED._("diff.type.movedFrom",{id:(localDiff.currentConfig.all[node.id].z||'global')});
+ const movedFromNodeTab = localDiff.currentConfig.all[localDiff.currentConfig.all[node.id].z]
+ const movedFromLabel = `'${movedFromNodeTab ? (movedFromNodeTab.label || movedFromNodeTab.id) : 'global'}'`
+ localMovedMessage = RED._("diff.type.movedFrom",{id: movedFromLabel});
} else {
- localMovedMessage = RED._("diff.type.movedTo",{id:(localN.z||'global')});
+ const movedToNodeTab = localDiff.newConfig.all[localN.z]
+ const movedToLabel = `'${movedToNodeTab ? (movedToNodeTab.label || movedToNodeTab.id) : 'global'}'`
+ localMovedMessage = RED._("diff.type.movedTo",{id:movedToLabel});
}
$(' '+localMovedMessage+'').appendTo(localNodeDiv);
}
- localChanged = true;
} else if (localDiff.deleted[node.z]) {
localNodeDiv.addClass("red-ui-diff-empty");
- localChanged = true;
} else if (localDiff.deleted[node.id]) {
localNodeDiv.addClass("red-ui-diff-status-deleted");
$(' ').appendTo(localNodeDiv);
- localChanged = true;
} else if (localDiff.changed[node.id]) {
if (localDiff.newConfig.all[node.id].z !== node.z) {
localNodeDiv.addClass("red-ui-diff-empty");
} else {
- localNodeDiv.addClass("red-ui-diff-status-changed");
- $(' ').appendTo(localNodeDiv);
- localChanged = true;
+ if (localDiff.positionChanged[node.id]) {
+ localNodeDiv.addClass("red-ui-diff-status-moved");
+ $(' ').appendTo(localNodeDiv);
+ } else {
+ localNodeDiv.addClass("red-ui-diff-status-changed");
+ $(' ').appendTo(localNodeDiv);
+ }
}
} else {
if (localDiff.newConfig.all[node.id].z !== node.z) {
@@ -646,9 +673,13 @@ RED.diff = (function() {
remoteNodeDiv.addClass("red-ui-diff-status-moved");
var remoteMovedMessage = "";
if (node.z === remoteN.z) {
- remoteMovedMessage = RED._("diff.type.movedFrom",{id:(remoteDiff.currentConfig.all[node.id].z||'global')});
+ const movedFromNodeTab = remoteDiff.currentConfig.all[remoteDiff.currentConfig.all[node.id].z]
+ const movedFromLabel = `'${movedFromNodeTab ? (movedFromNodeTab.label || movedFromNodeTab.id) : 'global'}'`
+ remoteMovedMessage = RED._("diff.type.movedFrom",{id:movedFromLabel});
} else {
- remoteMovedMessage = RED._("diff.type.movedTo",{id:(remoteN.z||'global')});
+ const movedToNodeTab = remoteDiff.newConfig.all[remoteN.z]
+ const movedToLabel = `'${movedToNodeTab ? (movedToNodeTab.label || movedToNodeTab.id) : 'global'}'`
+ remoteMovedMessage = RED._("diff.type.movedTo",{id:movedToLabel});
}
$(' '+remoteMovedMessage+'').appendTo(remoteNodeDiv);
}
@@ -661,8 +692,13 @@ RED.diff = (function() {
if (remoteDiff.newConfig.all[node.id].z !== node.z) {
remoteNodeDiv.addClass("red-ui-diff-empty");
} else {
- remoteNodeDiv.addClass("red-ui-diff-status-changed");
- $(' ').appendTo(remoteNodeDiv);
+ if (remoteDiff.positionChanged[node.id]) {
+ remoteNodeDiv.addClass("red-ui-diff-status-moved");
+ $(' ').appendTo(remoteNodeDiv);
+ } else {
+ remoteNodeDiv.addClass("red-ui-diff-status-changed");
+ $(' ').appendTo(remoteNodeDiv);
+ }
}
} else {
if (remoteDiff.newConfig.all[node.id].z !== node.z) {
@@ -788,7 +824,7 @@ RED.diff = (function() {
$("
",{class:"red-ui-diff-list-cell-label"}).text("position").appendTo(row);
localCell = $(" | ",{class:"red-ui-diff-list-cell red-ui-diff-list-node-local"}).appendTo(row);
if (localNode) {
- localCell.addClass("red-ui-diff-status-"+(localChanged?"changed":"unchanged"));
+ localCell.addClass("red-ui-diff-status-"+(localChanged?"moved":"unchanged"));
$(''+(localChanged?'':'')+'').appendTo(localCell);
element = $('').appendTo(localCell);
var localPosition = {x:localNode.x,y:localNode.y};
@@ -813,7 +849,7 @@ RED.diff = (function() {
if (remoteNode !== undefined) {
remoteCell = $(" | ",{class:"red-ui-diff-list-cell red-ui-diff-list-node-remote"}).appendTo(row);
- remoteCell.addClass("red-ui-diff-status-"+(remoteChanged?"changed":"unchanged"));
+ remoteCell.addClass("red-ui-diff-status-"+(remoteChanged?"moved":"unchanged"));
if (remoteNode) {
$(''+(remoteChanged?'':'')+'').appendTo(remoteCell);
element = $('').appendTo(remoteCell);
@@ -1099,11 +1135,11 @@ RED.diff = (function() {
// var diff = generateDiff(originalFlow,nns);
// showDiff(diff);
// }
- function showRemoteDiff(diff) {
- if (diff === undefined) {
- getRemoteDiff(showRemoteDiff);
+ function showRemoteDiff(diff, options = {}) {
+ if (!diff) {
+ getRemoteDiff((remoteDiff) => showRemoteDiff(remoteDiff, options));
} else {
- showDiff(diff,{mode:'merge'});
+ showDiff(diff,{...options, mode:'merge'});
}
}
function parseNodes(nodeList) {
@@ -1144,23 +1180,53 @@ RED.diff = (function() {
}
}
function generateDiff(currentNodes,newNodes) {
- var currentConfig = parseNodes(currentNodes);
- var newConfig = parseNodes(newNodes);
- var added = {};
- var deleted = {};
- var changed = {};
- var moved = {};
+ const currentConfig = parseNodes(currentNodes);
+ const newConfig = parseNodes(newNodes);
+ const added = {};
+ const deleted = {};
+ const changed = {};
+ const positionChanged = {};
+ const moved = {};
Object.keys(currentConfig.all).forEach(function(id) {
- var node = RED.nodes.workspace(id)||RED.nodes.subflow(id)||RED.nodes.node(id);
+ const node = RED.nodes.workspace(id)||RED.nodes.subflow(id)||RED.nodes.node(id);
if (!newConfig.all.hasOwnProperty(id)) {
deleted[id] = true;
- } else if (JSON.stringify(currentConfig.all[id]) !== JSON.stringify(newConfig.all[id])) {
+ return
+ }
+ const currentConfigJSON = JSON.stringify(currentConfig.all[id])
+ const newConfigJSON = JSON.stringify(newConfig.all[id])
+
+ if (currentConfigJSON !== newConfigJSON) {
changed[id] = true;
-
if (currentConfig.all[id].z !== newConfig.all[id].z) {
moved[id] = true;
+ } else if (
+ currentConfig.all[id].x !== newConfig.all[id].x ||
+ currentConfig.all[id].y !== newConfig.all[id].y ||
+ currentConfig.all[id].w !== newConfig.all[id].w ||
+ currentConfig.all[id].h !== newConfig.all[id].h
+ ) {
+ // This node's position on its parent has changed. We want to
+ // check if this is the *only* change for this given node
+ const currentNodeClone = JSON.parse(currentConfigJSON)
+ const newNodeClone = JSON.parse(newConfigJSON)
+
+ delete currentNodeClone.x
+ delete currentNodeClone.y
+ delete currentNodeClone.w
+ delete currentNodeClone.h
+ delete newNodeClone.x
+ delete newNodeClone.y
+ delete newNodeClone.w
+ delete newNodeClone.h
+
+ if (JSON.stringify(currentNodeClone) === JSON.stringify(newNodeClone)) {
+ // Only the position has changed - everything else is the same
+ positionChanged[id] = true
+ }
}
+
}
});
Object.keys(newConfig.all).forEach(function(id) {
@@ -1169,13 +1235,14 @@ RED.diff = (function() {
}
});
- var diff = {
- currentConfig: currentConfig,
- newConfig: newConfig,
- added: added,
- deleted: deleted,
- changed: changed,
- moved: moved
+ const diff = {
+ currentConfig,
+ newConfig,
+ added,
+ deleted,
+ changed,
+ positionChanged,
+ moved
};
return diff;
}
@@ -1240,12 +1307,14 @@ RED.diff = (function() {
return diff;
}
- function showDiff(diff,options) {
+ function showDiff(diff, options) {
if (diffVisible) {
return;
}
options = options || {};
var mode = options.mode || 'merge';
+
+ options.hidePositionChanges = true
var localDiff = diff.localDiff;
var remoteDiff = diff.remoteDiff;
@@ -1315,6 +1384,9 @@ RED.diff = (function() {
if (!$("#red-ui-diff-view-diff-merge").hasClass('disabled')) {
refreshConflictHeader(diff);
mergeDiff(diff);
+ if (options.onmerge) {
+ options.onmerge()
+ }
RED.tray.close();
}
}
@@ -1345,6 +1417,7 @@ RED.diff = (function() {
var newConfig = [];
var node;
var nodeChangedStates = {};
+ var nodeMovedStates = {};
var localChangedStates = {};
for (id in localDiff.newConfig.all) {
if (localDiff.newConfig.all.hasOwnProperty(id)) {
@@ -1352,12 +1425,14 @@ RED.diff = (function() {
if (resolutions[id] === 'local') {
if (node) {
nodeChangedStates[id] = node.changed;
+ nodeMovedStates[id] = node.moved;
}
newConfig.push(localDiff.newConfig.all[id]);
} else if (resolutions[id] === 'remote') {
if (!remoteDiff.deleted[id] && remoteDiff.newConfig.all.hasOwnProperty(id)) {
if (node) {
nodeChangedStates[id] = node.changed;
+ nodeMovedStates[id] = node.moved;
}
localChangedStates[id] = 1;
newConfig.push(remoteDiff.newConfig.all[id]);
@@ -1381,8 +1456,9 @@ RED.diff = (function() {
}
return {
config: newConfig,
- nodeChangedStates: nodeChangedStates,
- localChangedStates: localChangedStates
+ nodeChangedStates,
+ nodeMovedStates,
+ localChangedStates
}
}
@@ -1393,6 +1469,7 @@ RED.diff = (function() {
var newConfig = appliedDiff.config;
var nodeChangedStates = appliedDiff.nodeChangedStates;
+ var nodeMovedStates = appliedDiff.nodeMovedStates;
var localChangedStates = appliedDiff.localChangedStates;
var isDirty = RED.nodes.dirty();
@@ -1401,33 +1478,56 @@ RED.diff = (function() {
t:"replace",
config: RED.nodes.createCompleteNodeSet(),
changed: nodeChangedStates,
+ moved: nodeMovedStates,
+ complete: true,
dirty: isDirty,
rev: RED.nodes.version()
}
RED.history.push(historyEvent);
- var originalFlow = RED.nodes.originalFlow();
- // originalFlow is what the editor things it loaded
- // - add any newly added nodes from remote diff as they are now part of the record
- for (var id in diff.remoteDiff.added) {
- if (diff.remoteDiff.added.hasOwnProperty(id)) {
- if (diff.remoteDiff.newConfig.all.hasOwnProperty(id)) {
- originalFlow.push(JSON.parse(JSON.stringify(diff.remoteDiff.newConfig.all[id])));
- }
- }
- }
+ // var originalFlow = RED.nodes.originalFlow();
+ // // originalFlow is what the editor thinks it loaded
+ // // - add any newly added nodes from remote diff as they are now part of the record
+ // for (var id in diff.remoteDiff.added) {
+ // if (diff.remoteDiff.added.hasOwnProperty(id)) {
+ // if (diff.remoteDiff.newConfig.all.hasOwnProperty(id)) {
+ // originalFlow.push(JSON.parse(JSON.stringify(diff.remoteDiff.newConfig.all[id])));
+ // }
+ // }
+ // }
RED.nodes.clear();
var imported = RED.nodes.import(newConfig);
- // Restore the original flow so subsequent merge resolutions can properly
- // identify new-vs-old
- RED.nodes.originalFlow(originalFlow);
+ // // Restore the original flow so subsequent merge resolutions can properly
+ // // identify new-vs-old
+ // RED.nodes.originalFlow(originalFlow);
+
+ // Clear all change flags from the import
+ RED.nodes.dirty(false);
+
+ const flowsToLock = new Set()
+ function ensureUnlocked(id) {
+ const flow = id && (RED.nodes.workspace(id) || RED.nodes.subflow(id) || null);
+ const isLocked = flow ? flow.locked : false;
+ if (flow && isLocked) {
+ flow.locked = false;
+ flowsToLock.add(flow)
+ }
+ }
imported.nodes.forEach(function(n) {
- if (nodeChangedStates[n.id] || localChangedStates[n.id]) {
+ if (nodeChangedStates[n.id]) {
+ ensureUnlocked(n.z)
n.changed = true;
}
+ if (nodeMovedStates[n.id]) {
+ ensureUnlocked(n.z)
+ n.moved = true;
+ }
+ })
+ flowsToLock.forEach(flow => {
+ flow.locked = true
})
RED.nodes.version(diff.remoteDiff.rev);
diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js
index 70de4d9ac..f11dd45d9 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js
@@ -190,7 +190,10 @@ RED.editor = (function() {
const input = $("#"+prefix+"-"+property);
const isTypedInput = input.length > 0 && input.next(".red-ui-typedInput-container").length > 0;
if (isTypedInput) {
- valid = input.typedInput("validate");
+ valid = input.typedInput("validate", { returnErrorMessage: true });
+ if (typeof valid === "string") {
+ return label ? label + ": " + valid : valid;
+ }
}
}
}
@@ -328,48 +331,108 @@ RED.editor = (function() {
/**
* Create a config-node select box for this property
- * @param node - the node being edited
- * @param property - the name of the field
- * @param type - the type of the config-node
+ * @param {Object} node - the node being edited
+ * @param {String} property - the name of the node property
+ * @param {String} type - the type of the config-node
+ * @param {"node-config-input"|"node-input"|"node-input-subflow-env"} prefix - the prefix to use in the input element ids
+ * @param {Function} [filter] - a function to filter the list of config nodes
+ * @param {Object} [env] - the environment variable object (only used for subflow env vars)
*/
- function prepareConfigNodeSelect(node,property,type,prefix,filter) {
- var input = $("#"+prefix+"-"+property);
- if (input.length === 0 ) {
+ function prepareConfigNodeSelect(node, property, type, prefix, filter, env) {
+ let nodeValue
+ if (prefix === 'node-input-subflow-env') {
+ nodeValue = env?.value
+ } else {
+ nodeValue = node[property]
+ }
+
+ const addBtnId = `${prefix}-btn-${property}-add`;
+ const editBtnId = `${prefix}-btn-${property}-edit`;
+ const selectId = prefix + '-' + property;
+ const input = $(`#${selectId}`);
+ if (input.length === 0) {
return;
}
- var newWidth = input.width();
- var attrStyle = input.attr('style');
- var m;
+ const attrStyle = input.attr('style');
+ let newWidth;
+ let m;
if ((m = /(^|\s|;)width\s*:\s*([^;]+)/i.exec(attrStyle)) !== null) {
newWidth = m[2].trim();
} else {
newWidth = "70%";
}
- var outerWrap = $("").css({
+ const outerWrap = $("").css({
width: newWidth,
- display:'inline-flex'
+ display: 'inline-flex'
});
- var select = $('').appendTo(outerWrap);
+ const select = $('').appendTo(outerWrap);
input.replaceWith(outerWrap);
// set the style attr directly - using width() on FF causes a value of 114%...
select.css({
'flex-grow': 1
});
- updateConfigNodeSelect(property,type,node[property],prefix,filter);
- $('')
- .css({"margin-left":"10px"})
+
+ updateConfigNodeSelect(property, type, nodeValue, prefix, filter);
+
+ // create the edit button
+ const editButton = $('')
+ .css({ "margin-left": "10px" })
.appendTo(outerWrap);
- $('#'+prefix+'-lookup-'+property).on("click", function(e) {
- showEditConfigNodeDialog(property,type,select.find(":selected").val(),prefix,node);
+
+ RED.popover.tooltip(editButton, RED._('editor.editConfig', { type }));
+
+ // create the add button
+ const addButton = $('')
+ .css({ "margin-left": "10px" })
+ .appendTo(outerWrap);
+ RED.popover.tooltip(addButton, RED._('editor.addNewConfig', { type }));
+
+ const disableButton = function(button, disabled) {
+ $(button).prop("disabled", !!disabled)
+ $(button).toggleClass("disabled", !!disabled)
+ };
+
+ // add the click handler
+ addButton.on("click", function (e) {
+ if (addButton.prop("disabled")) { return }
+ showEditConfigNodeDialog(property, type, "_ADD_", prefix, node);
e.preventDefault();
});
+ editButton.on("click", function (e) {
+ const selectedOpt = select.find(":selected")
+ if (selectedOpt.data('env')) { return } // don't show the dialog for env vars items (MVP. Future enhancement: lookup the env, if present, show the associated edit dialog)
+ if (editButton.prop("disabled")) { return }
+ showEditConfigNodeDialog(property, type, selectedOpt.val(), prefix, node);
+ e.preventDefault();
+ });
+
+ // dont permit the user to click the button if the selected option is an env var
+ select.on("change", function () {
+ const selectedOpt = select.find(":selected");
+ const optionsLength = select.find("option").length;
+ if (selectedOpt?.data('env')) {
+ disableButton(addButton, true);
+ disableButton(editButton, true);
+ // disable the edit button if no options available
+ } else if (optionsLength === 1 && selectedOpt.val() === "_ADD_") {
+ disableButton(addButton, false);
+ disableButton(editButton, true);
+ } else if (selectedOpt.val() === "") {
+ disableButton(addButton, false);
+ disableButton(editButton, true);
+ } else {
+ disableButton(addButton, false);
+ disableButton(editButton, false);
+ }
+ });
+
var label = "";
- var configNode = RED.nodes.node(node[property]);
- var node_def = RED.nodes.getType(type);
+ var configNode = RED.nodes.node(nodeValue);
if (configNode) {
- label = RED.utils.getNodeLabel(configNode,configNode.id);
+ label = RED.utils.getNodeLabel(configNode, configNode.id);
}
+
input.val(label);
}
@@ -777,12 +840,9 @@ RED.editor = (function() {
}
function defaultConfigNodeSort(A,B) {
- if (A.__label__ < B.__label__) {
- return -1;
- } else if (A.__label__ > B.__label__) {
- return 1;
- }
- return 0;
+ // sort case insensitive so that `[env] node-name` items are at the top and
+ // not mixed inbetween the the lower and upper case items
+ return (A.__label__ || '').localeCompare((B.__label__ || ''), undefined, {sensitivity: 'base'})
}
function updateConfigNodeSelect(name,type,value,prefix,filter) {
@@ -797,7 +857,7 @@ RED.editor = (function() {
}
$("#"+prefix+"-"+name).val(value);
} else {
-
+ let inclSubflowEnvvars = false
var select = $("#"+prefix+"-"+name);
var node_def = RED.nodes.getType(type);
select.children().remove();
@@ -805,6 +865,7 @@ RED.editor = (function() {
var activeWorkspace = RED.nodes.workspace(RED.workspaces.active());
if (!activeWorkspace) {
activeWorkspace = RED.nodes.subflow(RED.workspaces.active());
+ inclSubflowEnvvars = true
}
var configNodes = [];
@@ -820,6 +881,31 @@ RED.editor = (function() {
}
}
});
+
+ // as includeSubflowEnvvars is true, this is a subflow.
+ // include any 'conf-types' env vars as a list of avaiable configs
+ // in the config dropdown as `[env] node-name`
+ if (inclSubflowEnvvars && activeWorkspace.env) {
+ const parentEnv = activeWorkspace.env.filter(env => env.ui?.type === 'conf-types' && env.type === type)
+ if (parentEnv && parentEnv.length > 0) {
+ const locale = RED.i18n.lang()
+ for (let i = 0; i < parentEnv.length; i++) {
+ const tenv = parentEnv[i]
+ const ui = tenv.ui || {}
+ const labels = ui.label || {}
+ const labelText = RED.editor.envVarList.lookupLabel(labels, labels["en-US"] || tenv.name, locale)
+ const config = {
+ env: tenv,
+ id: '${' + parentEnv[0].name + '}',
+ type: type,
+ label: labelText,
+ __label__: `[env] ${labelText}`
+ }
+ configNodes.push(config)
+ }
+ }
+ }
+
var configSortFn = defaultConfigNodeSort;
if (typeof node_def.sort == "function") {
configSortFn = node_def.sort;
@@ -831,7 +917,10 @@ RED.editor = (function() {
}
configNodes.forEach(function(cn) {
- $('').text(RED.text.bidi.enforceTextDirectionWithUCC(cn.__label__)).appendTo(select);
+ const option = $('').text(RED.text.bidi.enforceTextDirectionWithUCC(cn.__label__)).appendTo(select);
+ if (cn.env) {
+ option.data('env', cn.env) // set a data attribute to indicate this is an env var (to inhibit the edit button)
+ }
delete cn.__label__;
});
@@ -844,7 +933,12 @@ RED.editor = (function() {
}
}
- select.append('');
+ if (!configNodes.length) {
+ select.append('');
+ } else {
+ select.append('');
+ }
+
window.setTimeout(function() { select.trigger("change");},50);
}
}
@@ -1512,9 +1606,16 @@ RED.editor = (function() {
}
RED.tray.close(function() {
var filter = null;
- if (editContext && typeof editContext._def.defaults[configProperty].filter === 'function') {
- filter = function(n) {
- return editContext._def.defaults[configProperty].filter.call(editContext,n);
+ // when editing a config via subflow edit panel, the `configProperty` will not
+ // necessarily be a property of the editContext._def.defaults object
+ // Also, when editing via dashboard sidebar, editContext can be null
+ // so we need to guard both scenarios
+ if (editContext?._def) {
+ const isSubflow = (editContext._def.type === 'subflow' || /subflow:.*/.test(editContext._def.type))
+ if (editContext && !isSubflow && typeof editContext._def.defaults?.[configProperty]?.filter === 'function') {
+ filter = function(n) {
+ return editContext._def.defaults[configProperty].filter.call(editContext,n);
+ }
}
}
updateConfigNodeSelect(configProperty,configType,editing_config_node.id,prefix,filter);
@@ -1575,7 +1676,7 @@ RED.editor = (function() {
RED.history.push(historyEvent);
RED.tray.close(function() {
var filter = null;
- if (editContext && typeof editContext._def.defaults[configProperty].filter === 'function') {
+ if (editContext && typeof editContext._def.defaults[configProperty]?.filter === 'function') {
filter = function(n) {
return editContext._def.defaults[configProperty].filter.call(editContext,n);
}
@@ -2116,6 +2217,7 @@ RED.editor = (function() {
}
},
editBuffer: function(options) { showTypeEditor("_buffer", options) },
+ getEditStack: function () { return [...editStack] },
buildEditForm: buildEditForm,
validateNode: validateNode,
updateNodeProperties: updateNodeProperties,
@@ -2160,6 +2262,7 @@ RED.editor = (function() {
filteredEditPanes[type] = filter
}
editPanes[type] = definition;
- }
+ },
+ prepareConfigNodeSelect: prepareConfigNodeSelect,
}
})();
diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/monaco.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/monaco.js
index 9f104faaf..cbeecd512 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/monaco.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/monaco.js
@@ -585,7 +585,7 @@ RED.editor.codeEditor.monaco = (function() {
createMonacoCompletionItem("set (flow context)", 'flow.set("${1:name}", ${1:value});','Set a value in flow context',range),
createMonacoCompletionItem("get (global context)", 'global.get("${1:name}");','Get a value from global context',range),
createMonacoCompletionItem("set (global context)", 'global.set("${1:name}", ${1:value});','Set a value in global context',range),
- createMonacoCompletionItem("get (env)", 'env.get("${1|NR_NODE_ID,NR_NODE_NAME,NR_NODE_PATH,NR_GROUP_ID,NR_GROUP_NAME,NR_FLOW_ID,NR_FLOW_NAME|}");','Get env variable value',range),
+ createMonacoCompletionItem("get (env)", 'env.get("${1|NR_NODE_ID,NR_NODE_NAME,NR_NODE_PATH,NR_GROUP_ID,NR_GROUP_NAME,NR_FLOW_ID,NR_FLOW_NAME,NR_SUBFLOW_NAME,NR_SUBFLOW_ID,NR_SUBFLOW_PATH|}");','Get env variable value',range),
createMonacoCompletionItem("cloneMessage (RED.util)", 'RED.util.cloneMessage(${1:msg});',
["```typescript",
"RED.util.cloneMessage(msg: T): T",
diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/envVarList.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/envVarList.js
index ba71e651f..dda5d1660 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/envVarList.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/envVarList.js
@@ -1,8 +1,9 @@
RED.editor.envVarList = (function() {
var currentLocale = 'en-US';
- var DEFAULT_ENV_TYPE_LIST = ['str','num','bool','json','bin','env'];
- var DEFAULT_ENV_TYPE_LIST_INC_CRED = ['str','num','bool','json','bin','env','cred','jsonata'];
+ const DEFAULT_ENV_TYPE_LIST = ['str','num','bool','json','bin','env'];
+ const DEFAULT_ENV_TYPE_LIST_INC_CONFTYPES = ['str','num','bool','json','bin','env','conf-types'];
+ const DEFAULT_ENV_TYPE_LIST_INC_CRED = ['str','num','bool','json','bin','env','cred','jsonata'];
/**
* Create env var edit interface
@@ -10,8 +11,8 @@ RED.editor.envVarList = (function() {
* @param node - subflow node
*/
function buildPropertiesList(envContainer, node) {
-
- var isTemplateNode = (node.type === "subflow");
+ if(RED.editor.envVarList.debug) { console.log('envVarList: buildPropertiesList', envContainer, node) }
+ const isTemplateNode = (node.type === "subflow");
envContainer
.css({
@@ -83,7 +84,14 @@ RED.editor.envVarList = (function() {
// if `opt.ui` does not exist, then apply defaults. If these
// defaults do not change then they will get stripped off
// before saving.
- if (opt.type === 'cred') {
+ if (opt.type === 'conf-types') {
+ opt.ui = opt.ui || {
+ icon: "fa fa-cog",
+ type: "conf-types",
+ opts: {opts:[]}
+ }
+ opt.ui.type = "conf-types";
+ } else if (opt.type === 'cred') {
opt.ui = opt.ui || {
icon: "",
type: "cred"
@@ -119,7 +127,7 @@ RED.editor.envVarList = (function() {
}
});
- buildEnvEditRow(uiRow, opt.ui, nameField, valueField);
+ buildEnvEditRow(uiRow, opt, nameField, valueField);
nameField.trigger('change');
}
},
@@ -181,21 +189,23 @@ RED.editor.envVarList = (function() {
* @param nameField - name field of env var
* @param valueField - value field of env var
*/
- function buildEnvEditRow(container, ui, nameField, valueField) {
+ function buildEnvEditRow(container, opt, nameField, valueField) {
+ const ui = opt.ui
+ if(RED.editor.envVarList.debug) { console.log('envVarList: buildEnvEditRow', container, ui, nameField, valueField) }
container.addClass("red-ui-editor-subflow-env-ui-row")
var topRow = $('').appendTo(container);
$('').appendTo(topRow);
$('').text(RED._("editor.icon")).appendTo(topRow);
$(' ').text(RED._("editor.label")).appendTo(topRow);
- $(' ').text(RED._("editor.inputType")).appendTo(topRow);
+ $(' ').text(RED._("editor.inputType")).appendTo(topRow);
var row = $(' ').appendTo(container);
$('
').appendTo(row);
var typeOptions = {
- 'input': {types:DEFAULT_ENV_TYPE_LIST},
- 'select': {opts:[]},
- 'spinner': {},
- 'cred': {}
+ 'input': {types:DEFAULT_ENV_TYPE_LIST_INC_CONFTYPES},
+ 'select': {opts:[]},
+ 'spinner': {},
+ 'cred': {}
};
if (ui.opts) {
typeOptions[ui.type] = ui.opts;
@@ -260,15 +270,16 @@ RED.editor.envVarList = (function() {
labelInput.attr("placeholder",$(this).val())
});
- var inputCell = $(' ').appendTo(row);
- var inputCellInput = $(' ').css("width","100%").appendTo(inputCell);
+ var inputCell = $(' ').appendTo(row);
+ var uiInputTypeInput = $(' ').css("width","100%").appendTo(inputCell);
if (ui.type === "input") {
- inputCellInput.val(ui.opts.types.join(","));
+ uiInputTypeInput.val(ui.opts.types.join(","));
}
var checkbox;
var selectBox;
- inputCellInput.typedInput({
+ // the options presented in the UI section for an "input" type selection
+ uiInputTypeInput.typedInput({
types: [
{
value:"input",
@@ -429,7 +440,7 @@ RED.editor.envVarList = (function() {
}
});
ui.opts.opts = vals;
- inputCellInput.typedInput('value',Date.now())
+ uiInputTypeInput.typedInput('value',Date.now())
}
}
}
@@ -496,12 +507,13 @@ RED.editor.envVarList = (function() {
} else {
delete ui.opts.max;
}
- inputCellInput.typedInput('value',Date.now())
+ uiInputTypeInput.typedInput('value',Date.now())
}
}
}
}
},
+ 'conf-types',
{
value:"none",
label:RED._("editor.inputs.none"), icon:"fa fa-times",hasValue:false
@@ -519,14 +531,20 @@ RED.editor.envVarList = (function() {
// In the case of 'input' type, the typedInput uses the multiple-option
// mode. Its value needs to be set to a comma-separately list of the
// selected options.
- inputCellInput.typedInput('value',ui.opts.types.join(","))
+ uiInputTypeInput.typedInput('value',ui.opts.types.join(","))
+ } else if (ui.type === 'conf-types') {
+ // In the case of 'conf-types' type, the typedInput will be populated
+ // with a list of all config nodes types installed.
+ // Restore the value to the last selected type
+ uiInputTypeInput.typedInput('value', opt.type)
} else {
// No other type cares about `value`, but doing this will
// force a refresh of the label now that `ui.opts` has
// been updated.
- inputCellInput.typedInput('value',Date.now())
+ uiInputTypeInput.typedInput('value',Date.now())
}
+ if(RED.editor.envVarList.debug) { console.log('envVarList: inputCellInput on:typedinputtypechange. ui.type = ' + ui.type) }
switch (ui.type) {
case 'input':
valueField.typedInput('types',ui.opts.types);
@@ -544,7 +562,7 @@ RED.editor.envVarList = (function() {
valueField.typedInput('types',['cred']);
break;
default:
- valueField.typedInput('types',DEFAULT_ENV_TYPE_LIST)
+ valueField.typedInput('types', DEFAULT_ENV_TYPE_LIST);
}
if (ui.type === 'checkbox') {
valueField.typedInput('type','bool');
@@ -556,8 +574,46 @@ RED.editor.envVarList = (function() {
}
}).on("change", function(evt,type) {
- if (ui.type === 'input') {
- var types = inputCellInput.typedInput('value');
+ const selectedType = $(this).typedInput('type') // the UI typedInput type
+ if(RED.editor.envVarList.debug) { console.log('envVarList: inputCellInput on:change. selectedType = ' + selectedType) }
+ if (selectedType === 'conf-types') {
+ const selectedConfigType = $(this).typedInput('value') || opt.type
+ let activeWorkspace = RED.nodes.workspace(RED.workspaces.active());
+ if (!activeWorkspace) {
+ activeWorkspace = RED.nodes.subflow(RED.workspaces.active());
+ }
+
+ // get a list of all config nodes matching the selectedValue
+ const configNodes = [];
+ RED.nodes.eachConfig(function(config) {
+ if (config.type == selectedConfigType && (!config.z || config.z === activeWorkspace.id)) {
+ const modulePath = config._def?.set?.id || ''
+ let label = RED.utils.getNodeLabel(config, config.id) || config.id;
+ label += config.d ? ' ['+RED._('workspace.disabled')+']' : '';
+ const _config = {
+ _type: selectedConfigType,
+ value: config.id,
+ label: label,
+ title: modulePath ? modulePath + ' - ' + label : label,
+ enabled: config.d !== true,
+ disabled: config.d === true,
+ }
+ configNodes.push(_config);
+ }
+ });
+ const tiTypes = {
+ value: selectedConfigType,
+ label: "config",
+ icon: "fa fa-cog",
+ options: configNodes,
+ }
+ valueField.typedInput('types', [tiTypes]);
+ valueField.typedInput('type', selectedConfigType);
+ valueField.typedInput('value', opt.value);
+
+
+ } else if (ui.type === 'input') {
+ var types = uiInputTypeInput.typedInput('value');
ui.opts.types = (types === "") ? ["str"] : types.split(",");
valueField.typedInput('types',ui.opts.types);
}
@@ -569,7 +625,7 @@ RED.editor.envVarList = (function() {
})
// Set the input to the right type. This will trigger the 'typedinputtypechange'
// event handler (just above ^^) to update the value if needed
- inputCellInput.typedInput('type',ui.type)
+ uiInputTypeInput.typedInput('type',ui.type)
}
function setLocale(l, list) {
diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js b/packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js
index 79c626af4..55c800be1 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js
@@ -153,10 +153,6 @@ RED.envVar = (function() {
}
function init(done) {
- if (!RED.user.hasPermission("settings.write")) {
- RED.notify(RED._("user.errors.settings"),"error");
- return;
- }
RED.userSettings.add({
id:'envvar',
title: RED._("env-var.environment"),
diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js b/packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js
index 30dcc4bd5..d68d03d3f 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js
@@ -221,12 +221,12 @@ RED.notifications = (function() {
if (newType) {
n.className = "red-ui-notification red-ui-notification-"+newType;
}
-
+ newTimeout = newOptions.hasOwnProperty('timeout')?newOptions.timeout:timeout
if (!fixed || newOptions.fixed === false) {
- newTimeout = (newOptions.hasOwnProperty('timeout')?newOptions.timeout:timeout)||5000;
+ newTimeout = newTimeout || 5000
}
if (newOptions.buttons) {
- var buttonSet = $(' ').appendTo(nn)
+ var buttonSet = $(' ').appendTo(nn)
newOptions.buttons.forEach(function(buttonDef) {
var b = $(' |