mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Add dynamic node api
Closes #322 - nodes modules can be installed/removed dynamically at runtime - nodes can be enabled/disabled - onpaletteadd/onpaletteremove api added to node definitions - initial implementation of nr-cli
This commit is contained in:
@@ -71,9 +71,23 @@ RED.comms = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function unsubscribe(topic,callback) {
|
||||
if (subscriptions.topic) {
|
||||
for (var i=0;i<subscriptions.topic.length;i++) {
|
||||
if (subscriptions.topic[i] === callback) {
|
||||
subscriptions.topic.splice(i,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (subscriptions.topic.length === 0) {
|
||||
delete subscriptions.topic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
connect: connectWS,
|
||||
subscribe: subscribe
|
||||
subscribe: subscribe,
|
||||
unsubscribe:unsubscribe
|
||||
}
|
||||
})();
|
||||
|
@@ -145,17 +145,35 @@ var RED = (function() {
|
||||
$.get('settings', function(data) {
|
||||
RED.settings = data;
|
||||
console.log("Node-RED: "+data.version);
|
||||
loadNodes();
|
||||
loadNodeList();
|
||||
});
|
||||
}
|
||||
function loadNodeList() {
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"application/json"
|
||||
},
|
||||
url: 'nodes',
|
||||
success: function(data) {
|
||||
RED.nodes.setNodeList(data);
|
||||
loadNodes();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadNodes() {
|
||||
$.get('nodes', function(data) {
|
||||
$("body").append(data);
|
||||
$(".palette-spinner").hide();
|
||||
$(".palette-scroll").show();
|
||||
$("#palette-search").show();
|
||||
loadFlows();
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"text/html"
|
||||
},
|
||||
url: 'nodes',
|
||||
success: function(data) {
|
||||
$("body").append(data);
|
||||
$(".palette-spinner").hide();
|
||||
$(".palette-scroll").show();
|
||||
$("#palette-search").show();
|
||||
loadFlows();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -176,24 +194,56 @@ var RED = (function() {
|
||||
}
|
||||
});
|
||||
RED.comms.subscribe("node/#",function(topic,msg) {
|
||||
var i;
|
||||
var i,m;
|
||||
var typeList;
|
||||
var info;
|
||||
|
||||
if (topic == "node/added") {
|
||||
var addedTypes = [];
|
||||
for (i=0;i<msg.length;i++) {
|
||||
var m = msg[i];
|
||||
m = msg[i];
|
||||
var id = m.id;
|
||||
$.get('nodes/'+id, function(data) {
|
||||
$("body").append(data);
|
||||
var typeList = "<ul><li>"+m.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify("Node"+(m.types.length!=1 ? "s":"")+" added to palette:"+typeList,"success");
|
||||
});
|
||||
RED.nodes.addNodeSet(m);
|
||||
if (m.loaded) {
|
||||
addedTypes = addedTypes.concat(m.types);
|
||||
$.get('nodes/'+id, function(data) {
|
||||
$("body").append(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (addedTypes.length) {
|
||||
typeList = "<ul><li>"+addedTypes.join("</li><li>")+"</li></ul>";
|
||||
RED.notify("Node"+(addedTypes.length!=1 ? "s":"")+" added to palette:"+typeList,"success");
|
||||
}
|
||||
} else if (topic == "node/removed") {
|
||||
if (msg.types) {
|
||||
for (i=0;i<msg.types.length;i++) {
|
||||
RED.palette.remove(msg.types[i]);
|
||||
for (i=0;i<msg.length;i++) {
|
||||
m = msg[i];
|
||||
info = RED.nodes.removeNodeSet(m.id);
|
||||
if (info.added) {
|
||||
typeList = "<ul><li>"+m.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify("Node"+(m.types.length!=1 ? "s":"")+" removed from palette:"+typeList,"success");
|
||||
}
|
||||
var typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" removed from palette:"+typeList,"success");
|
||||
}
|
||||
} else if (topic == "node/enabled") {
|
||||
if (msg.types) {
|
||||
info = RED.nodes.getNodeSet(msg.id);
|
||||
if (info.added) {
|
||||
RED.nodes.enableNodeSet(msg.id);
|
||||
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" enabled:"+typeList,"success");
|
||||
} else {
|
||||
$.get('nodes/'+msg.id, function(data) {
|
||||
$("body").append(data);
|
||||
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" added to palette:"+typeList,"success");
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (topic == "node/disabled") {
|
||||
if (msg.types) {
|
||||
RED.nodes.disableNodeSet(msg.id);
|
||||
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
|
||||
RED.notify("Node"+(msg.types.length!=1 ? "s":"")+" disabled:"+typeList,"success");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@@ -21,21 +21,101 @@ RED.nodes = (function() {
|
||||
var links = [];
|
||||
var defaultWorkspace;
|
||||
var workspaces = {};
|
||||
|
||||
function registerType(nt,def) {
|
||||
node_defs[nt] = def;
|
||||
// TODO: too tightly coupled into palette UI
|
||||
RED.palette.add(nt,def);
|
||||
}
|
||||
|
||||
|
||||
var registry = (function() {
|
||||
var nodeList = [];
|
||||
var nodeSets = {};
|
||||
var typeToId = {};
|
||||
var nodeDefinitions = {};
|
||||
|
||||
var exports = {
|
||||
getNodeList: function() {
|
||||
return nodeList;
|
||||
},
|
||||
setNodeList: function(list) {
|
||||
nodeList = [];
|
||||
for(var i=0;i<list.length;i++) {
|
||||
var ns = list[i];
|
||||
exports.addNodeSet(ns);
|
||||
}
|
||||
},
|
||||
addNodeSet: function(ns) {
|
||||
ns.added = false;
|
||||
nodeSets[ns.id] = ns;
|
||||
for (var j=0;j<ns.types.length;j++) {
|
||||
typeToId[ns.types[j]] = ns.id;
|
||||
}
|
||||
nodeList.push(ns);
|
||||
},
|
||||
removeNodeSet: function(id) {
|
||||
var ns = nodeSets[id];
|
||||
for (var j=0;j<ns.types.length;j++) {
|
||||
if (ns.added) {
|
||||
// TODO: too tightly coupled into palette UI
|
||||
RED.palette.remove(ns.types[j]);
|
||||
var def = nodeDefinitions[ns.types[j]];
|
||||
if (def.onpaletteremove && typeof def.onpaletteremove === "function") {
|
||||
def.onpaletteremove.call(def);
|
||||
}
|
||||
}
|
||||
delete typeToId[ns.types[j]];
|
||||
}
|
||||
delete nodeSets[id];
|
||||
for (var i=0;i<nodeList.length;i++) {
|
||||
if (nodeList[i].id == id) {
|
||||
nodeList.splice(i,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ns;
|
||||
},
|
||||
getNodeSet: function(id) {
|
||||
return nodeSets[id];
|
||||
},
|
||||
enableNodeSet: function(id) {
|
||||
var ns = nodeSets[id];
|
||||
ns.enabled = true;
|
||||
for (var j=0;j<ns.types.length;j++) {
|
||||
// TODO: too tightly coupled into palette UI
|
||||
RED.palette.show(ns.types[j]);
|
||||
var def = nodeDefinitions[ns.types[j]];
|
||||
if (def.onpaletteadd && typeof def.onpaletteadd === "function") {
|
||||
def.onpaletteadd.call(def);
|
||||
}
|
||||
}
|
||||
},
|
||||
disableNodeSet: function(id) {
|
||||
var ns = nodeSets[id];
|
||||
ns.enabled = false;
|
||||
for (var j=0;j<ns.types.length;j++) {
|
||||
// TODO: too tightly coupled into palette UI
|
||||
RED.palette.hide(ns.types[j]);
|
||||
var def = nodeDefinitions[ns.types[j]];
|
||||
if (def.onpaletteremove && typeof def.onpaletteremove === "function") {
|
||||
def.onpaletteremove.call(def);
|
||||
}
|
||||
}
|
||||
},
|
||||
registerNodeType: function(nt,def) {
|
||||
nodeDefinitions[nt] = def;
|
||||
nodeSets[typeToId[nt]].added = true;
|
||||
// TODO: too tightly coupled into palette UI
|
||||
RED.palette.add(nt,def);
|
||||
if (def.onpaletteadd && typeof def.onpaletteadd === "function") {
|
||||
def.onpaletteadd.call(def);
|
||||
}
|
||||
},
|
||||
getNodeType: function(nt) {
|
||||
return nodeDefinitions[nt];
|
||||
}
|
||||
}
|
||||
return exports;
|
||||
})();
|
||||
|
||||
function getID() {
|
||||
return (1+Math.random()*4294967295).toString(16);
|
||||
}
|
||||
|
||||
function getType(type) {
|
||||
return node_defs[type];
|
||||
}
|
||||
|
||||
function addNode(n) {
|
||||
if (n._def.category == "config") {
|
||||
configNodes[n.id] = n;
|
||||
@@ -48,7 +128,7 @@ RED.nodes = (function() {
|
||||
if (n._def.defaults.hasOwnProperty(d)) {
|
||||
var property = n._def.defaults[d];
|
||||
if (property.type) {
|
||||
var type = getType(property.type)
|
||||
var type = registry.getNodeType(property.type)
|
||||
if (type && type.category == "config") {
|
||||
var configNode = configNodes[n[d]];
|
||||
if (configNode) {
|
||||
@@ -101,7 +181,7 @@ RED.nodes = (function() {
|
||||
if (node._def.defaults.hasOwnProperty(d)) {
|
||||
var property = node._def.defaults[d];
|
||||
if (property.type) {
|
||||
var type = getType(property.type)
|
||||
var type = registry.getNodeType(property.type)
|
||||
if (type && type.category == "config") {
|
||||
var configNode = configNodes[node[d]];
|
||||
if (configNode) {
|
||||
@@ -229,7 +309,7 @@ RED.nodes = (function() {
|
||||
for (var d in node._def.defaults) {
|
||||
if (node._def.defaults[d].type && node[d] in configNodes) {
|
||||
var confNode = configNodes[node[d]];
|
||||
var exportable = getType(node._def.defaults[d].type).exportable;
|
||||
var exportable = registry.getNodeType(node._def.defaults[d].type).exportable;
|
||||
if ((exportable == null || exportable)) {
|
||||
if (!(node[d] in exportedConfigNodes)) {
|
||||
exportedConfigNodes[node[d]] = true;
|
||||
@@ -288,7 +368,7 @@ RED.nodes = (function() {
|
||||
for (i=0;i<newNodes.length;i++) {
|
||||
n = newNodes[i];
|
||||
// TODO: remove workspace in next release+1
|
||||
if (n.type != "workspace" && n.type != "tab" && !getType(n.type)) {
|
||||
if (n.type != "workspace" && n.type != "tab" && !registry.getNodeType(n.type)) {
|
||||
// TODO: get this UI thing out of here! (see below as well)
|
||||
n.name = n.type;
|
||||
n.type = "unknown";
|
||||
@@ -347,7 +427,7 @@ RED.nodes = (function() {
|
||||
n = newNodes[i];
|
||||
// TODO: remove workspace in next release+1
|
||||
if (n.type !== "workspace" && n.type !== "tab") {
|
||||
var def = getType(n.type);
|
||||
var def = registry.getNodeType(n.type);
|
||||
if (def && def.category == "config") {
|
||||
if (!RED.nodes.node(n.id)) {
|
||||
var configNode = {id:n.id,type:n.type,users:[]};
|
||||
@@ -424,8 +504,17 @@ RED.nodes = (function() {
|
||||
}
|
||||
|
||||
return {
|
||||
registerType: registerType,
|
||||
getType: getType,
|
||||
registry:registry,
|
||||
setNodeList: registry.setNodeList,
|
||||
|
||||
getNodeSet: registry.getNodeSet,
|
||||
addNodeSet: registry.addNodeSet,
|
||||
removeNodeSet: registry.removeNodeSet,
|
||||
enableNodeSet: registry.enableNodeSet,
|
||||
disableNodeSet: registry.disableNodeSet,
|
||||
|
||||
registerType: registry.registerNodeType,
|
||||
getType: registry.getNodeType,
|
||||
convertNode: convertNode,
|
||||
add: addNode,
|
||||
addLink: addLink,
|
||||
|
@@ -29,14 +29,21 @@ RED.palette = (function() {
|
||||
'<div id="palette-'+category+'-function"></div>'+
|
||||
'</div>'+
|
||||
'</div>');
|
||||
|
||||
|
||||
$("#header-"+category).on('click', function(e) {
|
||||
$(this).next().slideToggle();
|
||||
$(this).children("i").toggleClass("expanded");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
core.forEach(createCategoryContainer);
|
||||
|
||||
function addNodeType(nt,def) {
|
||||
|
||||
if ($("#palette_node_"+nt).length) {
|
||||
var nodeTypeId = nt.replace(" ","_");
|
||||
|
||||
if ($("#palette_node_"+nodeTypeId).length) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -46,7 +53,7 @@ RED.palette = (function() {
|
||||
var rootCategory = category.split("-")[0];
|
||||
|
||||
var d = document.createElement("div");
|
||||
d.id = "palette_node_"+nt;
|
||||
d.id = "palette_node_"+nodeTypeId;
|
||||
d.type = nt;
|
||||
|
||||
var label = /^(.*?)([ -]in|[ -]out)?$/.exec(nt)[1];
|
||||
@@ -106,17 +113,21 @@ RED.palette = (function() {
|
||||
revert: true,
|
||||
revertDuration: 50
|
||||
});
|
||||
|
||||
$("#header-"+category[0]).off('click').on('click', function(e) {
|
||||
$(this).next().slideToggle();
|
||||
$(this).children("i").toggleClass("expanded");
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function removeNodeType(type) {
|
||||
$("#palette_node_"+type).remove();
|
||||
function removeNodeType(nt) {
|
||||
var nodeTypeId = nt.replace(" ","_");
|
||||
$("#palette_node_"+nodeTypeId).remove();
|
||||
}
|
||||
function hideNodeType(nt) {
|
||||
var nodeTypeId = nt.replace(" ","_");
|
||||
$("#palette_node_"+nodeTypeId).hide();
|
||||
}
|
||||
|
||||
function showNodeType(nt) {
|
||||
var nodeTypeId = nt.replace(" ","_");
|
||||
$("#palette_node_"+nodeTypeId).show();
|
||||
}
|
||||
|
||||
function filterChange() {
|
||||
@@ -164,6 +175,8 @@ RED.palette = (function() {
|
||||
|
||||
return {
|
||||
add:addNodeType,
|
||||
remove:removeNodeType
|
||||
remove:removeNodeType,
|
||||
hide:hideNodeType,
|
||||
show:showNodeType
|
||||
};
|
||||
})();
|
||||
|
@@ -34,6 +34,10 @@ RED.sidebar = (function() {
|
||||
//$('#sidebar').tabs("refresh");
|
||||
}
|
||||
|
||||
function removeTab(title) {
|
||||
sidebar_tabs.removeTab("tab-"+title);
|
||||
}
|
||||
|
||||
var sidebarSeparator = {};
|
||||
$("#sidebar-separator").draggable({
|
||||
axis: "x",
|
||||
@@ -141,6 +145,7 @@ RED.sidebar = (function() {
|
||||
|
||||
return {
|
||||
addTab: addTab,
|
||||
removeTab: removeTab,
|
||||
show: showSidebar,
|
||||
containsTab: containsTab,
|
||||
toggleSidebar: toggleSidebar
|
||||
|
Reference in New Issue
Block a user