From 76728d1783baa9d7aeb625a127f6d3af73fce960 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 15 Jun 2020 22:17:09 +0100 Subject: [PATCH] Move config nodes under type-level hierarchy in outline Also adds user-count label and button to open search --- .../src/js/ui/common/treeList.js | 2 +- .../editor-client/src/js/ui/search.js | 24 +++- .../src/js/ui/tab-info-outliner.js | 128 +++++++++++++++--- 3 files changed, 135 insertions(+), 19 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js index 77a301545..9a3c249e3 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js @@ -360,7 +360,7 @@ } processChildren(item,newItem); - if (!item.deferBuild) { + if (!item.deferBuild && item.treeList.childList) { item.treeList.childList.editableList('insertItemAt',newItem,position) if (select) { setTimeout(function() { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/search.js b/packages/node_modules/@node-red/editor-client/src/js/ui/search.js index 3ac418be9..e595eed18 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/search.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/search.js @@ -79,9 +79,21 @@ RED.search = (function() { return val; } + function extractValue(val, flagName, flags) { + // flagName:XYZ + var regEx = new RegExp("(?:^| )"+flagName+":([^ ]+)(?: |$)"); + var m + while(m = regEx.exec(val)) { + val = val.replace(regEx," ").trim(); + flags[flagName] = flags[flagName] || []; + flags[flagName].push(m[1]); + } + return val; + } + function search(val) { var results = []; - var keys = Object.keys(index); + var keys = []; var typeFilter; var m = /(?:^| )type:([^ ]+)/.exec(val); if (m) { @@ -93,6 +105,8 @@ RED.search = (function() { val = extractFlag(val,"unused",flags); val = extractFlag(val,"config",flags); val = extractFlag(val,"subflow",flags); + // uses: + val = extractValue(val,"uses",flags); var hasFlags = Object.keys(flags).length > 0; @@ -104,6 +118,11 @@ RED.search = (function() { var j; var list = []; var nodes = {}; + if (flags.uses) { + keys = flags.uses; + } else { + keys = Object.keys(index); + } for (i=0;i',{class:"red-ui-info-outline-item-controls red-ui-info-outline-item-hover-controls"}).appendTo(div); + + if (n._def.category === "config" && n.type !== "group") { + var userCountBadge = $('').text(n.users.length).appendTo(controls).on("click",function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + RED.search.show("uses:"+n.id); + }) + RED.popover.tooltip(userCountBadge,function() { return RED._('editor.nodesUse',{count:n.users.length})}); + } + if (n._def.button) { var triggerButton = $('').appendTo(controls).on("click",function(evt) { evt.preventDefault(); @@ -394,19 +409,59 @@ RED.sidebar.info.outliner = (function() { } else { existingObject.element.find(".red-ui-info-outline-item-label").html(" "); } - if (parent !== existingObject.parent.id) { + if (parent !== existingObject.parent.parent.flow) { + var parentItem = existingObject.parent; existingObject.treeList.remove(true); - if (parent === "__global__") { - globalConfigNodes.treeList.addChild(existingObject); - } else { - if (empties[parent]) { - empties[parent].treeList.remove(); - delete empties[parent]; + if (parentItem.children.length === 0) { + if (parentItem.config) { + // this is a config + parentItem.treeList.remove(); + // console.log("Removing",n.type,"from",parentItem.parent.id||parentItem.parent.parent.id) + + delete configNodeTypes[parentItem.parent.id||parentItem.parent.parent.id].types[n.type]; + + + if (parentItem.parent.children.length === 0) { + if (parentItem.parent.id === "__global__") { + parentItem.parent.treeList.addChild(getEmptyItem(parentItem.parent.id)); + } else { + delete configNodeTypes[parentItem.parent.parent.id]; + parentItem.parent.treeList.remove(); + } + } + } else { + parentItem.treeList.addChild(getEmptyItem(parentItem.id)); } - objects[parent].treeList.addChild(existingObject) } + // This must be a config node that has been rescoped + createFlowConfigNode(parent,n.type); + configNodeTypes[parent].types[n.type].treeList.addChild(objects[n.id]); + + // if (parent === "__global__") { + // // Global always exists here + // if (!configNodeTypes[parent][n.type]) { + // configNodeTypes[parent][n.type] = { + // config: true, + // label: n.type, + // children: [] + // } + // globalConfigNodes.treeList.addChild(configNodeTypes[parent][n.type]) + // } + // configNodeTypes[parent][n.type].treeList.addChild(existingObject); + // } else { + // if (empties[parent]) { + // empties[parent].treeList.remove(); + // delete empties[parent]; + // } + // objects[parent].treeList.addChild(existingObject) + // } } existingObject.element.toggleClass("red-ui-info-outline-item-disabled", !!n.d) + + if (n._def.category === "config" && n.type !== 'group') { + existingObject.element.find(".red-ui-info-outline-item-control-users").text(n.users.length); + } + updateSearch(); } function onObjectRemove(n) { @@ -418,10 +473,23 @@ RED.sidebar.info.outliner = (function() { if (empties[n.id]) { delete empties[n.id]; } - var parent = existingObject.parent; if (parent.children.length === 0) { - parent.treeList.addChild(getEmptyItem(parent.id)); + if (parent.config) { + // this is a config + parent.treeList.remove(); + delete configNodeTypes[parent.parent.id||n.z].types[n.type]; + if (parent.parent.children.length === 0) { + if (parent.parent.id === "__global__") { + parent.parent.treeList.addChild(getEmptyItem(parent.parent.id)); + } else { + delete configNodeTypes[n.z]; + parent.parent.treeList.remove(); + } + } + } else { + parent.treeList.addChild(getEmptyItem(parent.id)); + } } } function getGutter(n) { @@ -434,6 +502,35 @@ RED.sidebar.info.outliner = (function() { RED.popover.tooltip(revealButton,RED._("sidebar.info.find")); return span; } + + function createFlowConfigNode(parent,type) { + // console.log("createFlowConfig",parent,type,configNodeTypes[parent]); + if (empties[parent]) { + empties[parent].treeList.remove(); + delete empties[parent]; + } + if (!configNodeTypes[parent]) { + // There is no 'config nodes' item in the parent flow + configNodeTypes[parent] = { + config: true, + flow: parent, + types: {}, + label: RED._("menu.label.displayConfig"), + children: [] + } + objects[parent].treeList.insertChildAt(configNodeTypes[parent],0); + // console.log("CREATED", parent) + } + if (!configNodeTypes[parent].types[type]) { + configNodeTypes[parent].types[type] = { + config: true, + label: type, + children: [] + } + configNodeTypes[parent].treeList.addChild(configNodeTypes[parent].types[type]); + // console.log("CREATED", parent,type) + } + } function onNodeAdd(n) { objects[n.id] = { id: n.id, @@ -449,7 +546,8 @@ RED.sidebar.info.outliner = (function() { } } var parent = n.g||n.z||"__global__"; - if (parent !== "__global__") { + + if (n._def.category !== "config" || n.type === 'group') { if (objects[parent]) { if (empties[parent]) { empties[parent].treeList.remove(); @@ -465,12 +563,8 @@ RED.sidebar.info.outliner = (function() { missingParents[parent].push(objects[n.id]) } } else { - if (empties[parent]) { - empties[parent].treeList.remove(); - delete empties[parent]; - } - // No parent - add to Global flow list - globalConfigNodes.treeList.addChild(objects[n.id]); + createFlowConfigNode(parent,n.type); + configNodeTypes[parent].types[n.type].treeList.addChild(objects[n.id]); } objects[n.id].element.toggleClass("red-ui-info-outline-item-disabled", !!n.d) updateSearch();