Merge branch 'node-red:master' into master

This commit is contained in:
ralphwetzel
2022-06-30 21:54:18 +02:00
committed by GitHub
104 changed files with 2713 additions and 1179 deletions

View File

@@ -167,6 +167,9 @@ RED.menu = (function() {
if (opt.disabled) {
item.addClass("disabled");
}
if (opt.visible === false) {
item.addClass("hide");
}
}
@@ -303,6 +306,14 @@ RED.menu = (function() {
}
}
function setVisible(id,state) {
if (!state) {
$("#"+id).parent().addClass("hide");
} else {
$("#"+id).parent().removeClass("hide");
}
}
function addItem(id,opt) {
var item = createMenuItem(opt);
if (opt !== null && opt.group) {
@@ -359,6 +370,7 @@ RED.menu = (function() {
isSelected: isSelected,
toggleSelected: toggleSelected,
setDisabled: setDisabled,
setVisible: setVisible,
addItem: addItem,
removeItem: removeItem,
setAction: setAction,

View File

@@ -63,16 +63,18 @@ RED.deploy = (function() {
'</a>'+
'<a id="red-ui-header-button-deploy-options" class="red-ui-deploy-button" href="#"><i class="fa fa-caret-down"></i></a>'+
'</span></li>').prependTo(".red-ui-header-toolbar");
RED.menu.init({id:"red-ui-header-button-deploy-options",
options: [
{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")}}},
{id:"deploymenu-item-flow",toggle:"deploy-type",icon:"red/images/deploy-flows.svg",label:RED._("deploy.modifiedFlows"),sublabel:RED._("deploy.modifiedFlowsDesc"), onselect:function(s) {if(s){changeDeploymentType("flows")}}},
{id:"deploymenu-item-node",toggle:"deploy-type",icon:"red/images/deploy-nodes.svg",label:RED._("deploy.modifiedNodes"),sublabel:RED._("deploy.modifiedNodesDesc"),onselect:function(s) { if(s){changeDeploymentType("nodes")}}},
null,
{id:"deploymenu-item-reload", icon:"red/images/deploy-reload.svg",label:RED._("deploy.restartFlows"),sublabel:RED._("deploy.restartFlowsDesc"),onselect:"core:restart-flows"},
]
});
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")}}},
{id:"deploymenu-item-flow",toggle:"deploy-type",icon:"red/images/deploy-flows.svg",label:RED._("deploy.modifiedFlows"),sublabel:RED._("deploy.modifiedFlowsDesc"), onselect:function(s) {if(s){changeDeploymentType("flows")}}},
{id:"deploymenu-item-node",toggle:"deploy-type",icon:"red/images/deploy-nodes.svg",label:RED._("deploy.modifiedNodes"),sublabel:RED._("deploy.modifiedNodesDesc"),onselect:function(s) { if(s){changeDeploymentType("nodes")}}},
null
]
if (RED.settings.runtimeState && RED.settings.runtimeState.ui === true) {
mainMenuItems.push({id:"deploymenu-item-runtime-start", icon:"red/images/start.svg",label:"Start"/*RED._("deploy.startFlows")*/,sublabel:"Start Flows" /*RED._("deploy.startFlowsDesc")*/,onselect:"core:start-flows", visible:false})
mainMenuItems.push({id:"deploymenu-item-runtime-stop", icon:"red/images/stop.svg",label:"Stop"/*RED._("deploy.startFlows")*/,sublabel:"Stop Flows" /*RED._("deploy.startFlowsDesc")*/,onselect:"core:stop-flows", visible:false})
}
mainMenuItems.push({id:"deploymenu-item-reload", icon:"red/images/deploy-reload.svg",label:RED._("deploy.restartFlows"),sublabel:RED._("deploy.restartFlowsDesc"),onselect:"core:restart-flows"})
RED.menu.init({id:"red-ui-header-button-deploy-options", options: mainMenuItems });
} else if (type == "simple") {
var label = options.label || RED._("deploy.deploy");
var icon = 'red/images/deploy-full-o.svg';
@@ -100,6 +102,10 @@ RED.deploy = (function() {
RED.actions.add("core:deploy-flows",save);
if (type === "default") {
if (RED.settings.runtimeState && RED.settings.runtimeState.ui === true) {
RED.actions.add("core:stop-flows",function() { stopStartFlows("stop") });
RED.actions.add("core:start-flows",function() { stopStartFlows("start") });
}
RED.actions.add("core:restart-flows",restart);
RED.actions.add("core:set-deploy-type-to-full",function() { RED.menu.setSelected("deploymenu-item-full",true);});
RED.actions.add("core:set-deploy-type-to-modified-flows",function() { RED.menu.setSelected("deploymenu-item-flow",true); });
@@ -270,18 +276,73 @@ RED.deploy = (function() {
function sanitize(html) {
return html.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")
}
function restart() {
var startTime = Date.now();
$(".red-ui-deploy-button-content").css('opacity',0);
$(".red-ui-deploy-button-spinner").show();
var deployWasEnabled = !$("#red-ui-header-button-deploy").hasClass("disabled");
$("#red-ui-header-button-deploy").addClass("disabled");
deployInflight = true;
function shadeShow() {
$("#red-ui-header-shade").show();
$("#red-ui-editor-shade").show();
$("#red-ui-palette-shade").show();
$("#red-ui-sidebar-shade").show();
}
function shadeHide() {
$("#red-ui-header-shade").hide();
$("#red-ui-editor-shade").hide();
$("#red-ui-palette-shade").hide();
$("#red-ui-sidebar-shade").hide();
}
function deployButtonSetBusy(){
$(".red-ui-deploy-button-content").css('opacity',0);
$(".red-ui-deploy-button-spinner").show();
$("#red-ui-header-button-deploy").addClass("disabled");
}
function deployButtonClearBusy(){
$(".red-ui-deploy-button-content").css('opacity',1);
$(".red-ui-deploy-button-spinner").hide();
}
function stopStartFlows(state) {
const startTime = Date.now()
const deployWasEnabled = !$("#red-ui-header-button-deploy").hasClass("disabled")
deployInflight = true
deployButtonSetBusy()
shadeShow()
$.ajax({
url:"flows/state",
type: "POST",
data: {state: state}
}).done(function(data,textStatus,xhr) {
if (deployWasEnabled) {
$("#red-ui-header-button-deploy").removeClass("disabled")
}
}).fail(function(xhr,textStatus,err) {
if (deployWasEnabled) {
$("#red-ui-header-button-deploy").removeClass("disabled")
}
if (xhr.status === 401) {
RED.notify(RED._("notification.error", { message: RED._("user.notAuthorized") }), "error")
} else if (xhr.responseText) {
const errorDetail = { message: err ? (err + "") : "" }
try {
errorDetail.message = JSON.parse(xhr.responseText).message
} finally {
errorDetail.message = errorDetail.message || xhr.responseText
}
RED.notify(RED._("notification.error", errorDetail), "error")
} else {
RED.notify(RED._("notification.error", { message: RED._("deploy.errors.noResponse") }), "error")
}
}).always(function() {
const delta = Math.max(0, 300 - (Date.now() - startTime))
setTimeout(function () {
deployButtonClearBusy()
shadeHide()
deployInflight = false
}, delta);
});
}
function restart() {
var startTime = Date.now();
var deployWasEnabled = !$("#red-ui-header-button-deploy").hasClass("disabled");
deployInflight = true;
deployButtonSetBusy();
$.ajax({
url:"flows",
type: "POST",
@@ -307,15 +368,10 @@ RED.deploy = (function() {
RED.notify(RED._("deploy.deployFailed",{message:RED._("deploy.errors.noResponse")}),"error");
}
}).always(function() {
deployInflight = false;
var delta = Math.max(0,300-(Date.now()-startTime));
setTimeout(function() {
$(".red-ui-deploy-button-content").css('opacity',1);
$(".red-ui-deploy-button-spinner").hide();
$("#red-ui-header-shade").hide();
$("#red-ui-editor-shade").hide();
$("#red-ui-palette-shade").hide();
$("#red-ui-sidebar-shade").hide();
deployButtonClearBusy();
deployInflight = false;
},delta);
});
}
@@ -450,21 +506,14 @@ RED.deploy = (function() {
const nns = RED.nodes.createCompleteNodeSet();
const startTime = Date.now();
$(".red-ui-deploy-button-content").css('opacity', 0);
$(".red-ui-deploy-button-spinner").show();
$("#red-ui-header-button-deploy").addClass("disabled");
deployButtonSetBusy();
const data = { flows: nns };
if (!force) {
data.rev = RED.nodes.version();
}
deployInflight = true;
$("#red-ui-header-shade").show();
$("#red-ui-editor-shade").show();
$("#red-ui-palette-shade").show();
$("#red-ui-sidebar-shade").show();
shadeShow();
$.ajax({
url: "flows",
type: "POST",
@@ -550,15 +599,11 @@ RED.deploy = (function() {
RED.notify(RED._("deploy.deployFailed", { message: RED._("deploy.errors.noResponse") }), "error");
}
}).always(function () {
deployInflight = false;
const delta = Math.max(0, 300 - (Date.now() - startTime));
setTimeout(function () {
$(".red-ui-deploy-button-content").css('opacity', 1);
$(".red-ui-deploy-button-spinner").hide();
$("#red-ui-header-shade").hide();
$("#red-ui-editor-shade").hide();
$("#red-ui-palette-shade").hide();
$("#red-ui-sidebar-shade").hide();
deployInflight = false;
deployButtonClearBusy()
shadeHide()
}, delta);
});
}

View File

@@ -21,7 +21,7 @@
const MONACO = "monaco";
const ACE = "ace";
const defaultEditor = ACE;
const defaultEditor = MONACO;
const DEFAULT_SETTINGS = { lib: defaultEditor, options: {} };
var selectedCodeEditor = null;
var initialised = false;
@@ -48,12 +48,12 @@
}
function create(options) {
//TODO: (quandry - for consideration)
//TODO: (quandry - for consideration)
// Below, I had to create a hidden element if options.id || options.element is not in the DOM
// I have seen 1 node calling `this.editor = RED.editor.createEditor()` with an
// I have seen 1 node calling `this.editor = RED.editor.createEditor()` with an
// invalid (non existing html element selector) (e.g. node-red-contrib-components does this)
// This causes monaco to throw an error when attempting to hook up its events to the dom & the rest of the 'oneditperapre'
// code is thus skipped.
// This causes monaco to throw an error when attempting to hook up its events to the dom & the rest of the 'oneditperapre'
// code is thus skipped.
// In ACE mode, creating an ACE editor (with an invalid ID) allows the editor to be created (but obviously there is no UI)
// Because one (or more) contrib nodes have left this bad code in place, how would we handle this?
// For compatibility, I have decided to create a hidden element so that at least an editor is created & errors do not occur.
@@ -79,7 +79,7 @@
return this.editor.create(options);//fallback to ACE
}
}
return {
init: init,
/**
@@ -91,7 +91,7 @@
},
/**
* Get user selected code editor
* @return {string} Returns
* @return {string} Returns
* @memberof RED.editor.codeEditor
*/
get editor() {
@@ -104,4 +104,4 @@
*/
create: create
}
})();
})();

View File

@@ -41,8 +41,12 @@ RED.editor.envVarList = (function() {
style: "width:100%",
class: "node-input-env-value",
type: "text",
}).attr("autocomplete","disable").appendTo(envRow)
valueField.typedInput({default:'str',types:isTemplateNode?DEFAULT_ENV_TYPE_LIST:DEFAULT_ENV_TYPE_LIST_INC_CRED});
}).attr("autocomplete","disable").appendTo(envRow);
var types = (opt.ui && opt.ui.opts && opt.ui.opts.types);
if (!types) {
types = isTemplateNode ? DEFAULT_ENV_TYPE_LIST : DEFAULT_ENV_TYPE_LIST_INC_CRED;
}
valueField.typedInput({default:'str',types:types});
valueField.typedInput('type', opt.type);
if (opt.type === "cred") {
if (opt.value) {
@@ -94,6 +98,11 @@ RED.editor.envVarList = (function() {
}
opt.ui.label = opt.ui.label || {};
opt.ui.type = opt.ui.type || "input";
if ((opt.ui.type === "cred") &&
opt.ui.opts &&
opt.ui.opts.types) {
opt.ui.type = "input";
}
var uiRow = $('<div/>').appendTo(container).hide();
// save current info for reverting on cancel

View File

@@ -37,8 +37,7 @@
if (!node._def.defaults || !node._def.defaults.hasOwnProperty("icon")) {
var icon = $("#red-ui-editor-node-icon").val()||"";
if (!this.isDefaultIcon) {
if ((icon !== node.icon) &&
(icon !== "")) {
if ((node.icon && icon !== node.icon) || (!node.icon && icon !== "")) {
editState.changes.icon = node.icon;
node.icon = icon;
editState.changed = true;

View File

@@ -20,10 +20,8 @@ RED.sidebar.help = (function() {
var helpSection;
var panels;
var panelRatio;
var helpTopics = [];
var treeList;
var tocPanel;
var helpIndex = {};
function resizeStack() {
var h = $(content).parent().height() - toolbar.outerHeight();
@@ -97,7 +95,10 @@ RED.sidebar.help = (function() {
var pendingContentLoad;
treeList.on('treelistselect', function(e,item) {
pendingContentLoad = item;
if (item.nodeType) {
if (item.tour) {
RED.tourGuide.run(item.tour);
}
else if (item.nodeType) {
showNodeTypeHelp(item.nodeType);
} else if (item.content) {
helpSection.empty();
@@ -189,7 +190,6 @@ RED.sidebar.help = (function() {
}
function refreshHelpIndex() {
helpTopics = [];
var modules = RED.nodes.registry.getModuleList();
var moduleNames = Object.keys(modules);
moduleNames.sort();
@@ -198,15 +198,32 @@ RED.sidebar.help = (function() {
label: RED._("sidebar.help.nodeHelp"),
children: [],
expanded: true
}
};
var tours = RED.tourGuide.list().map(function (item) {
return {
icon: "fa fa-play-circle-o",
label: item.label,
tour: item.path,
};
});
var helpData = [
{
id: 'changelog',
label: "Node-RED v"+RED.settings.version,
content: getChangelog
label: "Node-RED",
children: [
{
id: 'changelog',
label: RED._("sidebar.help.changeLog"),
content: getChangelog
},
{
label: RED._("tourGuide.welcomeTours"),
children: tours
}
]
},
nodeHelp
]
];
var subflows = RED.nodes.registry.getNodeTypes().filter(function(t) {return /subflow/.test(t)});
if (subflows.length > 0) {
nodeHelp.children.push({

View File

@@ -433,9 +433,30 @@ RED.tourGuide = (function() {
})
}
function listTour() {
return [
{
id: "3_0",
label: "3.0.0-beta.4",
path: "./tours/welcome.js"
},
{
id: "2_2",
label: "2.2.0",
path: "./tours/2.2/welcome.js"
},
{
id: "2_1",
label: "2.1.0",
path: "./tours/2.1/welcome.js"
}
];
}
return {
load: loadTour,
run: run,
list: listTour,
reset: function() {
RED.settings.set("editor.tours.welcome",'');
}

View File

@@ -979,13 +979,14 @@ RED.view.tools = (function() {
* - it uses `<paletteLabel> <N>` - where N is the next available integer that
* doesn't clash with any existing nodes of that type
* @param {Object} node The node to set the name of - if not provided, uses current selection
* @param {{ renameBlank: boolean, renameClash: boolean, generateHistory: boolean }} options Possible options are `renameBlank`, `renameClash` and `generateHistory`
*/
function generateNodeNames(node, options) {
options = options || {
options = Object.assign({
renameBlank: true,
renameClash: true,
generateHistory: true
}
}, options)
let nodes = node;
if (node) {
if (!Array.isArray(node)) {

View File

@@ -4877,6 +4877,9 @@ RED.view = (function() {
if (d._def.button) {
var buttonEnabled = isButtonEnabled(d);
this.__buttonGroup__.classList.toggle("red-ui-flow-node-button-disabled", !buttonEnabled);
if (RED.runtime && Object.hasOwn(RED.runtime,'started')) {
this.__buttonGroup__.classList.toggle("red-ui-flow-node-button-stopped", !RED.runtime.started);
}
var x = d._def.align == "right"?d.w-6:-25;
if (d._def.button.toggle && !d[d._def.button.toggle]) {
@@ -5872,6 +5875,7 @@ RED.view = (function() {
* @private
*/
function createNode(type, x, y, z) {
const wasDirty = RED.nodes.dirty()
var m = /^subflow:(.+)$/.exec(type);
var activeSubflow = z ? RED.nodes.subflow(z) : null;
if (activeSubflow && m) {
@@ -5930,7 +5934,7 @@ RED.view = (function() {
var historyEvent = {
t: "add",
nodes: [nn.id],
dirty: RED.nodes.dirty()
dirty: wasDirty
}
if (activeSubflow) {
var subflowRefresh = RED.subflow.refresh(true);

View File

@@ -284,9 +284,22 @@ RED.workspaces = (function() {
onselect: "core:show-last-hidden-flow"
}
]
if (hideStack.length > 0) {
let hiddenFlows = new Set()
for (let i = 0; i < hideStack.length; i++) {
let ids = hideStack[i]
if (!Array.isArray(ids)) {
ids = [ids]
}
ids.forEach(id => {
if (RED.nodes.workspace(id)) {
hiddenFlows.add(id)
}
})
}
const flowCount = hiddenFlows.size;
if (flowCount > 0) {
menuItems.unshift({
label: RED._("workspace.hiddenFlows",{count: hideStack.length}),
label: RED._("workspace.hiddenFlows",{count: flowCount}),
onselect: "core:list-hidden-flows"
})
}