Allow config nodes to be scoped to an individual Flow

This commit is contained in:
Nick O'Leary
2015-09-23 22:49:48 +01:00
parent da64c018ac
commit d96b6e77c0
22 changed files with 447 additions and 160 deletions

View File

@@ -189,7 +189,7 @@ RED.history = (function() {
});
if (ev.node.type === 'subflow') {
$("#menu-item-workspace-menu-"+ev.node.id.replace(".","-")).text(ev.node.name);
$("#menu-item-flow-menu-"+ev.node.id.replace(".","-")).text(ev.node.name);
}
RED.palette.refresh();

View File

@@ -152,6 +152,9 @@ var RED = (function() {
statusEnabled = state;
RED.view.status(statusEnabled);
}
function toggleConfigNodes(state) {
RED.workspaces.toggleConfigNodes(state);
}
function loadEditor() {
RED.menu.init({id:"btn-sidemenu",
@@ -161,6 +164,7 @@ var RED = (function() {
null
]},
{id:"menu-item-status",label:RED._("menu.label.displayStatus"),toggle:true,onselect:toggleStatus, selected: true},
{id:"menu-item-config-nodes",label:RED._("menu.label.displayConfig"),toggle:true,onselect:toggleConfigNodes, selected: false},
null,
{id:"menu-item-import",label:RED._("menu.label.import"),options:[
{id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:RED.clipboard.import},
@@ -171,18 +175,18 @@ var RED = (function() {
{id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:RED.library.export}
]},
null,
{id:"menu-item-flow",label:RED._("menu.label.flows"),options:[
{id:"menu-item-flow-add",label:RED._("menu.label.add"),onselect:RED.workspaces.add},
{id:"menu-item-flow-edit",label:RED._("menu.label.rename"),onselect:RED.workspaces.edit},
{id:"menu-item-flow-delete",label:RED._("menu.label.delete"),onselect:RED.workspaces.remove},
null
]},
null,
{id:"menu-item-subflow",label:RED._("menu.label.subflows"), options: [
{id:"menu-item-subflow-create",label:RED._("menu.label.createSubflow"),onselect:RED.subflow.createSubflow},
{id:"menu-item-subflow-convert",label:RED._("menu.label.selectionToSubflow"),disabled:true,onselect:RED.subflow.convertToSubflow},
]},
null,
{id:"menu-item-workspace",label:RED._("menu.label.workspaces"),options:[
{id:"menu-item-workspace-add",label:RED._("menu.label.add"),onselect:RED.workspaces.add},
{id:"menu-item-workspace-edit",label:RED._("menu.label.rename"),onselect:RED.workspaces.edit},
{id:"menu-item-workspace-delete",label:RED._("menu.label.delete"),onselect:RED.workspaces.remove},
null
]},
null,
{id:"menu-item-keyboard-shortcuts",label:RED._("menu.label.keyboardShortcuts"),onselect:RED.keyboard.showHelp},
{id:"menu-item-help",
label: RED.settings.theme("menu.menu-item-help.label","Node-RED Website"),

View File

@@ -156,7 +156,6 @@ RED.nodes = (function() {
}
if (n._def.category == "config") {
configNodes[n.id] = n;
RED.sidebar.config.refresh();
} else {
n.dirty = true;
var updatedConfigNode = false;
@@ -176,7 +175,7 @@ RED.nodes = (function() {
}
}
if (updatedConfigNode) {
RED.sidebar.config.refresh();
// TODO: refresh config tab?
}
if (n._def.category == "subflows" && typeof n.i === "undefined") {
var nextId = 0;
@@ -215,7 +214,7 @@ RED.nodes = (function() {
if (id in configNodes) {
node = configNodes[id];
delete configNodes[id];
RED.sidebar.config.refresh();
RED.workspaces.refresh();
} else {
node = getNode(id);
if (node) {
@@ -245,11 +244,11 @@ RED.nodes = (function() {
}
}
if (updatedConfigNode) {
RED.sidebar.config.refresh();
RED.workspaces.refresh();
}
}
}
if (node._def.onremove) {
if (node && node._def.onremove) {
node._def.onremove.call(n);
}
return {links:removedLinks,nodes:removedNodes};
@@ -273,16 +272,26 @@ RED.nodes = (function() {
var removedNodes = [];
var removedLinks = [];
var n;
var node;
for (n=0;n<nodes.length;n++) {
var node = nodes[n];
node = nodes[n];
if (node.z == id) {
removedNodes.push(node);
}
}
for (n=0;n<removedNodes.length;n++) {
var rmlinks = removeNode(removedNodes[n].id);
removedLinks = removedLinks.concat(rmlinks);
for(n in configNodes) {
if (configNodes.hasOwnProperty(n)) {
node = configNodes[n];
if (node.z == id) {
removedNodes.push(node);
}
}
}
for (n=0;n<removedNodes.length;n++) {
var result = removeNode(removedNodes[n].id);
removedLinks = removedLinks.concat(result.links);
}
console.log(removedLinks);
return {nodes:removedNodes,links:removedLinks};
}
@@ -382,6 +391,7 @@ RED.nodes = (function() {
var node = {};
node.id = n.id;
node.type = n.type;
node.z = n.z;
if (node.type == "unknown") {
for (var p in n._orig) {
if (n._orig.hasOwnProperty(p)) {
@@ -417,7 +427,6 @@ RED.nodes = (function() {
if (n._def.category != "config") {
node.x = n.x;
node.y = n.y;
node.z = n.z;
node.wires = [];
for(var i=0;i<n.outputs;i++) {
node.wires.push([]);
@@ -690,7 +699,7 @@ RED.nodes = (function() {
if (def && def.category == "config") {
var existingConfigNode = RED.nodes.node(n.id);
if (!existingConfigNode || !compareNodes(existingConfigNode,n) || existingConfigNode._def.exclusive) {
var configNode = {id:n.id,type:n.type,users:[]};
var configNode = {id:n.id, z:n.z, type:n.type, users:[]};
for (var d in def.defaults) {
if (def.defaults.hasOwnProperty(d)) {
configNode[d] = n[d];
@@ -846,6 +855,7 @@ RED.nodes = (function() {
});
}
RED.workspaces.refresh();
return [new_nodes,new_links,new_workspaces,new_subflows];
}
@@ -947,6 +957,13 @@ RED.nodes = (function() {
}
}
},
eachWorkspace: function(cb) {
for (var id in workspaces) {
if (workspaces.hasOwnProperty(id)) {
cb(workspaces[id]);
}
}
},
node: getNode,

View File

@@ -103,7 +103,7 @@ RED.deploy = (function() {
],
create: function() {
$("#node-dialog-confirm-deploy").parent().find("div.ui-dialog-buttonpane")
.append('<div style="height:0; vertical-align: middle; display:inline-block;">'+
.prepend('<div style="height:0; vertical-align: middle; display:inline-block; margin-top: 13px; float:left;">'+
'<input style="vertical-align:top;" type="checkbox" id="node-dialog-confirm-deploy-hide">'+
'<label style="display:inline;" for="node-dialog-confirm-deploy-hide"> do not warn about this again</label>'+
'<input type="hidden" id="node-dialog-confirm-deploy-type">'+

View File

@@ -391,7 +391,7 @@ RED.editor = (function() {
if (editing_node) {
RED.sidebar.info.refresh(editing_node);
}
RED.sidebar.config.refresh();
RED.workspaces.refresh();
var buttons = $( this ).dialog("option","buttons");
if (buttons.length == 3) {
@@ -671,12 +671,18 @@ RED.editor = (function() {
ns = node_def.set.id;
}
var activeWorkspace = RED.nodes.workspace(RED.workspaces.active());
if (!activeWorkspace) {
activeWorkspace = RED.nodes.subflow(RED.workspaces.active());
}
if (configNode == null) {
configNode = {
id: (1+Math.random()*4294967295).toString(16),
_def: node_def,
type: type
type: type,
z: activeWorkspace.id,
users: []
}
for (var d in node_def.defaults) {
if (node_def.defaults[d].value) {
@@ -710,7 +716,7 @@ RED.editor = (function() {
buttons = buttons.splice(1);
}
buttons[0].text = "Add";
$("#node-config-dialog-user-count").html("").hide();
$("#node-config-dialog-user-count").find("span").html("").parent().hide();
} else {
if (buttons.length == 2) {
buttons.unshift({
@@ -747,8 +753,60 @@ RED.editor = (function() {
});
}
buttons[1].text = "Update";
$("#node-config-dialog-user-count").html(RED._("editor.nodesUse", {count:configNode.users.length})).show();
$("#node-config-dialog-user-count").find("span").html(RED._("editor.nodesUse", {count:configNode.users.length})).parent().show();
}
if (configNode._def.exclusive) {
$("#node-config-dialog-scope").hide();
} else {
$("#node-config-dialog-scope").show();
}
$("#node-config-dialog-scope-warning").hide();
var nodeUserFlows = {};
configNode.users.forEach(function(n) {
nodeUserFlows[n.z] = true;
});
var flowCount = Object.keys(nodeUserFlows).length;
var tabSelect = $("#node-config-dialog-scope").empty();
tabSelect.off("change");
tabSelect.append('<option value=""'+(!configNode.z?" selected":"")+' data-i18n="workspace.config.global"></option>');
tabSelect.append('<option disabled>flows</option>');
RED.nodes.eachWorkspace(function(ws) {
var workspaceLabel = ws.label;
if (nodeUserFlows[ws.id]) {
workspaceLabel = "* "+workspaceLabel;
}
tabSelect.append('<option value="'+ws.id+'"'+(ws.id==configNode.z?" selected":"")+'>'+workspaceLabel+'</option>');
});
tabSelect.append('<option disabled>subflows</option>');
RED.nodes.eachSubflow(function(ws) {
var workspaceLabel = ws.name;
if (nodeUserFlows[ws.id]) {
workspaceLabel = "* "+workspaceLabel;
}
tabSelect.append('<option value="'+ws.id+'"'+(ws.id==configNode.z?" selected":"")+'>'+workspaceLabel+'</option>');
});
if (flowCount > 0) {
tabSelect.on('change',function() {
var newScope = $(this).val();
if (newScope === '') {
// global scope - everyone can use it
$("#node-config-dialog-scope-warning").hide();
} else if (!nodeUserFlows[newScope] || flowCount > 1) {
// a user will loose access to it
$("#node-config-dialog-scope-warning").show();
} else {
$("#node-config-dialog-scope-warning").hide();
}
});
}
//tabSelect.append('<option value="'+activeWorkspace.id+'"'+(activeWorkspace.id==configNode.z?" selected":"")+'>'+workspaceLabel+'</option>');
tabSelect.i18n();
$( "#node-config-dialog" ).dialog("option","buttons",buttons);
$("#node-config-dialog").i18n();
@@ -776,17 +834,39 @@ RED.editor = (function() {
var select = $("#node-input-"+name);
var node_def = RED.nodes.getType(type);
select.children().remove();
var activeWorkspace = RED.nodes.workspace(RED.workspaces.active());
if (!activeWorkspace) {
activeWorkspace = RED.nodes.subflow(RED.workspaces.active());
}
var configNodes = [];
RED.nodes.eachConfig(function(config) {
if (config.type == type) {
if (config.type == type && (!config.z || config.z === activeWorkspace.id)) {
var label = "";
if (typeof node_def.label == "function") {
label = node_def.label.call(config);
} else {
label = node_def.label;
}
select.append('<option value="'+config.id+'"'+(value==config.id?" selected":"")+'>'+label+'</option>');
configNodes.push({id:config.id,label:label});
}
});
configNodes.sort(function(A,B) {
if (A.label < B.label) {
return -1;
} else if (A.label > B.label) {
return 1;
}
return 0;
});
configNodes.forEach(function(cn) {
select.append('<option value="'+cn.id+'"'+(value==cn.id?" selected":"")+'>'+cn.label+'</option>');
});
select.append('<option value="_ADD_"'+(value===""?" selected":"")+'>'+RED._("editor.addNewType", {type:type})+'</option>');
window.setTimeout(function() { select.change();},50);
}
@@ -813,7 +893,7 @@ RED.editor = (function() {
var configNode;
var d;
var input;
var scope = $("#node-config-dialog-scope").val();
if (configAdding) {
configNode = {type:configType,id:configId,users:[]};
for (d in configTypeDef.defaults) {
@@ -828,6 +908,7 @@ RED.editor = (function() {
}
configNode.label = configTypeDef.label;
configNode._def = configTypeDef;
configNode.z = scope;
RED.nodes.add(configNode);
updateConfigNodeSelect(configProperty,configType,configNode.id);
} else {
@@ -842,6 +923,26 @@ RED.editor = (function() {
}
}
}
if (scope) {
configNode.users = configNode.users.filter(function(n) {
var keep = true;
for (var d in n._def.defaults) {
if (n._def.defaults.hasOwnProperty(d)) {
if (n._def.defaults[d].type === configNode.type &&
n[d] === configNode.id &&
n.z !== scope) {
keep = false;
n[d] = null;
n.dirty = true;
n.changed = true;
validateNode(n);
}
}
}
return keep;
});
}
configNode.z = scope;
updateConfigNodeSelect(configProperty,configType,configId);
}
if (configTypeDef.credentials) {
@@ -857,6 +958,7 @@ RED.editor = (function() {
}
RED.nodes.dirty(true);
RED.view.redraw(true);
$(this).dialog("close");
}
@@ -903,7 +1005,16 @@ RED.editor = (function() {
if (RED.view.state() != RED.state.EDITING) {
RED.keyboard.enable();
}
RED.sidebar.config.refresh();
RED.workspaces.refresh();
},
create: function() {
$("#node-config-dialog").parent().find("div.ui-dialog-buttonpane")
.prepend('<div id="node-config-dialog-user-count"><i class="fa fa-info-circle"></i> <span></span></div>');
$("#node-config-dialog").parent().find('.ui-dialog-titlebar').append('<span id="node-config-dialog-scope-container"><span id="node-config-dialog-scope-warning" data-i18n="[title]editor.errors.scopeChange"><i class="fa fa-warning"></i></span><select id="node-config-dialog-scope"></select></span>');
$("#node-config-dialog").parent().draggable({
cancel: '.ui-dialog-content, .ui-dialog-titlebar-close, #node-config-dialog-scope-container'
});
}
});
}
@@ -933,7 +1044,7 @@ RED.editor = (function() {
changes['name'] = editing_node.name;
editing_node.name = newName;
changed = true;
$("#menu-item-workspace-menu-"+editing_node.id.replace(".","-")).text(newName);
$("#menu-item-flow-menu-"+editing_node.id.replace(".","-")).text(newName);
}
RED.palette.refresh();
@@ -996,6 +1107,7 @@ RED.editor = (function() {
RED.view.state(RED.state.DEFAULT);
}
RED.sidebar.info.refresh(editing_node);
RED.workspaces.refresh();
editing_node = null;
}
});

View File

@@ -61,7 +61,7 @@ RED.palette = (function() {
}
function setLabel(type, el,label) {
var nodeWidth = 80;
var nodeWidth = 82;
var nodeHeight = 25;
var lineHeight = 20;
var portHeight = 10;

View File

@@ -188,7 +188,6 @@ RED.sidebar = (function() {
RED.keyboard.add(/* SPACE */ 32,{ctrl:true},function(){RED.menu.setSelected("menu-item-sidebar",!RED.menu.isSelected("menu-item-sidebar"));d3.event.preventDefault();});
showSidebar();
RED.sidebar.info.init();
RED.sidebar.config.init();
// hide info bar at start if screen rather narrow...
if ($(window).width() < 600) { toggleSidebar(); }
}

View File

@@ -1,92 +0,0 @@
/**
* Copyright 2013 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
RED.sidebar.config = (function() {
var content = document.createElement("div");
content.style.paddingTop = "4px";
content.style.paddingLeft = "4px";
content.style.paddingRight = "4px";
var list = $("<ul>",{class:"tab-config-list"}).appendTo(content);
function init() {
RED.sidebar.addTab({
id: "config",
label: RED._("sidebar.config.label"),
name: RED._("sidebar.config.name"),
content: content,
closeable: true,
visible: false,
onchange: function() { refresh(); }
});
}
function show() {
refresh();
RED.sidebar.show("config");
}
function refresh() {
list.empty();
RED.nodes.eachConfig(function(node) {
var li = list.find("#tab-config-list-type-"+node.type);
if (li.length === 0) {
li = $("<li>",{id:"tab-config-list-type-"+node.type}).appendTo(list);
$('<div class="tab-config-list-type">'+node.type+'</div>').appendTo(li);
}
var label = "";
if (typeof node._def.label == "function") {
label = node._def.label.call(node);
} else {
label = node._def.label;
}
label = label || "&nbsp;";
var entry = $('<div class="tab-config-list-entry"></div>').appendTo(li);
entry.on('dblclick',function(e) {
RED.editor.editConfig("", node.type, node.id);
});
var userArray = node.users.map(function(n) { return n.id });
entry.on('mouseover',function(e) {
RED.nodes.eachNode(function(node) {
if( userArray.indexOf(node.id) != -1) {
node.highlighted = true;
node.dirty = true;
}
});
RED.view.redraw();
});
entry.on('mouseout',function(e) {
RED.nodes.eachNode(function(node) {
if(node.highlighted) {
node.highlighted = false;
node.dirty = true;
}
});
RED.view.redraw();
});
$('<div class="tab-config-list-label">'+label+'</div>').appendTo(entry);
$('<div class="tab-config-list-users">'+node.users.length+'</div>').appendTo(entry);
});
}
return {
init:init,
show:show,
refresh:refresh
}
})();

View File

@@ -256,8 +256,8 @@ RED.view = (function() {
activeSubflow = RED.nodes.subflow(event.workspace);
RED.menu.setDisabled("menu-item-workspace-edit", activeSubflow);
RED.menu.setDisabled("menu-item-workspace-delete",RED.workspaces.count() == 1 || activeSubflow);
RED.menu.setDisabled("menu-item-flow-edit", activeSubflow);
RED.menu.setDisabled("menu-item-flow-delete",RED.workspaces.count() == 1 || activeSubflow);
if (workspaceScrollPositions[event.workspace]) {
chart.scrollLeft(workspaceScrollPositions[event.workspace].left);
@@ -407,8 +407,8 @@ RED.view = (function() {
lasso = vis.append('rect')
.attr("ox",point[0])
.attr("oy",point[1])
.attr("rx",2)
.attr("ry",2)
.attr("rx",1)
.attr("ry",1)
.attr("x",point[0])
.attr("y",point[1])
.attr("width",0)
@@ -1370,14 +1370,7 @@ RED.view = (function() {
var statusLabel = status.append("svg:text")
.attr("class","node_status_label")
.attr('x',20).attr('y',9)
.style({
'stroke-width': 0,
'fill': '#888',
'font-size':'9pt',
'stroke':'#000',
'text-anchor':'start'
});
.attr('x',20).attr('y',9);
//node.append("circle").attr({"class":"centerDot","cx":0,"cy":0,"r":5});
@@ -1802,7 +1795,6 @@ RED.view = (function() {
if (updateActive) {
updateActiveNodes();
}
RED.workspaces.refresh();
redraw();
},
focus: focusView,

View File

@@ -90,6 +90,7 @@ RED.workspaces = (function() {
activeWorkspace = tab.id;
event.workspace = activeWorkspace;
RED.events.emit("workspace:change",event);
refreshConfigNodeList();
},
ondblclick: function(tab) {
if (tab.type != "subflow") {
@@ -99,18 +100,18 @@ RED.workspaces = (function() {
}
},
onadd: function(tab) {
RED.menu.addItem("menu-item-workspace",{
id:"menu-item-workspace-menu-"+tab.id.replace(".","-"),
RED.menu.addItem("menu-item-flow",{
id:"menu-item-flow-menu-"+tab.id.replace(".","-"),
label:tab.label,
onselect:function() {
workspace_tabs.activateTab(tab.id);
}
});
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
RED.menu.setDisabled("menu-item-flow-delete",workspace_tabs.count() == 1);
},
onremove: function(tab) {
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
RED.menu.removeItem("menu-item-workspace-menu-"+tab.id.replace(".","-"));
RED.menu.setDisabled("menu-item-flow-delete",workspace_tabs.count() == 1);
RED.menu.removeItem("menu-item-flow-menu-"+tab.id.replace(".","-"));
},
minimumActiveTabWidth: 150
});
@@ -140,7 +141,7 @@ RED.workspaces = (function() {
if (workspace.label != label) {
workspace_tabs.renameTab(workspace.id,label);
RED.nodes.dirty(true);
$("#menu-item-workspace-menu-"+workspace.id.replace(".","-")).text(label);
$("#menu-item-flow-menu-"+workspace.id.replace(".","-")).text(label);
// TODO: update entry in menu
}
$( this ).dialog( "close" );
@@ -196,7 +197,19 @@ RED.workspaces = (function() {
$('#btn-workspace-add-tab').on("click",function(e) {addWorkspace(); e.preventDefault()});
RED.events.on("sidebar:resize",workspace_tabs.resize);
RED.menu.setAction('menu-item-workspace-delete',function() {
$(".workspace-config-node-tray-header").on('click', function(e) {
var icon = $(this).find("i");
if (icon.hasClass("expanded")) {
icon.removeClass("expanded");
$(this).next().slideUp();
} else {
icon.addClass("expanded");
$(this).next().slideDown();
}
});
RED.menu.setAction('menu-item-flow-delete',function() {
deleteWorkspace(RED.nodes.workspace(activeWorkspace));
});
@@ -214,6 +227,84 @@ RED.workspaces = (function() {
}
}
}
function createConfigNodeList(nodes,list) {
nodes.sort(function(A,B) {
if (A.type < B.type) { return -1;}
if (A.type > B.type) { return 1;}
return 0;
});
list.empty();
if (nodes.length === 0) {
$('<li class="config_node_none">none</li>').appendTo(list);
} else {
var currentType = "";
nodes.forEach(function(node) {
var label = "";
if (typeof node._def.label == "function") {
label = node._def.label.call(node);
} else {
label = node._def.label;
}
label = label || node.id;
if (node.type != currentType) {
$('<li class="config_node_type">'+node.type+'</li>').appendTo(list);
currentType = node.type;
}
var entry = $('<li class="palette_node config_node"></li>').appendTo(list);
$('<div class="palette_label"></div>').text(label).appendTo(entry);
var iconContainer = $('<div/>',{class:"palette_icon_container palette_icon_container_right"}).text(node.users.length).appendTo(entry);
if (node.users.length === 0) {
entry.addClass("config_node_unused");
}
entry.on('click',function(e) {
RED.sidebar.info.refresh(node);
});
entry.on('dblclick',function(e) {
RED.editor.editConfig("", node.type, node.id);
});
var userArray = node.users.map(function(n) { return n.id });
entry.on('mouseover',function(e) {
RED.nodes.eachNode(function(node) {
if( userArray.indexOf(node.id) != -1) {
node.highlighted = true;
node.dirty = true;
}
});
RED.view.redraw();
});
entry.on('mouseout',function(e) {
RED.nodes.eachNode(function(node) {
if(node.highlighted) {
node.highlighted = false;
node.dirty = true;
}
});
RED.view.redraw();
});
});
}
}
function refreshConfigNodeList() {
var localConfigNodes = [];
var globalConfigNodes = [];
RED.nodes.eachConfig(function(cn) {
if (cn.z == activeWorkspace) {
localConfigNodes.push(cn);
} else if (!cn.z) {
globalConfigNodes.push(cn);
}
});
createConfigNodeList(localConfigNodes,$("#workspace-config-node-tray-locals"));
createConfigNodeList(globalConfigNodes,$("#workspace-config-node-tray-globals"));
}
return {
init: init,
add: addWorkspace,
@@ -246,9 +337,14 @@ RED.workspaces = (function() {
workspace_tabs.renameTab(sf.id,sf.name);
}
});
refreshConfigNodeList();
},
resize: function() {
workspace_tabs.resize();
},
toggleConfigNodes: function(state) {
refreshConfigNodeList();
$("#workspace").toggleClass("config-open",state);
}
}
})();