mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Merge branch 'dev' into diagnostics
This commit is contained in:
@@ -474,7 +474,7 @@ var RED = (function() {
|
||||
var parts = topic.split("/");
|
||||
var node = RED.nodes.node(parts[1]);
|
||||
if (node) {
|
||||
if (msg.hasOwnProperty("text") && msg.text !== null && /^[a-zA-Z]/.test(msg.text)) {
|
||||
if (msg.hasOwnProperty("text") && msg.text !== null && /^[@a-zA-Z]/.test(msg.text)) {
|
||||
msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()});
|
||||
}
|
||||
node.status = msg;
|
||||
|
@@ -9,12 +9,14 @@
|
||||
*
|
||||
* options:
|
||||
*
|
||||
* search : function(value, [done])
|
||||
* A function that is passed the current contents of the input whenever
|
||||
* it changes.
|
||||
* The function must either return auto-complete options, or pass them
|
||||
* to the optional 'done' parameter.
|
||||
* If the function signature includes 'done', it must be used
|
||||
* search: function(value, [done])
|
||||
* A function that is passed the current contents of the input whenever
|
||||
* it changes.
|
||||
* The function must either return auto-complete options, or pass them
|
||||
* to the optional 'done' parameter.
|
||||
* If the function signature includes 'done', it must be used
|
||||
* minLength: number
|
||||
* If `minLength` is 0, pressing down arrow will show the list
|
||||
*
|
||||
* The auto-complete options should be an array of objects in the form:
|
||||
* {
|
||||
@@ -26,10 +28,11 @@
|
||||
|
||||
$.widget( "nodered.autoComplete", {
|
||||
_create: function() {
|
||||
var that = this;
|
||||
const that = this;
|
||||
this.completionMenuShown = false;
|
||||
this.options.search = this.options.search || function() { return [] }
|
||||
this.element.addClass("red-ui-autoComplete")
|
||||
this.options.minLength = parseInteger(this.options.minLength, 1, 0);
|
||||
this.options.search = this.options.search || function() { return [] };
|
||||
this.element.addClass("red-ui-autoComplete");
|
||||
this.element.on("keydown.red-ui-autoComplete", function(evt) {
|
||||
if ((evt.keyCode === 13 || evt.keyCode === 9) && that.completionMenuShown) {
|
||||
var opts = that.menu.options();
|
||||
@@ -71,8 +74,8 @@
|
||||
this.completionMenuShown = true;
|
||||
},
|
||||
_updateCompletions: function(val) {
|
||||
var that = this;
|
||||
if (val.trim() === "") {
|
||||
const that = this;
|
||||
if (val.trim().length < this.options.minLength) {
|
||||
if (this.completionMenuShown) {
|
||||
this.menu.hide();
|
||||
}
|
||||
@@ -96,7 +99,7 @@
|
||||
}
|
||||
}
|
||||
if (this.options.search.length === 2) {
|
||||
var requestId = 1+Math.floor(Math.random()*10000);
|
||||
const requestId = 1+Math.floor(Math.random()*10000);
|
||||
this.pendingRequest = requestId;
|
||||
this.options.search(val,function(completions) { displayResults(completions,requestId);})
|
||||
} else {
|
||||
@@ -112,4 +115,12 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
function parseInteger(input, def, min, max) {
|
||||
if(input == null) { return (def || 0); }
|
||||
min = min == null ? Number.NEGATIVE_INFINITY : min;
|
||||
max = max == null ? Number.POSITIVE_INFINITY : max;
|
||||
let n = parseInt(input);
|
||||
if(isNaN(n) || n < min || n > max) { n = def || 0; }
|
||||
return n;
|
||||
}
|
||||
})(jQuery);
|
||||
|
@@ -359,6 +359,7 @@ RED.popover = (function() {
|
||||
setTimeout(closePopup,delay.hide);
|
||||
}
|
||||
});
|
||||
|
||||
if (trigger === 'hover') {
|
||||
target.on('mouseenter',function(e) {
|
||||
clearTimeout(timer);
|
||||
@@ -470,6 +471,10 @@ RED.popover = (function() {
|
||||
popover.setAction = function(newAction) {
|
||||
action = newAction;
|
||||
}
|
||||
popover.delete = function() {
|
||||
target.off("mouseenter");
|
||||
target.off("mouseleave");
|
||||
};
|
||||
return popover;
|
||||
|
||||
},
|
||||
|
@@ -105,8 +105,8 @@
|
||||
}
|
||||
});
|
||||
this.element.on("keydown",function(e) {
|
||||
if (!menuShown && e.keyCode === 40) {
|
||||
//DOWN
|
||||
if (!menuShown && e.keyCode === 40 && $(this).val() === '') {
|
||||
//DOWN (only show menu if search field is emty)
|
||||
showMenu();
|
||||
}
|
||||
});
|
||||
|
@@ -670,7 +670,7 @@ RED.tabs = (function() {
|
||||
}
|
||||
var link = $("<a/>",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li);
|
||||
if (tab.icon) {
|
||||
$('<img src="'+tab.icon+'" class="red-ui-tab-icon"/>').appendTo(link);
|
||||
$('<i>',{class:"red-ui-tab-icon", style:"mask-image: url("+tab.icon+"); -webkit-mask-image: url("+tab.icon+");"}).appendTo(link);
|
||||
} else if (tab.iconClass) {
|
||||
$('<i>',{class:"red-ui-tab-icon "+tab.iconClass}).appendTo(link);
|
||||
}
|
||||
|
@@ -55,34 +55,46 @@
|
||||
}
|
||||
|
||||
var autoComplete = function(options) {
|
||||
function getMatch(value, searchValue) {
|
||||
const idx = value.toLowerCase().indexOf(searchValue.toLowerCase());
|
||||
const len = idx > -1 ? searchValue.length : 0;
|
||||
return {
|
||||
index: idx,
|
||||
found: idx > -1,
|
||||
pre: value.substring(0,idx),
|
||||
match: value.substring(idx,idx+len),
|
||||
post: value.substring(idx+len),
|
||||
}
|
||||
}
|
||||
function generateSpans(match) {
|
||||
const els = [];
|
||||
if(match.pre) { els.push($('<span/>').text(match.pre)); }
|
||||
if(match.match) { els.push($('<span/>',{style:"font-weight: bold; color: var(--red-ui-text-color-link);"}).text(match.match)); }
|
||||
if(match.post) { els.push($('<span/>').text(match.post)); }
|
||||
return els;
|
||||
}
|
||||
return function(val) {
|
||||
var matches = [];
|
||||
options.forEach(opt => {
|
||||
let v = opt.value;
|
||||
var i = v.toLowerCase().indexOf(val.toLowerCase());
|
||||
if (i > -1) {
|
||||
var pre = v.substring(0,i);
|
||||
var matchedVal = v.substring(i,i+val.length);
|
||||
var post = v.substring(i+val.length)
|
||||
|
||||
var el = $('<div/>',{style:"white-space:nowrap; overflow: hidden; flex-grow:1"});
|
||||
$('<span/>').text(pre).appendTo(el);
|
||||
$('<span/>',{style:"font-weight: bold"}).text(matchedVal).appendTo(el);
|
||||
$('<span/>').text(post).appendTo(el);
|
||||
|
||||
var element = $('<div>',{style: "display: flex"});
|
||||
el.appendTo(element);
|
||||
if (opt.source) {
|
||||
$('<div>').css({
|
||||
"font-size": "0.8em"
|
||||
}).text(opt.source.join(",")).appendTo(element);
|
||||
const optVal = opt.value;
|
||||
const optSrc = (opt.source||[]).join(",");
|
||||
const valMatch = getMatch(optVal, val);
|
||||
const srcMatch = getMatch(optSrc, val);
|
||||
if (valMatch.found || srcMatch.found) {
|
||||
const element = $('<div>',{style: "display: flex"});
|
||||
const valEl = $('<div/>',{style:"font-family: var(--red-ui-monospace-font); white-space:nowrap; overflow: hidden; flex-grow:1"});
|
||||
valEl.append(generateSpans(valMatch));
|
||||
valEl.appendTo(element);
|
||||
if (optSrc) {
|
||||
const optEl = $('<div>').css({ "font-size": "0.8em" });
|
||||
optEl.append(generateSpans(srcMatch));
|
||||
optEl.appendTo(element);
|
||||
}
|
||||
|
||||
matches.push({
|
||||
value: v,
|
||||
label: element,
|
||||
i:i
|
||||
})
|
||||
matches.push({
|
||||
value: optVal,
|
||||
label: element,
|
||||
i: (valMatch.found ? valMatch.index : srcMatch.index)
|
||||
});
|
||||
}
|
||||
})
|
||||
matches.sort(function(A,B){return A.i-B.i})
|
||||
@@ -93,6 +105,36 @@
|
||||
// This is a hand-generated list of completions for the core nodes (based on the node help html).
|
||||
var msgCompletions = [
|
||||
{ value: "payload" },
|
||||
{ value: "topic", source: ["mqtt","inject","rbe"] },
|
||||
{ value: "action", source: ["mqtt"] },
|
||||
{ value: "complete", source: ["join"] },
|
||||
{ value: "contentType", source: ["mqtt"] },
|
||||
{ value: "cookies", source: ["http request","http response"] },
|
||||
{ value: "correlationData", source: ["mqtt"] },
|
||||
{ value: "delay", source: ["delay","trigger"] },
|
||||
{ value: "encoding", source: ["file"] },
|
||||
{ value: "error", source: ["catch"] },
|
||||
{ value: "error.message", source: ["catch"] },
|
||||
{ value: "error.source", source: ["catch"] },
|
||||
{ value: "error.source.id", source: ["catch"] },
|
||||
{ value: "error.source.type", source: ["catch"] },
|
||||
{ value: "error.source.name", source: ["catch"] },
|
||||
{ value: "filename", source: ["file","file in"] },
|
||||
{ value: "flush", source: ["delay"] },
|
||||
{ value: "followRedirects", source: ["http request"] },
|
||||
{ value: "headers", source: ["http response","http request"] },
|
||||
{ value: "host", source: ["tcp request","http request"] },
|
||||
{ value: "ip", source: ["udp out"] },
|
||||
{ value: "kill", source: ["exec"] },
|
||||
{ value: "messageExpiryInterval", source: ["mqtt"] },
|
||||
{ value: "method", source: ["http request"] },
|
||||
{ value: "options", source: ["xml"] },
|
||||
{ value: "parts", source: ["split","join","batch","sort"] },
|
||||
{ value: "pid", source: ["exec"] },
|
||||
{ value: "port", source: ["tcp request"," udp out"] },
|
||||
{ value: "qos", source: ["mqtt"] },
|
||||
{ value: "rate", source: ["delay"] },
|
||||
{ value: "rejectUnauthorized", source: ["http request"] },
|
||||
{ value: "req", source: ["http in"]},
|
||||
{ value: "req.body", source: ["http in"]},
|
||||
{ value: "req.headers", source: ["http in"]},
|
||||
@@ -100,38 +142,28 @@
|
||||
{ value: "req.params", source: ["http in"]},
|
||||
{ value: "req.cookies", source: ["http in"]},
|
||||
{ value: "req.files", source: ["http in"]},
|
||||
{ value: "complete", source: ["join"] },
|
||||
{ value: "contentType", source: ["mqtt"] },
|
||||
{ value: "cookies", source: ["http in","http request"] },
|
||||
{ value: "correlationData", source: ["mqtt"] },
|
||||
{ value: "delay", source: ["delay","trigger"] },
|
||||
{ value: "encoding", source: ["file"] },
|
||||
{ value: "error", source: ["catch"] },
|
||||
{ value: "filename", source: ["file","file in"] },
|
||||
{ value: "flush", source: ["delay"] },
|
||||
{ value: "followRedirects", source: ["http request"] },
|
||||
{ value: "headers", source: ["http in"," http request"] },
|
||||
{ value: "kill", source: ["exec"] },
|
||||
{ value: "messageExpiryInterval", source: ["mqtt"] },
|
||||
{ value: "method", source: ["http-request"] },
|
||||
{ value: "options", source: ["xml"] },
|
||||
{ value: "parts", source: ["split","join"] },
|
||||
{ value: "pid", source: ["exec"] },
|
||||
{ value: "qos", source: ["mqtt"] },
|
||||
{ value: "rate", source: ["delay"] },
|
||||
{ value: "rejectUnauthorized", source: ["http request"] },
|
||||
{ value: "requestTimeout", source: ["http request"] },
|
||||
{ value: "reset", source: ["delay","trigger","join","rbe"] },
|
||||
{ value: "responseCookies", source: ["http request"] },
|
||||
{ value: "responseTopic", source: ["mqtt"] },
|
||||
{ value: "responseURL", source: ["http request"] },
|
||||
{ value: "restartTimeout", source: ["join"] },
|
||||
{ value: "retain", source: ["mqtt"] },
|
||||
{ value: "schema", source: ["json"] },
|
||||
{ value: "select", source: ["html"] },
|
||||
{ value: "statusCode", source: ["http in"] },
|
||||
{ value: "statusCode", source: ["http response","http request"] },
|
||||
{ value: "status", source: ["status"] },
|
||||
{ value: "status.text", source: ["status"] },
|
||||
{ value: "status.source", source: ["status"] },
|
||||
{ value: "status.source.type", source: ["status"] },
|
||||
{ value: "status.source.id", source: ["status"] },
|
||||
{ value: "status.source.name", source: ["status"] },
|
||||
{ value: "target", source: ["link call"] },
|
||||
{ value: "template", source: ["template"] },
|
||||
{ value: "toFront", source: ["delay"] },
|
||||
{ value: "topic", source: ["inject","mqtt","rbe"] },
|
||||
{ value: "url", source: ["http request"] },
|
||||
{ value: "userProperties", source: ["mqtt"] }
|
||||
{ value: "userProperties", source: ["mqtt"] },
|
||||
{ value: "_session", source: ["websocket out","tcp out"] },
|
||||
]
|
||||
var allOptions = {
|
||||
msg: {value:"msg",label:"msg.",validate:RED.utils.validatePropertyExpression, autoComplete: autoComplete(msgCompletions)},
|
||||
@@ -637,7 +669,7 @@
|
||||
if (opt.icon.indexOf("<") === 0) {
|
||||
$(opt.icon).prependTo(op);
|
||||
} else if (opt.icon.indexOf("/") !== -1) {
|
||||
$('<img>',{src:mapDeprecatedIcon(opt.icon),style:"margin-right: 4px; height: 18px;"}).prependTo(op);
|
||||
$('<i>',{class:"red-ui-typedInput-icon", style:"mask-image: url("+opt.icon+"); -webkit-mask-image: url("+opt.icon+");"}).prependTo(op);
|
||||
} else {
|
||||
$('<i>',{class:"red-ui-typedInput-icon "+opt.icon}).prependTo(op);
|
||||
}
|
||||
@@ -1147,7 +1179,8 @@
|
||||
this.elementDiv.show();
|
||||
if (opt.autoComplete) {
|
||||
this.input.autoComplete({
|
||||
search: opt.autoComplete
|
||||
search: opt.autoComplete,
|
||||
minLength: 0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -319,205 +319,208 @@ RED.deploy = (function() {
|
||||
},delta);
|
||||
});
|
||||
}
|
||||
function save(skipValidation,force) {
|
||||
if (!$("#red-ui-header-button-deploy").hasClass("disabled")) {
|
||||
if (!RED.user.hasPermission("flows.write")) {
|
||||
RED.notify(RED._("user.errors.deploy"),"error");
|
||||
function save(skipValidation, force) {
|
||||
if ($("#red-ui-header-button-deploy").hasClass("disabled")) {
|
||||
return; //deploy is disabled
|
||||
}
|
||||
if ($("#red-ui-header-shade").is(":visible")) {
|
||||
return; //deploy is shaded
|
||||
}
|
||||
if (!RED.user.hasPermission("flows.write")) {
|
||||
RED.notify(RED._("user.errors.deploy"), "error");
|
||||
return;
|
||||
}
|
||||
let hasUnusedConfig = false;
|
||||
if (!skipValidation) {
|
||||
let hasUnknown = false;
|
||||
let hasInvalid = false;
|
||||
const unknownNodes = [];
|
||||
const invalidNodes = [];
|
||||
|
||||
RED.nodes.eachConfig(function (node) {
|
||||
if (node.valid === undefined) {
|
||||
RED.editor.validateNode(node);
|
||||
}
|
||||
if (!node.valid && !node.d) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
}
|
||||
if (node.type === "unknown") {
|
||||
if (unknownNodes.indexOf(node.name) == -1) {
|
||||
unknownNodes.push(node.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
RED.nodes.eachNode(function (node) {
|
||||
if (!node.valid && !node.d) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
}
|
||||
if (node.type === "unknown") {
|
||||
if (unknownNodes.indexOf(node.name) == -1) {
|
||||
unknownNodes.push(node.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
hasUnknown = unknownNodes.length > 0;
|
||||
hasInvalid = invalidNodes.length > 0;
|
||||
|
||||
const unusedConfigNodes = [];
|
||||
RED.nodes.eachConfig(function (node) {
|
||||
if ((node._def.hasUsers !== false) && (node.users.length === 0)) {
|
||||
unusedConfigNodes.push(getNodeInfo(node));
|
||||
hasUnusedConfig = true;
|
||||
}
|
||||
});
|
||||
|
||||
let showWarning = false;
|
||||
let notificationMessage;
|
||||
let notificationButtons = [];
|
||||
let notification;
|
||||
if (hasUnknown && !ignoreDeployWarnings.unknown) {
|
||||
showWarning = true;
|
||||
notificationMessage = "<p>" + RED._('deploy.confirm.unknown') + "</p>" +
|
||||
'<ul class="red-ui-deploy-dialog-confirm-list"><li>' + cropList(unknownNodes).map(function (n) { return sanitize(n) }).join("</li><li>") + "</li></ul><p>" +
|
||||
RED._('deploy.confirm.confirm') +
|
||||
"</p>";
|
||||
|
||||
notificationButtons = [
|
||||
{
|
||||
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
|
||||
text: RED._("deploy.confirm.button.confirm"),
|
||||
class: "primary",
|
||||
click: function () {
|
||||
save(true);
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
];
|
||||
} else if (hasInvalid && !ignoreDeployWarnings.invalid) {
|
||||
showWarning = true;
|
||||
invalidNodes.sort(sortNodeInfo);
|
||||
|
||||
notificationMessage = "<p>" + RED._('deploy.confirm.improperlyConfigured') + "</p>" +
|
||||
'<ul class="red-ui-deploy-dialog-confirm-list"><li>' + cropList(invalidNodes.map(function (A) { return sanitize((A.tab ? "[" + A.tab + "] " : "") + A.label + " (" + A.type + ")") })).join("</li><li>") + "</li></ul><p>" +
|
||||
RED._('deploy.confirm.confirm') +
|
||||
"</p>";
|
||||
notificationButtons = [
|
||||
{
|
||||
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
|
||||
text: RED._("deploy.confirm.button.confirm"),
|
||||
class: "primary",
|
||||
click: function () {
|
||||
save(true);
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
if (showWarning) {
|
||||
notificationButtons.unshift(
|
||||
{
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function () {
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
);
|
||||
notification = RED.notify(notificationMessage, {
|
||||
modal: true,
|
||||
fixed: true,
|
||||
buttons: notificationButtons
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!skipValidation) {
|
||||
var hasUnknown = false;
|
||||
var hasInvalid = false;
|
||||
var hasUnusedConfig = false;
|
||||
|
||||
var unknownNodes = [];
|
||||
var invalidNodes = [];
|
||||
|
||||
RED.nodes.eachConfig(function(node) {
|
||||
if (node.valid === undefined) {
|
||||
RED.editor.validateNode(node);
|
||||
}
|
||||
if (!node.valid && !node.d) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
}
|
||||
if (node.type === "unknown") {
|
||||
if (unknownNodes.indexOf(node.name) == -1) {
|
||||
unknownNodes.push(node.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if (!node.valid && !node.d) {
|
||||
invalidNodes.push(getNodeInfo(node));
|
||||
}
|
||||
if (node.type === "unknown") {
|
||||
if (unknownNodes.indexOf(node.name) == -1) {
|
||||
unknownNodes.push(node.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
hasUnknown = unknownNodes.length > 0;
|
||||
hasInvalid = invalidNodes.length > 0;
|
||||
|
||||
var unusedConfigNodes = [];
|
||||
RED.nodes.eachConfig(function(node) {
|
||||
if ((node._def.hasUsers !== false) && (node.users.length === 0)) {
|
||||
unusedConfigNodes.push(getNodeInfo(node));
|
||||
hasUnusedConfig = true;
|
||||
}
|
||||
});
|
||||
|
||||
var showWarning = false;
|
||||
var notificationMessage;
|
||||
var notificationButtons = [];
|
||||
var notification;
|
||||
if (hasUnknown && !ignoreDeployWarnings.unknown) {
|
||||
showWarning = true;
|
||||
notificationMessage = "<p>"+RED._('deploy.confirm.unknown')+"</p>"+
|
||||
'<ul class="red-ui-deploy-dialog-confirm-list"><li>'+cropList(unknownNodes).map(function(n) { return sanitize(n) }).join("</li><li>")+"</li></ul><p>"+
|
||||
RED._('deploy.confirm.confirm')+
|
||||
"</p>";
|
||||
|
||||
notificationButtons= [
|
||||
{
|
||||
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
|
||||
text: RED._("deploy.confirm.button.confirm"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
save(true);
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
];
|
||||
} else if (hasInvalid && !ignoreDeployWarnings.invalid) {
|
||||
showWarning = true;
|
||||
invalidNodes.sort(sortNodeInfo);
|
||||
|
||||
notificationMessage = "<p>"+RED._('deploy.confirm.improperlyConfigured')+"</p>"+
|
||||
'<ul class="red-ui-deploy-dialog-confirm-list"><li>'+cropList(invalidNodes.map(function(A) { return sanitize( (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")")})).join("</li><li>")+"</li></ul><p>"+
|
||||
RED._('deploy.confirm.confirm')+
|
||||
"</p>";
|
||||
notificationButtons= [
|
||||
{
|
||||
id: "red-ui-deploy-dialog-confirm-deploy-deploy",
|
||||
text: RED._("deploy.confirm.button.confirm"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
save(true);
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
if (showWarning) {
|
||||
notificationButtons.unshift(
|
||||
{
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
);
|
||||
notification = RED.notify(notificationMessage,{
|
||||
modal: true,
|
||||
fixed: true,
|
||||
buttons:notificationButtons
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var nns = RED.nodes.createCompleteNodeSet();
|
||||
|
||||
var startTime = Date.now();
|
||||
$(".red-ui-deploy-button-content").css('opacity',0);
|
||||
$(".red-ui-deploy-button-spinner").show();
|
||||
$("#red-ui-header-button-deploy").addClass("disabled");
|
||||
|
||||
var 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();
|
||||
$.ajax({
|
||||
url:"flows",
|
||||
type: "POST",
|
||||
data: JSON.stringify(data),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
headers: {
|
||||
"Node-RED-Deployment-Type":deploymentType
|
||||
}
|
||||
}).done(function(data,textStatus,xhr) {
|
||||
RED.nodes.dirty(false);
|
||||
RED.nodes.version(data.rev);
|
||||
RED.nodes.originalFlow(nns);
|
||||
if (hasUnusedConfig) {
|
||||
RED.notify(
|
||||
'<p>'+RED._("deploy.successfulDeploy")+'</p>'+
|
||||
'<p>'+RED._("deploy.unusedConfigNodes")+' <a href="#" onclick="RED.sidebar.config.show(true); return false;">'+RED._("deploy.unusedConfigNodesLink")+'</a></p>',"success",false,6000);
|
||||
} else {
|
||||
RED.notify('<p>'+RED._("deploy.successfulDeploy")+'</p>',"success");
|
||||
}
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if (node.changed) {
|
||||
node.dirty = true;
|
||||
node.changed = false;
|
||||
}
|
||||
if (node.moved) {
|
||||
node.dirty = true;
|
||||
node.moved = false;
|
||||
}
|
||||
if(node.credentials) {
|
||||
delete node.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachConfig(function (confNode) {
|
||||
confNode.changed = false;
|
||||
if (confNode.credentials) {
|
||||
delete confNode.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachSubflow(function(subflow) {
|
||||
subflow.changed = false;
|
||||
});
|
||||
RED.nodes.eachWorkspace(function(ws) {
|
||||
ws.changed = false;
|
||||
});
|
||||
// Once deployed, cannot undo back to a clean state
|
||||
RED.history.markAllDirty();
|
||||
RED.view.redraw();
|
||||
RED.events.emit("deploy");
|
||||
}).fail(function(xhr,textStatus,err) {
|
||||
RED.nodes.dirty(true);
|
||||
$("#red-ui-header-button-deploy").removeClass("disabled");
|
||||
if (xhr.status === 401) {
|
||||
RED.notify(RED._("deploy.deployFailed",{message:RED._("user.notAuthorized")}),"error");
|
||||
} else if (xhr.status === 409) {
|
||||
resolveConflict(nns, true);
|
||||
} else if (xhr.responseText) {
|
||||
RED.notify(RED._("deploy.deployFailed",{message:xhr.responseText}),"error");
|
||||
} else {
|
||||
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();
|
||||
},delta);
|
||||
});
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
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();
|
||||
$.ajax({
|
||||
url: "flows",
|
||||
type: "POST",
|
||||
data: JSON.stringify(data),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
headers: {
|
||||
"Node-RED-Deployment-Type": deploymentType
|
||||
}
|
||||
}).done(function (data, textStatus, xhr) {
|
||||
RED.nodes.dirty(false);
|
||||
RED.nodes.version(data.rev);
|
||||
RED.nodes.originalFlow(nns);
|
||||
if (hasUnusedConfig) {
|
||||
RED.notify(
|
||||
'<p>' + RED._("deploy.successfulDeploy") + '</p>' +
|
||||
'<p>' + RED._("deploy.unusedConfigNodes") + ' <a href="#" onclick="RED.sidebar.config.show(true); return false;">' + RED._("deploy.unusedConfigNodesLink") + '</a></p>', "success", false, 6000);
|
||||
} else {
|
||||
RED.notify('<p>' + RED._("deploy.successfulDeploy") + '</p>', "success");
|
||||
}
|
||||
RED.nodes.eachNode(function (node) {
|
||||
if (node.changed) {
|
||||
node.dirty = true;
|
||||
node.changed = false;
|
||||
}
|
||||
if (node.moved) {
|
||||
node.dirty = true;
|
||||
node.moved = false;
|
||||
}
|
||||
if (node.credentials) {
|
||||
delete node.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachConfig(function (confNode) {
|
||||
confNode.changed = false;
|
||||
if (confNode.credentials) {
|
||||
delete confNode.credentials;
|
||||
}
|
||||
});
|
||||
RED.nodes.eachSubflow(function (subflow) {
|
||||
subflow.changed = false;
|
||||
});
|
||||
RED.nodes.eachWorkspace(function (ws) {
|
||||
ws.changed = false;
|
||||
});
|
||||
// Once deployed, cannot undo back to a clean state
|
||||
RED.history.markAllDirty();
|
||||
RED.view.redraw();
|
||||
RED.events.emit("deploy");
|
||||
}).fail(function (xhr, textStatus, err) {
|
||||
RED.nodes.dirty(true);
|
||||
$("#red-ui-header-button-deploy").removeClass("disabled");
|
||||
if (xhr.status === 401) {
|
||||
RED.notify(RED._("deploy.deployFailed", { message: RED._("user.notAuthorized") }), "error");
|
||||
} else if (xhr.status === 409) {
|
||||
resolveConflict(nns, true);
|
||||
} else if (xhr.responseText) {
|
||||
RED.notify(RED._("deploy.deployFailed", { message: xhr.responseText }), "error");
|
||||
} else {
|
||||
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();
|
||||
}, delta);
|
||||
});
|
||||
}
|
||||
return {
|
||||
init: init,
|
||||
|
@@ -110,7 +110,11 @@ RED.editor = (function() {
|
||||
var result = [];
|
||||
for (var prop in definition) {
|
||||
if (definition.hasOwnProperty(prop)) {
|
||||
if (!validateNodeProperty(node, definition, prop, properties[prop])) {
|
||||
var valid = validateNodeProperty(node, definition, prop, properties[prop]);
|
||||
if ((typeof valid) === "string") {
|
||||
result.push(valid);
|
||||
}
|
||||
else if(!valid) {
|
||||
result.push(prop);
|
||||
}
|
||||
}
|
||||
@@ -124,7 +128,7 @@ RED.editor = (function() {
|
||||
* @param definition - the node property definitions (either def.defaults or def.creds)
|
||||
* @param property - the property name being validated
|
||||
* @param value - the property value being validated
|
||||
* @returns {boolean} whether the node proprty is valid
|
||||
* @returns {boolean|string} whether the node proprty is valid. `true`: valid `false|String`: invalid
|
||||
*/
|
||||
function validateNodeProperty(node,definition,property,value) {
|
||||
var valid = true;
|
||||
@@ -136,22 +140,74 @@ RED.editor = (function() {
|
||||
if (/^\$\{[a-zA-Z_][a-zA-Z0-9_]*\}$/.test(value)) {
|
||||
return true;
|
||||
}
|
||||
var label = null;
|
||||
if (("label" in definition[property]) &&
|
||||
((typeof definition[property].label) == "string")) {
|
||||
label = definition[property].label;
|
||||
}
|
||||
if ("required" in definition[property] && definition[property].required) {
|
||||
valid = value !== "";
|
||||
if (!valid && label) {
|
||||
return RED._("validator.errors.missing-required-prop", {
|
||||
prop: label
|
||||
});
|
||||
}
|
||||
}
|
||||
if (valid && "validate" in definition[property]) {
|
||||
try {
|
||||
valid = definition[property].validate.call(node,value);
|
||||
var opt = {};
|
||||
if (label) {
|
||||
opt.label = label;
|
||||
}
|
||||
valid = definition[property].validate.call(node,value, opt);
|
||||
// If the validator takes two arguments, it is a 3.x validator that
|
||||
// can return a String to mean 'invalid' and provide a reason
|
||||
if ((definition[property].validate.length === 2) &&
|
||||
((typeof valid) === "string")) {
|
||||
return valid;
|
||||
} else {
|
||||
// Otherwise, a 2.x returns a truth-like/false-like value that
|
||||
// we should cooerce to a boolean.
|
||||
valid = !!valid
|
||||
}
|
||||
} catch(err) {
|
||||
console.log("Validation error:",node.type,node.id,"property: "+property,"value:",value,err);
|
||||
return RED._("validator.errors.validation-error", {
|
||||
prop: property,
|
||||
node: node.type,
|
||||
id: node.id,
|
||||
error: err.message
|
||||
});
|
||||
}
|
||||
}
|
||||
if (valid && definition[property].type && RED.nodes.getType(definition[property].type) && !("validate" in definition[property])) {
|
||||
if (!value || value == "_ADD_") {
|
||||
valid = definition[property].hasOwnProperty("required") && !definition[property].required;
|
||||
if (!valid && label) {
|
||||
return RED._("validator.errors.missing-required-prop", {
|
||||
prop: label
|
||||
});
|
||||
}
|
||||
} else {
|
||||
var configNode = RED.nodes.node(value);
|
||||
valid = (configNode && (configNode.valid == null || configNode.valid));
|
||||
if (configNode) {
|
||||
if ((configNode.valid == null) || configNode.valid) {
|
||||
return true;
|
||||
}
|
||||
if (label) {
|
||||
return RED._("validator.errors.invalid-config", {
|
||||
prop: label
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (label) {
|
||||
return RED._("validator.errors.missing-config", {
|
||||
prop: label
|
||||
});
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
@@ -179,10 +235,26 @@ RED.editor = (function() {
|
||||
if (defaults[property].hasOwnProperty("format") && defaults[property].format !== "" && input[0].nodeName === "DIV") {
|
||||
value = input.text();
|
||||
}
|
||||
if (!validateNodeProperty(node, defaults, property,value)) {
|
||||
var valid = validateNodeProperty(node, defaults, property,value);
|
||||
if (((typeof valid) === "string") || !valid) {
|
||||
input.addClass("input-error");
|
||||
if ((typeof valid) === "string") {
|
||||
var tooltip = input.data("tooltip");
|
||||
if (tooltip) {
|
||||
tooltip.setContent(valid);
|
||||
}
|
||||
else {
|
||||
tooltip = RED.popover.tooltip(input, valid);
|
||||
input.data("tooltip", tooltip);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
input.removeClass("input-error");
|
||||
var tooltip = input.data("tooltip");
|
||||
if (tooltip) {
|
||||
input.data("tooltip", null);
|
||||
tooltip.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1151,7 +1151,7 @@ RED.editor.codeEditor.monaco = (function() {
|
||||
try {
|
||||
var _model = ed.getModel();
|
||||
if (_model !== null) {
|
||||
var id = _model.getModeId(); // e.g. javascript
|
||||
var id = _model._languageId; // e.g. javascript
|
||||
var ra = _model._associatedResource.authority; //e.g. model
|
||||
var rp = _model._associatedResource.path; //e.g. /18
|
||||
var rs = _model._associatedResource.scheme; //e.g. inmemory
|
||||
|
@@ -168,7 +168,7 @@
|
||||
'b': { before:"**", after: "**", tooltip: RED._("markdownEditor.bold")},
|
||||
'i': { before:"_", after: "_", tooltip: RED._("markdownEditor.italic")},
|
||||
'code': { before:"`", after: "`", tooltip: RED._("markdownEditor.code")},
|
||||
'ol': { before:" * ", newline: true, tooltip: RED._("markdownEditor.ordered-list")},
|
||||
'ol': { before:" 1. ", newline: true, tooltip: RED._("markdownEditor.ordered-list")},
|
||||
'ul': { before:" - ", newline: true, tooltip: RED._("markdownEditor.unordered-list")},
|
||||
'bq': { before:"> ", newline: true, tooltip: RED._("markdownEditor.quote")},
|
||||
'link': { before:"[", after: "]()", tooltip: RED._("markdownEditor.link")},
|
||||
|
@@ -977,18 +977,31 @@ RED.view.tools = (function() {
|
||||
* 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
|
||||
*/
|
||||
function generateNodeNames(node) {
|
||||
const nodes = node?[node]:RED.view.selection().nodes;
|
||||
function generateNodeNames(node, options) {
|
||||
options = options || {
|
||||
renameBlank: true,
|
||||
renameClash: true,
|
||||
generateHistory: true
|
||||
}
|
||||
let nodes = node;
|
||||
if (node) {
|
||||
if (!Array.isArray(node)) {
|
||||
nodes = [ node ]
|
||||
}
|
||||
} else {
|
||||
nodes = RED.view.selection().nodes;
|
||||
}
|
||||
if (nodes && nodes.length > 0) {
|
||||
// Generate history event if using the workspace selection,
|
||||
// or if the provided node already exists
|
||||
const generateHistory = !node || !!RED.nodes.node(node.id)
|
||||
const generateHistory = options.generateHistory && (!node || !!RED.nodes.node(node.id))
|
||||
const historyEvents = []
|
||||
const typeIndex = {}
|
||||
let changed = false;
|
||||
nodes.forEach(n => {
|
||||
if (n._def && n._def.defaults && n._def.defaults.name) {
|
||||
const paletteLabel = RED.utils.getPaletteLabel(n.type, n._def)
|
||||
const nodeDef = n._def || RED.nodes.getType(n.type)
|
||||
if (nodeDef && nodeDef.defaults && nodeDef.defaults.name) {
|
||||
const paletteLabel = RED.utils.getPaletteLabel(n.type, nodeDef)
|
||||
const defaultNodeNameRE = new RegExp('^'+paletteLabel+' (\\d+)$')
|
||||
if (!typeIndex.hasOwnProperty(n.type)) {
|
||||
const existingNodes = RED.nodes.filterNodes({type: n.type})
|
||||
@@ -1004,7 +1017,7 @@ RED.view.tools = (function() {
|
||||
})
|
||||
typeIndex[n.type] = maxNameNumber + 1
|
||||
}
|
||||
if (n.name === '') {
|
||||
if ((options.renameBlank && n.name === '') || (options.renameClash && defaultNodeNameRE.test(n.name))) {
|
||||
if (generateHistory) {
|
||||
historyEvents.push({
|
||||
t:'edit',
|
||||
|
@@ -455,7 +455,7 @@ RED.view = (function() {
|
||||
}
|
||||
});
|
||||
|
||||
//add search to status-toolbar
|
||||
//add search to status-toolbar
|
||||
RED.statusBar.add({
|
||||
id: "view-search-tools",
|
||||
align: "left",
|
||||
@@ -604,7 +604,7 @@ RED.view = (function() {
|
||||
|
||||
RED.actions.add("core:copy-selection-to-internal-clipboard",copySelection);
|
||||
RED.actions.add("core:cut-selection-to-internal-clipboard",function(){copySelection();deleteSelection();});
|
||||
RED.actions.add("core:paste-from-internal-clipboard",function(){importNodes(clipboard,{generateIds: true});});
|
||||
RED.actions.add("core:paste-from-internal-clipboard",function(){importNodes(clipboard,{generateIds: true, generateDefaultNames: true});});
|
||||
|
||||
RED.actions.add("core:detach-selected-nodes", function() { detachSelectedNodes() })
|
||||
|
||||
@@ -2463,7 +2463,7 @@ RED.view = (function() {
|
||||
var removedEntities = RED.nodes.remove(node.id);
|
||||
removedNodes.push(node);
|
||||
removedNodes = removedNodes.concat(removedEntities.nodes);
|
||||
addToRemovedLinks(removedNodes.removedLinks);
|
||||
addToRemovedLinks(removedEntities.links);
|
||||
if (node.g) {
|
||||
var group = RED.nodes.group(node.g);
|
||||
if (selectedGroups.indexOf(group) === -1) {
|
||||
@@ -3480,7 +3480,6 @@ RED.view = (function() {
|
||||
enterActiveGroup(ag);
|
||||
activeGroup.selected = true;
|
||||
}
|
||||
console.log(d3.event);
|
||||
var cnodes = RED.nodes.getAllFlowNodes(mousedown_node);
|
||||
for (var n=0;n<cnodes.length;n++) {
|
||||
if (!cnodes[n].selected) {
|
||||
@@ -5403,12 +5402,16 @@ RED.view = (function() {
|
||||
* - addFlow - whether to import nodes to a new tab
|
||||
* - touchImport - whether this is a touch import. If not, imported nodes are
|
||||
* attachedto mouse for placing - "IMPORT_DRAGGING" state
|
||||
* - generateIds - whether to automatically generate new ids for all imported nodes
|
||||
* - generateDefaultNames - whether to automatically update any nodes with clashing
|
||||
* default names
|
||||
*/
|
||||
function importNodes(newNodesObj,options) {
|
||||
options = options || {
|
||||
addFlow: false,
|
||||
touchImport: false,
|
||||
generateIds: false
|
||||
generateIds: false,
|
||||
generateDefaultNames: false
|
||||
}
|
||||
var addNewFlow = options.addFlow
|
||||
var touchImport = options.touchImport;
|
||||
@@ -5436,7 +5439,13 @@ RED.view = (function() {
|
||||
if (!$.isArray(nodesToImport)) {
|
||||
nodesToImport = [nodesToImport];
|
||||
}
|
||||
|
||||
if (options.generateDefaultNames) {
|
||||
RED.actions.invoke("core:generate-node-names", nodesToImport, {
|
||||
renameBlank: false,
|
||||
renameClash: true,
|
||||
generateHistory: false
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
var activeSubflowChanged;
|
||||
|
@@ -118,20 +118,26 @@ RED.user = (function() {
|
||||
});
|
||||
|
||||
} else if (data.type == "strategy") {
|
||||
var sessionMessage = /[?&]session_message=(.*?)(?:$|&)/.exec(window.location.search);
|
||||
RED.sessionMessages = RED.sessionMessages || [];
|
||||
if (sessionMessage) {
|
||||
RED.sessionMessages.push(decodeURIComponent(sessionMessage[1]));
|
||||
if (history.pushState) {
|
||||
var newurl = window.location.protocol+"//"+window.location.host+window.location.pathname
|
||||
window.history.replaceState({ path: newurl }, "", newurl);
|
||||
} else {
|
||||
window.location.search = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (RED.sessionMessages.length === 0 && data.autoLogin) {
|
||||
document.location = data.loginRedirect
|
||||
return
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (;i<data.prompts.length;i++) {
|
||||
var field = data.prompts[i];
|
||||
var sessionMessage = /[?&]session_message=(.*?)(?:$|&)/.exec(window.location.search);
|
||||
if (sessionMessage) {
|
||||
RED.sessionMessages = RED.sessionMessages || [];
|
||||
RED.sessionMessages.push(sessionMessage[1]);
|
||||
if (history.pushState) {
|
||||
var newurl = window.location.protocol+"//"+window.location.host+window.location.pathname
|
||||
window.history.replaceState({ path: newurl }, "", newurl);
|
||||
} else {
|
||||
window.location.search = "";
|
||||
}
|
||||
}
|
||||
if (RED.sessionMessages) {
|
||||
var sessionMessages = $("<div/>",{class:"form-row",style:"text-align: center"}).appendTo("#node-dialog-login-fields");
|
||||
RED.sessionMessages.forEach(function (msg) {
|
||||
|
@@ -14,22 +14,72 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
RED.validators = {
|
||||
number: function(blankAllowed){return function(v) { return (blankAllowed&&(v===''||v===undefined)) || (v!=='' && !isNaN(v));}},
|
||||
regex: function(re){return function(v) { return re.test(v);}},
|
||||
typedInput: function(ptypeName,isConfig) { return function(v) {
|
||||
var ptype = $("#node-"+(isConfig?"config-":"")+"input-"+ptypeName).val() || this[ptypeName];
|
||||
if (ptype === 'json') {
|
||||
try {
|
||||
JSON.parse(v);
|
||||
number: function(blankAllowed,mopt){
|
||||
return function(v, opt) {
|
||||
if ((blankAllowed&&(v===''||v===undefined)) || (v!=='' && !isNaN(v))) {
|
||||
return true;
|
||||
} catch(err) {
|
||||
return false;
|
||||
}
|
||||
} else if (ptype === 'msg' || ptype === 'flow' || ptype === 'global' ) {
|
||||
return RED.utils.validatePropertyExpression(v);
|
||||
} else if (ptype === 'num') {
|
||||
return /^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/.test(v);
|
||||
}
|
||||
return true;
|
||||
}}
|
||||
if (opt && opt.label) {
|
||||
return RED._("validator.errors.invalid-num-prop", {
|
||||
prop: opt.label
|
||||
});
|
||||
}
|
||||
return opt ? RED._("validator.errors.invalid-num") : false;
|
||||
};
|
||||
},
|
||||
regex: function(re, mopt) {
|
||||
return function(v, opt) {
|
||||
if (re.test(v)) {
|
||||
return true;
|
||||
}
|
||||
if (opt && opt.label) {
|
||||
return RED._("validator.errors.invalid-regex-prop", {
|
||||
prop: opt.label
|
||||
});
|
||||
}
|
||||
return opt ? RED._("validator.errors.invalid-regexp") : false;
|
||||
};
|
||||
},
|
||||
typedInput: function(ptypeName,isConfig,mopt) {
|
||||
return function(v, opt) {
|
||||
var ptype = $("#node-"+(isConfig?"config-":"")+"input-"+ptypeName).val() || this[ptypeName];
|
||||
if (ptype === 'json') {
|
||||
try {
|
||||
JSON.parse(v);
|
||||
return true;
|
||||
} catch(err) {
|
||||
if (opt && opt.label) {
|
||||
return RED._("validator.errors.invalid-json-prop", {
|
||||
error: err.message,
|
||||
prop: opt.label,
|
||||
});
|
||||
}
|
||||
return opt ? RED._("validator.errors.invalid-json", {
|
||||
error: err.message
|
||||
}) : false;
|
||||
}
|
||||
} else if (ptype === 'msg' || ptype === 'flow' || ptype === 'global' ) {
|
||||
if (RED.utils.validatePropertyExpression(v)) {
|
||||
return true;
|
||||
}
|
||||
if (opt && opt.label) {
|
||||
return RED._("validator.errors.invalid-prop-prop", {
|
||||
prop: opt.label
|
||||
});
|
||||
}
|
||||
return opt ? RED._("validator.errors.invalid-prop") : false;
|
||||
} else if (ptype === 'num') {
|
||||
if (/^[+-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/.test(v)) {
|
||||
return true;
|
||||
}
|
||||
if (opt && opt.label) {
|
||||
return RED._("validator.errors.invalid-num-prop", {
|
||||
prop: opt.label
|
||||
});
|
||||
}
|
||||
return opt ? RED._("validator.errors.invalid-num") : false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user