mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Merge pull request #2873 from node-red/function-modules
Function node external modules
This commit is contained in:
@@ -143,6 +143,7 @@
|
||||
"nodeActionDisabled": "node actions disabled",
|
||||
"nodeActionDisabledSubflow": "node actions disabled within subflow",
|
||||
"missing-types": "<p>Flows stopped due to missing node types.</p>",
|
||||
"missing-modules": "<p>Flows stopped due to missing modules.</p>",
|
||||
"safe-mode":"<p>Flows stopped in safe mode.</p><p>You can modify your flows and deploy the changes to restart.</p>",
|
||||
"restartRequired": "Node-RED must be restarted to enable upgraded modules",
|
||||
"credentials_load_failed": "<p>Flows stopped as the credentials could not be decrypted.</p><p>The flow credential file is encrypted, but the project's encryption key is missing or invalid.</p>",
|
||||
|
@@ -315,6 +315,7 @@ var RED = (function() {
|
||||
id: notificationId
|
||||
}
|
||||
if (notificationId === "runtime-state") {
|
||||
RED.events.emit("runtime-state",msg);
|
||||
if (msg.error === "safe-mode") {
|
||||
options.buttons = [
|
||||
{
|
||||
@@ -347,6 +348,16 @@ var RED = (function() {
|
||||
}
|
||||
]
|
||||
}
|
||||
} else if (msg.error === "missing-modules") {
|
||||
text+="<ul><li>"+msg.modules.map(function(m) { return RED.utils.sanitize(m.module)+(m.error?(" - <small>"+RED.utils.sanitize(""+m.error)+"</small>"):"")}).join("</li><li>")+"</li></ul>";
|
||||
options.buttons = [
|
||||
{
|
||||
text: RED._("common.label.close"),
|
||||
click: function() {
|
||||
persistentNotifications[notificationId].hideNotification();
|
||||
}
|
||||
}
|
||||
]
|
||||
} else if (msg.error === "credentials_load_failed") {
|
||||
if (RED.settings.theme("projects.enabled",false)) {
|
||||
// projects enabled
|
||||
@@ -437,6 +448,9 @@ var RED = (function() {
|
||||
} else if (persistentNotifications.hasOwnProperty(notificationId)) {
|
||||
persistentNotifications[notificationId].close();
|
||||
delete persistentNotifications[notificationId];
|
||||
if (notificationId === 'runtime-state') {
|
||||
RED.events.emit("runtime-state",msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
RED.comms.subscribe("status/#",function(topic,msg) {
|
||||
|
@@ -29,6 +29,7 @@ RED.tabs = (function() {
|
||||
var currentTabWidth;
|
||||
var currentActiveTabWidth = 0;
|
||||
var collapsibleMenu;
|
||||
var mousedownTab;
|
||||
var preferredOrder = options.order;
|
||||
var ul = options.element || $("#"+options.id);
|
||||
var wrapper = ul.wrap( "<div>" ).parent();
|
||||
@@ -207,6 +208,11 @@ RED.tabs = (function() {
|
||||
if (dragActive) {
|
||||
return
|
||||
}
|
||||
if (evt.currentTarget !== mousedownTab) {
|
||||
mousedownTab = null;
|
||||
return;
|
||||
}
|
||||
mousedownTab = null;
|
||||
if (dblClickTime && Date.now()-dblClickTime < 400) {
|
||||
dblClickTime = 0;
|
||||
dblClickArmed = true;
|
||||
@@ -445,6 +451,7 @@ RED.tabs = (function() {
|
||||
}
|
||||
|
||||
ul.find("li.red-ui-tab a")
|
||||
.on("mousedown", function(evt) { mousedownTab = evt.currentTarget })
|
||||
.on("mouseup",onTabClick)
|
||||
.on("click", function(evt) {evt.preventDefault(); })
|
||||
.on("dblclick", function(evt) {evt.stopPropagation(); evt.preventDefault(); })
|
||||
@@ -509,8 +516,8 @@ RED.tabs = (function() {
|
||||
li.attr('id',"red-ui-tab-"+(tab.id.replace(".","-")));
|
||||
li.data("tabId",tab.id);
|
||||
|
||||
if (options.maximumTabWidth) {
|
||||
li.css("maxWidth",options.maximumTabWidth+"px");
|
||||
if (options.maximumTabWidth || tab.maximumTabWidth) {
|
||||
li.css("maxWidth",(options.maximumTabWidth || tab.maximumTabWidth) +"px");
|
||||
}
|
||||
var link = $("<a/>",{href:"#"+tab.id, class:"red-ui-tab-label"}).appendTo(li);
|
||||
if (tab.icon) {
|
||||
@@ -636,6 +643,7 @@ RED.tabs = (function() {
|
||||
}
|
||||
|
||||
}
|
||||
link.on("mousedown", function(evt) { mousedownTab = evt.currentTarget })
|
||||
link.on("mouseup",onTabClick);
|
||||
link.on("click", function(evt) { evt.preventDefault(); })
|
||||
link.on("dblclick", function(evt) { evt.stopPropagation(); evt.preventDefault(); })
|
||||
|
@@ -344,6 +344,16 @@
|
||||
that.element.val(that.value());
|
||||
that.element.trigger('change',[that.propertyType,that.value()]);
|
||||
});
|
||||
this.input.on('keyup', function(evt) {
|
||||
that.validate();
|
||||
that.element.val(that.value());
|
||||
that.element.trigger('keyup',evt);
|
||||
});
|
||||
this.input.on('paste', function(evt) {
|
||||
that.validate();
|
||||
that.element.val(that.value());
|
||||
that.element.trigger('paste',evt);
|
||||
});
|
||||
this.input.on('keydown', function(evt) {
|
||||
if (evt.keyCode >= 37 && evt.keyCode <= 40) {
|
||||
evt.stopPropagation();
|
||||
|
@@ -369,7 +369,7 @@ RED.palette.editor = (function() {
|
||||
if (v.modules) {
|
||||
var a = false;
|
||||
v.modules = v.modules.filter(function(m) {
|
||||
if (checkModuleAllowed(m.id,m.version,installAllowList,installDenyList)) {
|
||||
if (RED.utils.checkModuleAllowed(m.id,m.version,installAllowList,installDenyList)) {
|
||||
loadedIndex[m.id] = m;
|
||||
m.index = [m.id];
|
||||
if (m.keywords) {
|
||||
@@ -483,68 +483,6 @@ RED.palette.editor = (function() {
|
||||
var installAllowList = ['*'];
|
||||
var installDenyList = [];
|
||||
|
||||
function parseModuleList(list) {
|
||||
list = list || ["*"];
|
||||
return list.map(function(rule) {
|
||||
var m = /^(.+?)(?:@(.*))?$/.exec(rule);
|
||||
var wildcardPos = m[1].indexOf("*");
|
||||
wildcardPos = wildcardPos===-1?Infinity:wildcardPos;
|
||||
|
||||
return {
|
||||
module: new RegExp("^"+m[1].replace(/\*/g,".*")+"$"),
|
||||
version: m[2],
|
||||
wildcardPos: wildcardPos
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function checkAgainstList(module,version,list) {
|
||||
for (var i=0;i<list.length;i++) {
|
||||
var rule = list[i];
|
||||
if (rule.module.test(module)) {
|
||||
// Without a full semver library in the editor,
|
||||
// we skip the version check.
|
||||
// Not ideal - but will get caught in the runtime
|
||||
// if the user tries to install.
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkModuleAllowed(module,version,allowList,denyList) {
|
||||
if (!allowList && !denyList) {
|
||||
// Default to allow
|
||||
return true;
|
||||
}
|
||||
if (allowList.length === 0 && denyList.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var allowedRule = checkAgainstList(module,version,allowList);
|
||||
var deniedRule = checkAgainstList(module,version,denyList);
|
||||
// console.log("A",allowedRule)
|
||||
// console.log("D",deniedRule)
|
||||
|
||||
if (allowedRule && !deniedRule) {
|
||||
return true;
|
||||
}
|
||||
if (!allowedRule && deniedRule) {
|
||||
return false;
|
||||
}
|
||||
if (!allowedRule && !deniedRule) {
|
||||
return true;
|
||||
}
|
||||
if (allowedRule.wildcardPos !== deniedRule.wildcardPos) {
|
||||
return allowedRule.wildcardPos > deniedRule.wildcardPos
|
||||
} else {
|
||||
// First wildcard in same position.
|
||||
// Go with the longer matching rule. This isn't going to be 100%
|
||||
// right, but we are deep into edge cases at this point.
|
||||
return allowedRule.module.toString().length > deniedRule.module.toString().length
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (RED.settings.get('externalModules.palette.allowInstall', true) === false) {
|
||||
return;
|
||||
@@ -555,8 +493,8 @@ RED.palette.editor = (function() {
|
||||
installAllowList = settingsAllowList;
|
||||
installDenyList = settingsDenyList
|
||||
}
|
||||
installAllowList = parseModuleList(installAllowList);
|
||||
installDenyList = parseModuleList(installDenyList);
|
||||
installAllowList = RED.utils.parseModuleList(installAllowList);
|
||||
installDenyList = RED.utils.parseModuleList(installDenyList);
|
||||
|
||||
createSettingsPane();
|
||||
|
||||
|
@@ -1171,6 +1171,67 @@ RED.utils = (function() {
|
||||
return '#'+'000000'.slice(0, 6-s.length)+s;
|
||||
}
|
||||
|
||||
function parseModuleList(list) {
|
||||
list = list || ["*"];
|
||||
return list.map(function(rule) {
|
||||
var m = /^(.+?)(?:@(.*))?$/.exec(rule);
|
||||
var wildcardPos = m[1].indexOf("*");
|
||||
wildcardPos = wildcardPos===-1?Infinity:wildcardPos;
|
||||
|
||||
return {
|
||||
module: new RegExp("^"+m[1].replace(/\*/g,".*")+"$"),
|
||||
version: m[2],
|
||||
wildcardPos: wildcardPos
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function checkAgainstList(module,version,list) {
|
||||
for (var i=0;i<list.length;i++) {
|
||||
var rule = list[i];
|
||||
if (rule.module.test(module)) {
|
||||
// Without a full semver library in the editor,
|
||||
// we skip the version check.
|
||||
// Not ideal - but will get caught in the runtime
|
||||
// if the user tries to install.
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkModuleAllowed(module,version,allowList,denyList) {
|
||||
if (!allowList && !denyList) {
|
||||
// Default to allow
|
||||
return true;
|
||||
}
|
||||
if (allowList.length === 0 && denyList.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var allowedRule = checkAgainstList(module,version,allowList);
|
||||
var deniedRule = checkAgainstList(module,version,denyList);
|
||||
// console.log("A",allowedRule)
|
||||
// console.log("D",deniedRule)
|
||||
|
||||
if (allowedRule && !deniedRule) {
|
||||
return true;
|
||||
}
|
||||
if (!allowedRule && deniedRule) {
|
||||
return false;
|
||||
}
|
||||
if (!allowedRule && !deniedRule) {
|
||||
return true;
|
||||
}
|
||||
if (allowedRule.wildcardPos !== deniedRule.wildcardPos) {
|
||||
return allowedRule.wildcardPos > deniedRule.wildcardPos
|
||||
} else {
|
||||
// First wildcard in same position.
|
||||
// Go with the longer matching rule. This isn't going to be 100%
|
||||
// right, but we are deep into edge cases at this point.
|
||||
return allowedRule.module.toString().length > deniedRule.module.toString().length
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return {
|
||||
createObjectElement: buildMessageElement,
|
||||
getMessageProperty: getMessageProperty,
|
||||
@@ -1190,6 +1251,8 @@ RED.utils = (function() {
|
||||
sanitize: sanitize,
|
||||
renderMarkdown: renderMarkdown,
|
||||
createNodeIcon: createNodeIcon,
|
||||
getDarkerColor: getDarkerColor
|
||||
getDarkerColor: getDarkerColor,
|
||||
parseModuleList: parseModuleList,
|
||||
checkModuleAllowed: checkModuleAllowed
|
||||
}
|
||||
})();
|
||||
|
@@ -146,6 +146,13 @@ body {
|
||||
background-size: contain
|
||||
}
|
||||
|
||||
.red-ui-font-code {
|
||||
font-family: $monospace-font;
|
||||
font-size: $primary-font-size;
|
||||
color: $info-text-code-color;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: $monospace-font;
|
||||
font-size: $primary-font-size;
|
||||
|
@@ -174,8 +174,8 @@ button.red-ui-tray-resize-button {
|
||||
|
||||
.red-ui-editor .red-ui-tray {
|
||||
.dialog-form, #dialog-form, #node-config-dialog-edit-form {
|
||||
margin: 20px;
|
||||
height: calc(100% - 40px);
|
||||
margin: 10px 20px;
|
||||
height: calc(100% - 20px);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user