You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ea...@apache.org on 2016/03/29 16:43:17 UTC
qpid-dispatch git commit: DISPATCH-201 Updates for dispatch 0.6.0
Repository: qpid-dispatch
Updated Branches:
refs/heads/master 8475aca8f -> 96ce4a6c8
DISPATCH-201 Updates for dispatch 0.6.0
Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/96ce4a6c
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/96ce4a6c
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/96ce4a6c
Branch: refs/heads/master
Commit: 96ce4a6c869c7caa1d8d762c9227da23fb98ca04
Parents: 8475aca
Author: Ernest Allen <ea...@redhat.com>
Authored: Tue Mar 29 10:42:05 2016 -0400
Committer: Ernest Allen <ea...@redhat.com>
Committed: Tue Mar 29 10:42:05 2016 -0400
----------------------------------------------------------------------
.../src/main/webapp/plugin/css/brokers.ttf | Bin 0 -> 2272 bytes
.../src/main/webapp/plugin/css/plugin.css | 106 +++-
.../src/main/webapp/plugin/css/qdrTopology.css | 76 ++-
.../src/main/webapp/plugin/html/qdrList.html | 54 +-
.../main/webapp/plugin/html/qdrOverview.html | 2 +-
.../main/webapp/plugin/html/qdrTopology.html | 16 +-
.../src/main/webapp/plugin/js/dispatchPlugin.js | 21 +-
.../hawtio/src/main/webapp/plugin/js/navbar.js | 4 +-
.../hawtio/src/main/webapp/plugin/js/qdrList.js | 260 ++++++++--
.../src/main/webapp/plugin/js/qdrOverview.js | 54 +-
.../src/main/webapp/plugin/js/qdrService.js | 208 +++++---
.../src/main/webapp/plugin/js/qdrTopology.js | 492 ++++++++++++-------
12 files changed, 979 insertions(+), 314 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/96ce4a6c/console/hawtio/src/main/webapp/plugin/css/brokers.ttf
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/css/brokers.ttf b/console/hawtio/src/main/webapp/plugin/css/brokers.ttf
new file mode 100644
index 0000000..ae83968
Binary files /dev/null and b/console/hawtio/src/main/webapp/plugin/css/brokers.ttf differ
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/96ce4a6c/console/hawtio/src/main/webapp/plugin/css/plugin.css
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/css/plugin.css b/console/hawtio/src/main/webapp/plugin/css/plugin.css
index c6f5cc1..889bf72 100644
--- a/console/hawtio/src/main/webapp/plugin/css/plugin.css
+++ b/console/hawtio/src/main/webapp/plugin/css/plugin.css
@@ -279,10 +279,13 @@ div.qdrList li.active, ul.qdrListNodes li.active {
div.qdr-attributes span.dynatree-selected a {
background-color: #e0e0ff;
}
-div.qdr-attributes.pane {
+div.qdr-attributes.pane, div.qdr-topology.pane {
position: absolute;
margin-left: 10px;
}
+div.qdr-topology.pane.left {
+ width: auto;
+}
/* the selected row in the name table */
div#main.qdr div.qdrList div.selected {
@@ -428,8 +431,8 @@ ul.qdrTopoModes {
background:#e0e0ff;
}
-.qdr-overview.pane.left, .qdr-attributes.pane.left {
- top: 100px;
+.qdr-overview.pane.left, .qdr-attributes.pane.left, .qdr-topology.pane.left {
+ top: 104px;
}
.qdr-overview.pane.left {
left: 10px;
@@ -723,3 +726,100 @@ span:not(.dynatree-has-children).allocator .dynatree-icon:before {
.changed {
color: #339933;
}
+
+div.dispatch-router div.help {
+ width: auto;
+ padding: 1em;
+ background-color: lavender;
+ border-radius: 6px;
+ margin-top: 1em;
+ text-align: center;
+}
+
+div.operations tr:nth-child(even) {
+ background: #f3f3f3;
+}
+div.operations tr:nth-child(odd), div.operations tr:last-child {
+ background: #fff;
+}
+
+div.operations tr input {
+ margin: 0;
+ padding: 3px 6px;
+}
+div.operations table {
+ width: 100%;
+}
+div.operations th {
+ width: 50%;
+ border-bottom: 1px solid #cccccc;
+ text-align: left;
+}
+div.operations td:nth-child(odd), div.operations th:nth-child(odd) {
+ border-right: 1px solid #cccccc;
+}
+div.operations td:nth-child(odd) {
+ padding-left: 0;
+}
+div.operations td:nth-child(even), div.operations th:nth-child(even) {
+ padding-left: 5px;
+}
+div.operations th {
+ padding: 5px;
+}
+div.operations .tab-pane.active {
+ padding: 12px 12px 12px 0;
+}
+div.operations label {
+ padding-top: 4px;
+ margin-bottom: 4px;
+}
+.qdrListActions .ngGrid {
+ /*min-height: 40em;
+ height: 100%; */
+}
+div.qdrListActions .ngViewport {
+ height: initial !important;
+}
+
+div.operations .boolean {
+ padding-bottom: 0;
+}
+
+table.log-entry {
+ margin-bottom: 1em;
+ border-top: 1px solid black;
+}
+
+table.log-entry pre {
+ background-color: #f5f5f5;
+ color: inherit;
+ margin: 0;
+}
+
+circle.node.normal.console {
+ fill: lightcyan;
+}
+
+text.console, text.on-demand, text.normal {
+ font-family: FontAwesome;
+ font-weight: normal;
+ font-size: 16px;
+}
+
+@font-face {
+ font-family:"Brokers";
+ src: url("brokers.ttf") /* TTF file for CSS3 browsers */
+}
+
+text.artemis.on-demand {
+ font-family: Brokers;
+ font-size: 20px;
+ font-weight: bold;
+}
+
+text.qpid-cpp.on-demand {
+ font-family: Brokers;
+ font-size: 18px;
+ font-weight: bold;
+}
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/96ce4a6c/console/hawtio/src/main/webapp/plugin/css/qdrTopology.css
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/css/qdrTopology.css b/console/hawtio/src/main/webapp/plugin/css/qdrTopology.css
index 0eac80d..bc7ccfc 100644
--- a/console/hawtio/src/main/webapp/plugin/css/qdrTopology.css
+++ b/console/hawtio/src/main/webapp/plugin/css/qdrTopology.css
@@ -97,7 +97,11 @@ circle.node.normal {
fill: #F0F000;
}
circle.node.on-demand {
- fill: #00F000;
+ fill: #C0FFC0;
+}
+circle.node.on-demand.artemis {
+ fill: #FCC;
+ /*opacity: 0.2; */
}
circle.node.fixed {
@@ -148,6 +152,11 @@ text.id {
font-weight: bold;
}
+text.label {
+ text-anchor: start;
+ font-weight: bold;
+}
+
.row-fluid.tertiary {
position: relative;
left: 20px;
@@ -159,7 +168,26 @@ text.id {
.row-fluid.tertiary.panel {
width: 410px;
- height: 100%;
+ /*height: 100%; */
+}
+
+/*, div.qdrTopology div#multiple_details .ngViewport*/
+div#topologyForm .ngViewport, div#topologyForm .gridStyle {
+ height: inherit !important;
+ min-height: initial !important;
+ overflow: initial;
+}
+
+div#multiple_details {
+ height: 300px;
+ width: 500px;
+ display: none;
+ padding: 1em;
+ border: 1px solid;
+ position: absolute;
+ background-color: white;
+ max-height: 330px !important;
+ overflow: hidden;
}
.panel-adjacent {
@@ -170,10 +198,13 @@ text.id {
border: 1px solid red;
}
#topologyForm {
- border: 1px solid white;
- padding: 2px;
- position: relative;
- top: -8px;
+ border: 1px solid white;
+ padding: 2px;
+ /* position: relative; */
+ /* top: -8px; */
+}
+div.qdr-topology.pane.left .ngViewport {
+ /* border: 1px solid lightgray; */
}
#topologyForm > div {
@@ -479,6 +510,13 @@ div.boolean {
stroke-width: 3px;
}
+circle.subcircle {
+ stroke-width: 1px;
+ /* stroke-dasharray: 2; */
+ fill-opacity: 0;
+ stroke: black;
+}
+
.leaf circle {
fill: #6fa8dc;
fill-opacity: 0.95;
@@ -490,6 +528,28 @@ div.boolean {
}
-.qdrListActions .ngGrid {
- height: 100vh;
+#svg_legend {
+ position: absolute;
+ top: 110px;
+ right: 0;
+ border: 1px solid #ccc;
+ border-radius: 5px;
+ background-color: #fcfcfc;
+ margin-right: 1.3em;
+ padding: 1em;
+}
+
+#svg_legend svg {
+ height: 235px;
+ width: 180px;
+}
+
+#multiple_details div.gridStyle {
+/* height: 50em; */
+ min-height: 70px !important;
+ height: auto !important;
+}
+
+#multiple_details .ngViewport {
+ height: auto !important;
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/96ce4a6c/console/hawtio/src/main/webapp/plugin/html/qdrList.html
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrList.html b/console/hawtio/src/main/webapp/plugin/html/qdrList.html
index adb249f..d07d3ca 100644
--- a/console/hawtio/src/main/webapp/plugin/html/qdrList.html
+++ b/console/hawtio/src/main/webapp/plugin/html/qdrList.html
@@ -26,12 +26,60 @@ under the License.
</div>
</hawtio-pane>
<div class="row-fluid qdrListActions">
+ <ul class="nav nav-tabs">
+ <li ng-repeat="mode in modes" ng-show="isValid(mode)" ng-click="selectMode(mode)" ng-class="{active : isModeSelected(mode)}" title="{{mode.title}}" ng-bind-html-unsafe="mode.content"> </li>
+ </ul>
<h4>{{selectedRecordName}}</h4>
<div ng-show="currentMode.id === 'attributes'" class="selectedItems">
- <div ng-grid="details"></div>
+ <div ng-show="selectedRecordName === selectedEntity" class="no-content">There are no {{selectedEntity}}s</div>
+ <div ng-hide="selectedRecordName === selectedEntity" ng-grid="details"></div>
</div>
- <div ng-show="currentMode.id === 'operations'">
- Operations are not implemented yet.
+ <div class="operations" ng-show="currentMode.id === 'operations'">
+ <!-- <div ng-grid="detailsCREATE"></div> -->
+ <fieldset ng-show="operation != ''">
+ <table>
+ <tr>
+ <th>Attribute</th>
+ <th>Value</th>
+ </tr>
+ <tr title="{{attribute.title}}" ng-repeat="attribute in detailFields">
+ <td><label for="{{attribute.name}}">{{attribute.name | humanify}}</label></td>
+ <!-- we can't do <input type="{angular expression}"> because... jquery throws an exception because... -->
+ <td>
+ <div ng-if="attribute.input == 'input'">
+ <!-- ng-pattern="testPattern(attribute)" -->
+ <input ng-if="attribute.type == 'number'" type="number" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.rawValue" ng-required="attribute.required" class="ui-widget-content ui-corner-all"/>
+ <input ng-if="attribute.type == 'text'" type="text" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.attributeValue" ng-required="attribute.required" class="ui-widget-content ui-corner-all"/>
+ <span ng-if="attribute.type == 'disabled'" >{{getAttributeValue(attribute)}}</span>
+ </div>
+ <div ng-if="attribute.input == 'select'">
+ <select id="{{attribute.name}}" ng-model="attribute.selected" ng-options="item for item in attribute.rawtype track by item"></select>
+ </div>
+ <div ng-if="attribute.input == 'boolean'" class="boolean">
+ <label><input type="radio" ng-model="attribute.rawValue" ng-value="true"> True</label>
+ <label><input type="radio" ng-model="attribute.rawValue" ng-value="false"> False</label>
+ </div>
+ </td>
+ </tr>
+ <tr><td></td><td><button class="btn btn-primary" type="button" ng-click="ok()">{{operation | Pascalcase}}</button></td></tr>
+ </table>
+ </fieldset>
+ </div>
+ <div ng-show="currentMode.id === 'log'">
+ <table class="log-entry" ng-repeat="entry in logResults track by $index">
+ <tr>
+ <td align="left" colspan="2">{{entry.time}}</td>
+ </tr>
+ <tr>
+ <td>Type</td><td>{{entry.type}}</td>
+ </tr>
+ <tr>
+ <td>Source</td><td>{{entry.source}}:{{entry.line}}</td>
+ </tr>
+ <tr>
+ <td valign="middle">Message</td><td valign="middle"><pre>{{entry.message}}</pre></td>
+ </tr>
+ </table>
</div>
</div>
</div>
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/96ce4a6c/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html b/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html
index 61d5143..2a66a94 100644
--- a/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html
+++ b/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html
@@ -47,7 +47,7 @@ under the License.
<script type="text/ng-template" id="router.html">
<div class="row-fluid">
- <h3>Router {{router.data.title}}</h3>
+ <h3>Router {{router.data.title}} attributes</h3>
<div class="gridStyle noHighlight" ng-grid="routerGrid"></div>
</div>
</script>
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/96ce4a6c/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html b/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html
index 704c8e2..61ca2c1 100644
--- a/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html
+++ b/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html
@@ -17,19 +17,18 @@ specific language governing permissions and limitations
under the License.
-->
<div class="qdrTopology row-fluid" ng-controller="QDR.TopologyController">
- <div class="tertiary left panel">
+ <div class="qdr-topology pane left" ng-controller="QDR.TopologyFormController">
<div id="topologyForm" ng-class="{selected : isSelected()}">
<!-- <div ng-repeat="form in forms" ng-show="isVisible(form)" ng-class='{selected : isSelected(form)}'> -->
-
- <div ng-show="isGeneral()">
+ <div ng-show="form == 'router'">
<h4>Router Info</h4>
<div class="gridStyle" ng-grid="topoGridOptions"></div>
</div>
- <div ng-show="isConnections()">
+ <div ng-show="form == 'connection'">
<h4>Connection Info</h4>
- <div class="gridStyle" ng-grid="topoConnOptions"></div>
+ <div class="gridStyle" ng-grid="topoGridOptions"></div>
</div>
- <div id="addNodeForm" ng-show="isAddNode()">
+ <div id="addNodeForm" ng-show="form == 'add'">
<h4>Add a new router</h4>
<ul>
<li>Click on an existing router to create a connection to the new router</li>
@@ -71,7 +70,10 @@ under the License.
<li ng-click="removeLink()">Remove connection</li>
</ul>
</div>
-
+ <div id="svg_legend"></div>
+ <div id="multiple_details">
+ <div class="gridStyle" ng-grid="multiDetails"></div>
+ </div>
</div>
</div>
<!--
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/96ce4a6c/console/hawtio/src/main/webapp/plugin/js/dispatchPlugin.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/dispatchPlugin.js b/console/hawtio/src/main/webapp/plugin/js/dispatchPlugin.js
index 59ea4d3..5061317 100644
--- a/console/hawtio/src/main/webapp/plugin/js/dispatchPlugin.js
+++ b/console/hawtio/src/main/webapp/plugin/js/dispatchPlugin.js
@@ -88,10 +88,12 @@ var QDR = (function(QDR) {
$compileProvider.urlSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|blob):/);
cur = $compileProvider.urlSanitizationWhitelist();
})
+
.config(function (JSONFormatterConfigProvider) {
// Enable the hover preview feature
JSONFormatterConfigProvider.hoverPreviewEnabled = true;
})
+
.filter('to_trusted', function($sce){
return function(text) {
return $sce.trustAsHtml(text);
@@ -107,7 +109,15 @@ var QDR = (function(QDR) {
var nameParts = name.split('/')
return nameParts.length > 1 ? nameParts[nameParts.length-1] : name;
};
- });
+ })
+ .filter('Pascalcase', function () {
+ return function (str) {
+ if (!str)
+ return "";
+ return str.replace(/(\w)(\w*)/g,
+ function(g0,g1,g2){return g1.toUpperCase() + g2.toLowerCase();});
+ }
+ })
/*
QDR.module.config(['$locationProvider', function($locationProvider) {
$locationProvider.html5Mode(true);
@@ -134,6 +144,7 @@ var QDR = (function(QDR) {
Core.addCSS("https://cdn.rawgit.com/mohsen1/json-formatter/master/dist/json-formatter.min.css");
Core.addCSS("https://cdnjs.cloudflare.com/ajax/libs/jquery.tipsy/1.0.2/jquery.tipsy.css");
Core.addCSS("https://code.jquery.com/ui/1.8.24/themes/base/jquery-ui.css");
+ Core.addCSS("https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css");
// tell hawtio that we have our own custom layout for
// our view
@@ -217,16 +228,14 @@ var QDR = (function(QDR) {
})(QDR || {});
-
-// tell the hawtio plugin loader about our plugin so it can be
-// bootstrapped with the rest of angular
-hawtioPluginLoader.addModule(QDR.pluginName);
-
$.getScript('https://cdn.rawgit.com/angular-ui/ui-slider/master/src/slider.js', function() {
hawtioPluginLoader.addModule('ui.slider');
});
$.getScript('https://cdn.rawgit.com/mohsen1/json-formatter/master/dist/json-formatter.min.js', function() {
hawtioPluginLoader.addModule('jsonFormatter');
+ // tell the hawtio plugin loader about our plugin so it can be
+ // bootstrapped with the rest of angular
+ hawtioPluginLoader.addModule(QDR.pluginName);
});
// force an more modern version of d3 to load
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/96ce4a6c/console/hawtio/src/main/webapp/plugin/js/navbar.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/navbar.js b/console/hawtio/src/main/webapp/plugin/js/navbar.js
index d305f38..8cfecdf 100644
--- a/console/hawtio/src/main/webapp/plugin/js/navbar.js
+++ b/console/hawtio/src/main/webapp/plugin/js/navbar.js
@@ -43,8 +43,8 @@ var QDR = (function (QDR) {
href: "#/dispatch_plugin/overview"
},
{
- content: '<i class="icon-list "></i> Details',
- title: "View the attributes of the router nodes",
+ content: '<i class="icon-list "></i> Entities',
+ title: "View the attributes of the router entities",
isValid: function (QDRService) { return QDRService.isConnected(); },
href: "#/dispatch_plugin/list"
},
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/96ce4a6c/console/hawtio/src/main/webapp/plugin/js/qdrList.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrList.js b/console/hawtio/src/main/webapp/plugin/js/qdrList.js
index 72fbc04..d816521 100644
--- a/console/hawtio/src/main/webapp/plugin/js/qdrList.js
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrList.js
@@ -28,9 +28,10 @@ var QDR = (function(QDR) {
*
* Controller for the main interface
*/
- QDR.module.controller("QDR.ListController", ['$scope', '$location', '$dialog', 'localStorage', 'QDRService', 'QDRChartService',
- function ($scope, $location, $dialog, localStorage, QDRService, QDRChartService) {
+ QDR.module.controller("QDR.ListController", ['$scope', '$location', '$dialog', '$filter', 'localStorage', 'QDRService', 'QDRChartService',
+ function ($scope, $location, $dialog, $filter, localStorage, QDRService, QDRChartService) {
+ $scope.details = [];
if (!QDRService.connected) {
// we are not connected. we probably got here from a bookmark or manual page reload
$location.path("/dispatch_plugin/connect")
@@ -43,6 +44,75 @@ var QDR = (function(QDR) {
$scope.selectedNodeId = localStorage['QDRSelectedNodeId'];
$scope.selectedRecordName = localStorage['QDRSelectedRecordName'];
+ $scope.modes = [{
+ content: '<a><i class="icon-list"></i> Attriutes</a>',
+ id: 'attributes',
+ op: 'READ',
+ title: "View router attributes",
+ isValid: function () { return true; }
+ },
+ {
+ content: '<a><i class="icon-edit"></i> Update</a>',
+ id: 'operations',
+ op: 'UPDATE',
+ title: "Update this attribute",
+ isValid: function () { return $scope.operations.indexOf(this.op) > -1 }
+ },
+ {
+ content: '<a><i class="icon-plus"></i> Create</a>',
+ id: 'operations',
+ op: 'CREATE',
+ title: "Create a new attribute",
+ isValid: function () { return $scope.operations.indexOf(this.op) > -1 }
+ },
+ {
+ content: '<a><i class="icon-chart"></i> Chart</a>',
+ id: 'charts',
+ op: 'graph',
+ title: "Graph attributes",
+ isValid: function () { return false; return $scope.detailFields.some( function (field ) {
+ return field.graph;
+ })}
+ },
+ {
+ content: '<a><i class="icon-eye-open"></i> Fetch</a>',
+ id: 'log',
+ op: 'GET-LOG',
+ title: "Fetch recent log entries",
+ isValid: function () { return ($scope.selectedEntity === 'log') }
+ }
+ ];
+ $scope.operations = []
+ $scope.currentMode = $scope.modes[0];
+ $scope.isModeSelected = function (mode) {
+ return mode === $scope.currentMode;
+ }
+ $scope.selectMode = function (mode) {
+ $scope.currentMode = mode;
+ if (mode.id === 'log') {
+ $scope.logResults = "getting recent log entries...";
+ QDRService.sendMethod($scope.currentNode.id, $scope.selectedEntity, {}, $scope.currentMode.op, function (nodeName, entity, response, context) {
+ $scope.logResults = response.filter( function (entry) {
+ return entry[0] === $scope.detailsObject.module
+ }).sort( function (a, b) {
+ return b[5] - a[5]
+ }).map( function (entry) {
+ return {
+ type: entry[1],
+ message: entry[2],
+ source: entry[3],
+ line: entry[4],
+ time: Date(entry[5]).toString()
+ }
+ })
+ $scope.$apply();
+ })
+ }
+ }
+ $scope.isValid = function (mode) {
+ return mode.isValid()
+ }
+
$scope.nodes = QDRService.nodeList().sort(function (a, b) { return a.name.toLowerCase() > b.name.toLowerCase()});
if (!angular.isDefined($scope.selectedNode)) {
//QDR.log.debug("selectedNode was " + $scope.selectedNode);
@@ -69,33 +139,20 @@ var QDR = (function(QDR) {
return row.linkType.value;
}
}
- $scope.modes = [
- {
- content: '<a><i class="icon-list"></i> Attriutes</a>',
- id: 'attributes',
- title: "View router attributes",
- isValid: function () { return true; }
- },
- {
- content: '<a><i class="icon-leaf"></i> Operations</a>',
- id: 'operations',
- title: "Execute operations",
- isValid: function () { return true; }
- }
- ];
- $scope.currentMode = $scope.modes[0];
- $scope.isModeSelected = function (mode) {
- return mode === $scope.currentMode;
- }
- $scope.selectMode = function (mode) {
- $scope.currentMode = mode;
+
+ var lookupOperations = function () {
+ var ops = QDRService.schema.entityTypes[$scope.selectedEntity].operations.filter( function (op) { return op !== 'READ'});
+ $scope.operation = ops.length ? ops[0] : "";
+ return ops;
}
var entityTreeChildren = [];
- for (var entity in QDRService.schema.entityTypes) {
+ var sortedEntities = Object.keys(QDRService.schema.entityTypes).sort();
+ sortedEntities.forEach( function (entity) {
if (excludedEntities.indexOf(entity) == -1) {
if (!angular.isDefined($scope.selectedEntity)) {
$scope.selectedEntity = entity;
+ $scope.operations = lookupOperations()
}
var current = entity === $scope.selectedEntity;
var e = new Folder(entity)
@@ -106,7 +163,7 @@ var QDR = (function(QDR) {
e.children = [placeHolder]
entityTreeChildren.push(e)
}
- }
+ })
$scope.treeReady = function () {
$('#entityTree').dynatree({
onActivate: onTreeSelected,
@@ -123,10 +180,16 @@ var QDR = (function(QDR) {
}
// a tree node was selected
var onTreeSelected = function (selectedNode) {
+ if ($scope.currentMode.id === 'operations')
+ $scope.currentMode = $scope.modes[0];
+ else if ($scope.currentMode.id === 'log')
+ $scope.selectMode($scope.currentMode)
if (selectedNode.data.typeName === "entity") {
$scope.selectedEntity = selectedNode.data.key;
+ $scope.operations = lookupOperations()
} else if (selectedNode.data.typeName === 'attribute') {
$scope.selectedEntity = selectedNode.parent.data.key;
+ $scope.operations = lookupOperations()
$scope.selectedRecordName = selectedNode.data.key;
updateDetails(selectedNode.data.details);
$("#entityTree").dynatree("getRoot").visit(function(node){
@@ -136,6 +199,28 @@ var QDR = (function(QDR) {
}
$scope.$apply();
}
+ // fill in an empty results recoord based on the entities schema
+ var fromSchema = function (entityName) {
+ var row = {}
+ var schemaEntity = QDRService.schema.entityTypes[entityName]
+ for (attr in schemaEntity.attributes) {
+ var entity = schemaEntity.attributes[attr]
+ row[attr] = {
+ value: "",
+ type: entity.type,
+ graph: false,
+ title: entity.description,
+ aggregate: false,
+ aggregateTip: ''
+ }
+ }
+ return row;
+ }
+ $scope.hasCreate = function () {
+ var schemaEntity = QDRService.schema.entityTypes[$scope.selectedEntity]
+ return (schemaEntity.operations.indexOf("CREATE") > -1)
+ }
+
// the data for the selected entity is available, populate the tree
var updateEntityChildren = function (tableRows, expand) {
var tree = $("#entityTree").dynatree("getTree");
@@ -148,8 +233,8 @@ var QDR = (function(QDR) {
typeName: "none",
title: "no data"
})
- $scope.selectedRecordName = "";
- updateDetails({});
+ $scope.selectedRecordName = $scope.selectedEntity;
+ updateDetails(fromSchema($scope.selectedEntity));
} else {
tableRows.forEach( function (row) {
var addClass = $scope.selectedEntity;
@@ -184,24 +269,85 @@ var QDR = (function(QDR) {
}
}
+ var schemaProps = function (entityName, key, currentNode) {
+ var typeMap = {integer: 'number', string: 'text', path: 'text', boolean: 'boolean'};
+
+ var entity = QDRService.schema.entityTypes[entityName]
+ var value = entity.attributes[key]
+ // skip identity and depricated fields
+ if (!value)
+ return {input: 'input', type: 'disabled', required: false, selected: "", rawtype: 'string', disabled: true, 'default': ''}
+ var description = value.description || ""
+ var val = value['default'];
+ var disabled = (key == 'identity' || description.startsWith('Deprecated'))
+ // special cases
+ if (entityName == 'log' && key == 'module') {
+ return {input: 'input', type: 'disabled', required: false, selected: "", rawtype: 'string', disabled: true, 'default': ''}
+ }
+ if (entityName === 'linkRoutePattern' && key === 'connector') {
+ // turn input into a select. the values will be populated later
+ value.type = []
+ // find all the connector names and populate the select
+ QDRService.getNodeInfo(currentNode.id, '.connector', ['name'], function (nodeName, dotentity, response) {
+ $scope.detailFields.some( function (field) {
+ if (field.name === 'connector') {
+ field.rawtype = response.results.map (function (result) {return result[0]})
+ return true;
+ }
+ })
+ });
+ }
+ return { name: key,
+ humanName: QDRService.humanify(key),
+ description:value.description,
+ type: disabled ? 'disabled' : typeMap[value.type],
+ rawtype: value.type,
+ input: typeof value.type == 'string' ? value.type == 'boolean' ? 'boolean' : 'input'
+ : 'select',
+ selected: val ? val : undefined,
+ 'default': value['default'],
+ value: val,
+ required: value.required,
+ unique: value.unique,
+ disabled: disabled
+ };
+ }
+ $scope.getAttributeValue = function (attribute) {
+ var value = attribute.attributeValue;
+ if ($scope.currentMode.op === "CREATE" && attribute.name === 'identity')
+ value = "<assigned by system>"
+ return value;
+ }
var updateDetails = function (row) {
var details = [];
- for (var attr in row) {
+ $scope.detailsObject = {};
+ var attrs = Object.keys(row).sort();
+ attrs.forEach( function (attr) {
var changed = $scope.detailFields.filter(function (old) {
return (old.name === attr) ? old.graph && old.rawValue != row[attr].value : false;
})
+ var schemaEntity = schemaProps($scope.selectedEntity, attr, $scope.currentNode)
details.push( {
attributeName: QDRService.humanify(attr),
- attributeValue: QDRService.pretty(row[attr].value),
+ attributeValue: attr === 'port' ? row[attr].value : QDRService.pretty(row[attr].value),
name: attr,
changed: changed.length,
rawValue: row[attr].value,
graph: row[attr].graph,
title: row[attr].title,
aggregateValue: QDRService.pretty(row[attr].aggregate),
- aggregateTip: row[attr].aggregateTip
+ aggregateTip: row[attr].aggregateTip,
+
+ input: schemaEntity.input,
+ type: schemaEntity.type,
+ required: schemaEntity.required,
+ selected: schemaEntity.selected,
+ rawtype: schemaEntity.rawtype,
+ disabled: schemaEntity.disabled,
+ 'default': schemaEntity['default']
})
- }
+ $scope.detailsObject[attr] = row[attr].value;
+ })
$scope.detailFields = details;
aggregateColumn();
$scope.$apply();
@@ -224,6 +370,7 @@ var QDR = (function(QDR) {
if (newValue !== oldValue) {
localStorage['QDRSelectedEntity'] = $scope.selectedEntity;
restartUpdate();
+ $scope.operations = lookupOperations()
}
})
$scope.$watch('selectedNode', function(newValue, oldValue) {
@@ -241,14 +388,19 @@ var QDR = (function(QDR) {
$scope.tableRows = [];
var selectedRowIndex = 0;
var updateTableData = function (entity, expand) {
+ // don't update the data when on the operations tab
+ if ($scope.currentMode.id === 'operations') {
+ return;
+ }
+
var gotNodeInfo = function (nodeName, dotentity, response) {
//QDR.log.debug("got results for " + nodeName);
//console.dump(response);
-
var records = response.results;
var aggregates = response.aggregates;
var attributeNames = response.attributeNames;
var nameIndex = attributeNames.indexOf("name");
+ var identityIndex = attributeNames.indexOf("identity");
var ent = QDRService.schema.entityTypes[entity];
var tableRows = [];
for (var i=0; i<records.length; ++i) {
@@ -258,7 +410,11 @@ var QDR = (function(QDR) {
var rowName;
if (nameIndex > -1) {
rowName = record[nameIndex];
- } else {
+ if (!rowName && identityIndex > -1) {
+ rowName = record[nameIndex] = (dotentity + '/' + record[identityIndex])
+ }
+ }
+ if (!rowName) {
QDR.log.error("response attributeNames did not contain a name field");
console.dump(response.attributeNames);
return;
@@ -290,15 +446,15 @@ var QDR = (function(QDR) {
}
tableRows.push(row);
}
+ tableRows.sort( function (a, b) { return a.name.value.localeCompare(b.name.value) })
setTimeout(selectRow, 0, {rows: tableRows, expand: expand});
}
-
// if this entity should show an aggregate column, send the request to get the info for this entity from all the nedes
if (aggregateEntities.indexOf(entity) > -1) {
var nodeInfo = QDRService.topology.nodeInfo();
QDRService.getMultipleNodeInfo(Object.keys(nodeInfo), entity, [], gotNodeInfo, $scope.selectedNodeId);
} else {
- QDRService.getNodeInfo($scope.selectedNodeId, '.' + entity, [], gotNodeInfo);
+ QDRService.getNodeInfo($scope.selectedNodeId, entity, [], gotNodeInfo);
}
};
@@ -420,7 +576,6 @@ var QDR = (function(QDR) {
return false;
}
};
-
updateTableData($scope.selectedEntity, true);
stop = setInterval(updateTableData, 5000, $scope.selectedEntity);
@@ -432,6 +587,41 @@ var QDR = (function(QDR) {
};
});
+ function gotMethodResponse (nodeName, entity, response, context) {
+ var statusCode = context.message.application_properties.statusCode;
+ if (statusCode < 200 || statusCode >= 300) {
+ Core.notification('error', context.message.application_properties.statusDescription);
+ QDR.log.debug(context.message.application_properties.statusDescription)
+ } else {
+ var note = entity + " " + $filter('Pascalcase')($scope.currentMode.op) + "d"
+ QDR.log.info(note)
+ Core.notification('success', note);
+ $scope.selectMode($scope.modes[0]);
+ $scope.$apply();
+ }
+ }
+ $scope.ok = function () {
+ var attributes = {}
+ $scope.detailFields.forEach( function (field) {
+ var value = field.rawValue;
+ if (field.input === 'input') {
+ if (field.type === 'text' || field.type === 'disabled')
+ value = field.attributeValue;
+ }
+ if (field.input === 'select')
+ value = field.selected;
+
+ if (value != field['default'] || field.required || (field.name === 'role')) {
+ if (field.name !== 'identity')
+ attributes[field.name] = value
+ }
+ if (!attributes.type)
+ attributes.type = $scope.selectedEntity;
+
+ })
+ QDRService.sendMethod($scope.currentNode.id, $scope.selectedEntity, attributes, $scope.currentMode.op, gotMethodResponse)
+ }
+
function doDialog(template, chart) {
var d = $dialog.dialog({
backdrop: true,
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/96ce4a6c/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js b/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js
index cc52868..bf75ffd 100644
--- a/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js
@@ -44,7 +44,31 @@ var QDR = (function (QDR) {
$location.path("/dispatch_plugin/connect")
return;
}
-
+ // we want attributes to be listed first, so add it at index 0
+ $scope.subLevelTabs = [{
+ content: '<i class="icon-list"></i> Attributes',
+ title: "View the attribute values on your selection",
+ isValid: function (workspace) { return true; },
+ href: function () { return "#/dispatch-plugin/attributes"; },
+ index: 0
+ },
+ {
+ content: '<i class="icon-leaf"></i> Operations',
+ title: "Execute operations on your selection",
+ isValid: function (workspace) { return true; },
+ href: function () { return "#/dispatch-plugin/operations"; },
+ index: 1
+ }]
+ $scope.activeTab = $scope.subLevelTabs[0];
+ $scope.setActive = function (nav) {
+ $scope.activeTab = nav;
+ }
+ $scope.isValid = function (nav) {
+ return nav.isValid()
+ }
+ $scope.isActive = function (nav) {
+ return nav == $scope.activeTab;
+ }
var nodeIds = QDRService.nodeIdList();
var currentTimer;
var refreshInterval = 5000
@@ -141,7 +165,28 @@ var QDR = (function (QDR) {
if (expected == received) {
allRouterFields.sort ( function (a,b) { return a.routerId < b.routerId ? -1 : a.routerId > b.routerId ? 1 : 0})
// now get each router's node info
- QDRService.getMultipleNodeInfo(nodeIds, "router", [], function (nodeIds, entity, response) {
+ QDRService.getMultipleNodeInfo(nodeIds, "router", [], function (nodeIds, entity, responses) {
+ for(var r in responses) {
+ var result = responses[r]
+ var routerId = QDRService.valFor(result.attributeNames, result.results[0], "routerId")
+ allRouterFields.some( function (connField) {
+ if (routerId === connField.routerId) {
+ result.attributeNames.forEach ( function (attrName) {
+ connField[attrName] = QDRService.valFor(result.attributeNames, result.results[0], attrName)
+ })
+ return true
+ }
+ return false
+ })
+ }
+ $scope.allRouterFields = allRouterFields
+ $scope.$apply()
+ if (currentTimer) {
+ clearTimeout(currentTimer)
+ }
+ currentTimer = setTimeout(allRouterInfo, refreshInterval);
+/*
+
var results = response.aggregates
results.forEach ( function (result) {
@@ -162,10 +207,11 @@ var QDR = (function (QDR) {
clearTimeout(currentTimer)
}
currentTimer = setTimeout(allRouterInfo, refreshInterval);
- }, nodeIds[0])
+*/
+ }, nodeIds[0], false)
}
}
- nodeIds.forEach ( function (nodeId) {
+ nodeIds.forEach ( function (nodeId, i) {
QDRService.getNodeInfo(nodeId, ".connection", ["role"], gotNodeInfo)
})
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/96ce4a6c/console/hawtio/src/main/webapp/plugin/js/qdrService.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrService.js b/console/hawtio/src/main/webapp/plugin/js/qdrService.js
index 06bf113..aebb71b 100644
--- a/console/hawtio/src/main/webapp/plugin/js/qdrService.js
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrService.js
@@ -143,7 +143,7 @@ var QDR = (function(QDR) {
// called by receiver's on('message') handler when a response arrives
resolve: function(context) {
var correlationID = context.message.properties.correlation_id;
- this._objects[correlationID].resolver(context.message.body);
+ this._objects[correlationID].resolver(context.message.body, context);
delete this._objects[correlationID];
}
},
@@ -247,6 +247,14 @@ var QDR = (function(QDR) {
return null;
},
+ isArtemis: function (d) {
+ return d.nodeType ==='on-demand' && !d.properties.product;
+ },
+
+ isQpid: function (d) {
+ return d.nodeType ==='on-demand' && (d.properties && d.properties.product === 'qpid-cpp');
+ },
+
/*
* send the management messages that build up the topology
*
@@ -482,74 +490,81 @@ The response looks like:
}, ret.error);
},
- getMultipleNodeInfo: function (nodeNames, entity, attrs, callback, selectedNodeId) {
+ getMultipleNodeInfo: function (nodeNames, entity, attrs, callback, selectedNodeId, aggregate) {
+ if (!angular.isDefined(aggregate))
+ aggregate = true;
var responses = {};
var gotNodesResult = function (nodeName, dotentity, response) {
responses[nodeName] = response;
if (Object.keys(responses).length == nodeNames.length) {
- aggregateNodeInfo(nodeNames, entity, responses, callback);
+ if (aggregate)
+ self.aggregateNodeInfo(nodeNames, entity, selectedNodeId, responses, callback);
+ else {
+ callback(nodeNames, entity, responses)
+ }
}
}
- var aggregateNodeInfo = function (nodeNames, entity, responses, callback) {
- //QDR.log.debug("got all results for " + entity);
- // aggregate the responses
- var newResponse = {};
- var thisNode = responses[selectedNodeId];
- newResponse['attributeNames'] = thisNode.attributeNames;
- newResponse['results'] = thisNode.results;
- newResponse['aggregates'] = [];
- for (var i=0; i<thisNode.results.length; ++i) {
- var result = thisNode.results[i];
- var vals = [];
- result.forEach( function (val) {
- vals.push({sum: val, detail: []})
- })
- newResponse.aggregates.push(vals);
- }
- var nameIndex = thisNode.attributeNames.indexOf("name");
- var ent = self.schema.entityTypes[entity];
- var ids = Object.keys(responses);
- ids.sort();
- ids.forEach( function (id) {
- var response = responses[id];
- var results = response.results;
- results.forEach( function (result) {
- // find the matching result in the aggregates
- var found = newResponse.aggregates.some( function (aggregate, j) {
- if (aggregate[nameIndex].sum === result[nameIndex]) {
- // result and aggregate are now the same record, add the graphable values
- newResponse.attributeNames.forEach( function (key, i) {
- if (ent.attributes[key] && ent.attributes[key].graph) {
- if (id != selectedNodeId)
- aggregate[i].sum += result[i];
- aggregate[i].detail.push({node: self.nameFromId(id)+':', val: result[i]})
- }
- })
- return true; // stop looping
- }
- return false; // continute looking for the aggregate record
- })
- if (!found) {
- // this attribute was not found in the aggregates yet
- // because it was not in the selectedNodeId's results
- var vals = [];
- result.forEach( function (val) {
- vals.push({sum: val, detail: []})
- })
- newResponse.aggregates.push(vals)
- }
- })
- })
- callback(nodeNames, entity, newResponse);
- }
-
nodeNames.forEach( function (id) {
self.getNodeInfo(id, '.'+entity, attrs, gotNodesResult);
})
//TODO: implement a timeout in case not all requests complete
},
+ aggregateNodeInfo: function (nodeNames, entity, selectedNodeId, responses, callback) {
+ //QDR.log.debug("got all results for " + entity);
+ // aggregate the responses
+ var newResponse = {};
+ var thisNode = responses[selectedNodeId];
+ newResponse['attributeNames'] = thisNode.attributeNames;
+ newResponse['results'] = thisNode.results;
+ newResponse['aggregates'] = [];
+ for (var i=0; i<thisNode.results.length; ++i) {
+ var result = thisNode.results[i];
+ var vals = [];
+ result.forEach( function (val) {
+ vals.push({sum: val, detail: []})
+ })
+ newResponse.aggregates.push(vals);
+ }
+ var nameIndex = thisNode.attributeNames.indexOf("name");
+ var ent = self.schema.entityTypes[entity];
+ var ids = Object.keys(responses);
+ ids.sort();
+ ids.forEach( function (id) {
+ var response = responses[id];
+ var results = response.results;
+ results.forEach( function (result) {
+ // find the matching result in the aggregates
+ var found = newResponse.aggregates.some( function (aggregate, j) {
+ if (aggregate[nameIndex].sum === result[nameIndex]) {
+ // result and aggregate are now the same record, add the graphable values
+ newResponse.attributeNames.forEach( function (key, i) {
+ if (ent.attributes[key] && ent.attributes[key].graph) {
+ if (id != selectedNodeId)
+ aggregate[i].sum += result[i];
+ aggregate[i].detail.push({node: self.nameFromId(id)+':', val: result[i]})
+ }
+ })
+ return true; // stop looping
+ }
+ return false; // continute looking for the aggregate record
+ })
+ if (!found) {
+ // this attribute was not found in the aggregates yet
+ // because it was not in the selectedNodeId's results
+ var vals = [];
+ result.forEach( function (val) {
+ vals.push({sum: val, detail: []})
+ })
+ newResponse.aggregates.push(vals)
+ }
+ })
+ })
+ callback(nodeNames, entity, newResponse);
+ },
+
+
getSchema: function () {
//QDR.log.debug("getting schema");
var ret;
@@ -564,13 +579,74 @@ The response looks like:
}, ret.error);
},
- sendQuery: function(toAddr, entity, attrs) {
+ getNodeInfo: function (nodeName, entity, attrs, callback) {
+ //QDR.log.debug("getNodeInfo called with nodeName: " + nodeName + " and entity " + entity);
+ var ret;
+ self.correlator.request(
+ ret = self.sendQuery(nodeName, entity, attrs)
+ ).then(ret.id, function(response) {
+ callback(nodeName, entity, response);
+ //self.topology.addNodeInfo(nodeName, entity, response);
+ //self.topology.cleanUp(response);
+ }, ret.error);
+ },
+
+ sendMethod: function (nodeId, entity, attrs, operation, callback) {
+ var ret;
+ self.correlator.request(
+ ret = self._sendMethod(nodeId, entity, attrs, operation)
+ ).then(ret.id, function (response, context) {
+ callback(nodeId, entity, response, context);
+ }, ret.error);
+ },
+
+ _fullAddr: function (toAddr) {
var toAddrParts = toAddr.split('/');
if (toAddrParts.shift() != "amqp:") {
self.topology.error(Error("unexpected format for router address: " + toAddr));
return;
}
- var fullAddr = self.toAddress + "/" + toAddrParts.join('/');
+ //var fullAddr = self.toAddress + "/" + toAddrParts.join('/');
+ var fullAddr = toAddrParts.join('/');
+ return fullAddr;
+ },
+
+ _sendMethod: function (toAddr, entity, attrs, operation) {
+ var fullAddr = self._fullAddr(toAddr);
+ var ret = {id: self.correlator.corr()};
+ if (!self.sender || !self.sendable) {
+ ret.error = "no sender"
+ return ret;
+ }
+ try {
+ var application_properties = {
+ operation: operation
+ }
+ if (attrs.type)
+ application_properties.type = attrs.type;
+ if (attrs.name)
+ application_properties.name = attrs.name;
+ self.sender.send({
+ body: attrs,
+ properties: {
+ to: fullAddr,
+ reply_to: self.receiver.remote.attach.source.address,
+ correlation_id: ret.id
+ },
+ application_properties: application_properties
+ })
+ }
+ catch (e) {
+ error = "error sending: " + e;
+ QDR.log.error(error)
+ ret.error = error;
+ }
+ return ret;
+ },
+
+ sendQuery: function(toAddr, entity, attrs, operation) {
+ operation = operation || "QUERY"
+ var fullAddr = self._fullAddr(toAddr);
var body;
if (attrs)
@@ -581,13 +657,14 @@ The response looks like:
body = {
"attributeNames": [],
}
-
- return self._send(body, fullAddr, "QUERY", "org.apache.qpid.dispatch" + entity);
+ if (entity[0] === '.')
+ entity = entity.substr(1, entity.length-1)
+ //return self._send(body, fullAddr, operation, entity);
+ return self._send(body, fullAddr, operation, "org.apache.qpid.dispatch." + entity);
},
sendMgmtQuery: function (operation) {
- // TODO: file bug against dispatch - We should be able to just pass body: [], but that generates an 'invalid body'
- return self._send([' '], self.toAddress + "/$management", operation);
+ return self._send([], "/$management", operation);
},
_send: function (body, to, operation, entityType) {
@@ -649,7 +726,6 @@ The response looks like:
self.receiver = null;
self.sendable = false;
}
-
var maybeStart = function () {
if (okay.connection && okay.sender && okay.receiver && self.sendable && !self.connected) {
QDR.log.info("okay to start")
@@ -662,7 +738,7 @@ The response looks like:
}
}
var onDisconnect = function () {
- QDR.log.warn("Disconnected");
+ //QDR.log.warn("Disconnected");
stop();
self.executeDisconnectActions();
}
@@ -690,7 +766,7 @@ The response looks like:
self.errorText = "Disconnected"
})
- var sender = connection.open_sender("/$management");
+ var sender = connection.open_sender();
sender.on('sender_open', function (context) {
QDR.log.debug("sender_opened")
okay.sender = true
@@ -724,7 +800,7 @@ The response looks like:
(function() {
console.dump = function(object) {
if (window.JSON && window.JSON.stringify)
- console.log(JSON.stringify(object));
+ console.log(JSON.stringify(object,undefined,2));
else
console.log(object);
};
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/96ce4a6c/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js b/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js
index ff5b696..a59c8d3 100644
--- a/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js
@@ -21,6 +21,44 @@ under the License.
*/
var QDR = (function (QDR) {
+
+ QDR.module.controller('QDR.TopologyFormController', function ($scope, QDRService) {
+
+ $scope.attributes = []
+ var generalCellTemplate = '<div class="ngCellText"><span title="{{row.entity.description}}">{{row.entity.attributeName}}</span></div>';
+ $scope.topoGridOptions = {
+ data: 'attributes',
+ enableColumnResize: true,
+ multiSelect: false,
+ columnDefs: [
+ {
+ field: 'attributeName',
+ displayName: 'Attribute',
+ cellTemplate: generalCellTemplate
+ },
+ {
+ field: 'attributeValue',
+ displayName: 'Value'
+ }
+ ]
+ };
+ $scope.form = ''
+ $scope.$on('showEntityForm', function (event, args) {
+ var attributes = args.attributes;
+ var entityTypes = QDRService.schema.entityTypes[args.entity].attributes;
+ Object.keys(attributes).forEach( function (attr) {
+ if (entityTypes[attr])
+ attributes[attr].description = entityTypes[attr]
+ })
+ $scope.attributes = attributes;
+ $scope.form = args.entity;
+ })
+ $scope.$on('showAddForm', function (event) {
+ $scope.form = 'add';
+ })
+ })
+
+
/**
* @method TopologyController
*
@@ -38,37 +76,11 @@ var QDR = (function (QDR) {
QDR.log.debug("started QDR.TopologyController with urlPrefix: " + $location.absUrl());
var urlPrefix = $location.absUrl();
- $scope.attributes = [];
- $scope.connAttributes = [];
- $scope.topoForm = "general";
- $scope.topoFormSelected = "";
$scope.addingNode = {
step: 0,
hasLink: false,
trigger: ''
- }; // shared object about the node that is be $scope.topoForm = "general";
-
- var generalCellTemplate = '<div class="ngCellText"><span title="{{row.entity.description}}">{{row.entity.attributeName}}</span></div>';
-
- $scope.isGeneral = function () {
- //QDR.log.debug("$scope.topoForm=" + $scope.topoForm)
- return $scope.topoForm === 'general';
- };
- $scope.isConnections = function () {
- //QDR.log.debug("$scope.topoForm=" + $scope.topoForm)
- return $scope.topoForm === 'connections';
};
- $scope.isAddNode = function () {
- //QDR.log.debug("$scope.topoForm=" + $scope.topoForm)
- return $scope.topoForm === 'addNode';
- }
-
- $scope.getTableHeight = function (rows) {
- return {height: (rows.length * 30) + "px"};
- }
- $scope.isSelected = function () {
- return ($scope.topoFormSelected != "");
- }
$scope.cancel = function () {
$scope.addingNode.step = 0;
@@ -77,24 +89,6 @@ var QDR = (function (QDR) {
$scope.addingNode.trigger = 'editNode';
}
- $scope.topoGridOptions = {
- data: 'attributes',
- enableColumnResize: true,
- multiSelect: false,
- columnDefs: [
- {
- field: 'attributeName',
- displayName: 'Attribute',
- cellTemplate: generalCellTemplate
- },
- {
- field: 'attributeValue',
- displayName: 'Value'
- }
- ]
- };
- $scope.topoConnOptions = angular.copy($scope.topoGridOptions);
- $scope.topoConnOptions.data = 'connAttributes';
var NewRouterName = "__NEW__";
// mouse event vars
var selected_node = null,
@@ -122,16 +116,12 @@ var QDR = (function (QDR) {
if (name == "Add Router") {
name = 'Diagram';
if ($scope.addingNode.step > 0) {
- $scope.topoForm = 'general'
- $scope.topoFormSelected = '';
$scope.addingNode.step = 0;
} else {
// start adding node mode
$scope.addingNode.step = 1;
}
} else {
- $scope.topoForm = 'general'
- $scope.topoFormSelected = '';
$scope.addingNode.step = 0;
}
@@ -160,12 +150,11 @@ var QDR = (function (QDR) {
}
return true;
})
- $scope.topoForm = 'general'
- $scope.topoFormSelected = '';
+ updateForm(Object.keys(QDRService.topology.nodeInfo())[0], 'router', 0);
+
} else if (newValue > 0) {
// we are starting the add mode
- $scope.topoForm = 'addNode';
- $scope.topoFormSelected = 'addNode';
+ $scope.$broadcast('showAddForm')
resetMouseVars();
selected_node = null;
@@ -190,6 +179,29 @@ var QDR = (function (QDR) {
return mode.right;
}
+ // for ng-grid that shows details for multiple consoles/clients
+ $scope.multiData = [{name: ''}, {name: ''}, {name: ''}]
+ $scope.multiDetails = {
+ data: 'multiData',
+ columnDefs: [
+ {
+ field: 'host',
+ displayName: 'Host'
+ },
+ {
+ field: 'user',
+ displayName: 'User'
+ },
+ {
+ field: 'properties',
+ displayName: 'Properties'
+ },
+ {
+ field: 'isEncrypted',
+ displayName: 'Encrypted'
+ }
+ ]
+ };
// generate unique name for router and containerName
var genNewName = function () {
@@ -283,9 +295,9 @@ var QDR = (function (QDR) {
var radius = 25;
var radiusNormal = 15;
width = tpdiv.width() - gap;
- height = $(document).height() - gap;
+ height = $('#main').height() - $('#topology').position().top - gap;
- var svg;
+ var svg, lsvg;
var force;
var animate = false; // should the force graph organize itself when it is displayed
var path, circle;
@@ -299,7 +311,8 @@ var QDR = (function (QDR) {
var nodes = [];
var links = [];
- var aNode = function (id, name, nodeType, nodeInfo, nodeIndex, x, y, resultIndex, fixed) {
+ var aNode = function (id, name, nodeType, nodeInfo, nodeIndex, x, y, resultIndex, fixed, properties) {
+ properties = properties || {};
var containerName;
if (nodeInfo) {
var node = nodeInfo[id];
@@ -310,6 +323,7 @@ var QDR = (function (QDR) {
return { key: id,
name: name,
nodeType: nodeType,
+ properties: properties,
containerName: containerName,
x: x,
y: y,
@@ -340,8 +354,6 @@ var QDR = (function (QDR) {
}
}
- //var drag;
- // create an bare svg element and
// initialize the nodes and links array from the QDRService.topology._nodeInfo object
var initForceGraph = function () {
//QDR.log.debug("initForceGraph called");
@@ -370,6 +382,20 @@ var QDR = (function (QDR) {
removeCrosssection()
});
+ $(document).keyup(function(e) {
+ if (e.keyCode === 27) {
+ removeCrosssection()
+ }
+ });
+
+ // the legend
+ lsvg = d3.select("#svg_legend")
+ .append('svg')
+ .attr('id', 'svglegend')
+ lsvg = lsvg.append('svg:g')
+ .attr('transform', 'translate('+(radii['inter-router']+2)+','+(radii['inter-router']+2)+')')
+ .selectAll('g');
+
// mouse event vars
selected_node = null;
selected_link = null;
@@ -388,11 +414,11 @@ var QDR = (function (QDR) {
if (!angular.isDefined(position)) {
animate = true;
position = {x: width / 4 + ((width / 2)/nodeCount) * nodes.length,
- y: height / 2 + yInit,
+ y: 200 + yInit,
fixed: false};
}
if (position.y > height)
- position.y = height / 2 - yInit;
+ position.y = 200 - yInit;
nodes.push( aNode(id, name, "inter-router", nodeInfo, nodes.length, position.x, position.y, undefined, position.fixed) );
yInit *= -1;
//QDR.log.debug("adding node " + nodes.length-1);
@@ -405,9 +431,13 @@ var QDR = (function (QDR) {
var onode = nodeInfo[id];
var conns = onode['.connection'].results;
var attrs = onode['.connection'].attributeNames;
+ var parent = getNodeIndex(QDRService.nameFromId(id));
+ //QDR.log.debug("external client parent is " + parent);
+ var normalsParent = {console: undefined, client: undefined}; // 1st normal node for this parent
for (var j = 0; j < conns.length; j++) {
var role = QDRService.valFor(attrs, conns[j], "role");
+ var properties = QDRService.valFor(attrs, conns[j], "properties") || {};
var dir = QDRService.valFor(attrs, conns[j], "dir");
if (role == "inter-router") {
var connId = QDRService.valFor(attrs, conns[j], "container");
@@ -419,8 +449,6 @@ var QDR = (function (QDR) {
//QDR.log.debug("found an external client for " + id);
var name = QDRService.nameFromId(id) + "." + client;
//QDR.log.debug("external client name is " + name + " and the role is " + role);
- var parent = getNodeIndex(QDRService.nameFromId(id));
- //QDR.log.debug("external client parent is " + parent);
// if we have any new clients, animate the force graph to position them
var position = angular.fromJson(localStorage[name]);
@@ -432,26 +460,36 @@ var QDR = (function (QDR) {
}
if (position.y > height)
position.y = nodes[parent].y + 40 + Math.cos(Math.PI/2 * client)
- //QDR.log.debug("adding node " + nodeIndex);
- nodes.push( aNode(id, name, role, nodeInfo, nodes.length, position.x, position.y, j, position.fixed) );
- // now add a link
- getLink(parent, nodes.length-1, dir);
- client++;
+ var node = aNode(id, name, role, nodeInfo, nodes.length, position.x, position.y, j, position.fixed, properties)
+ var nodeType = role === 'normal' ? (properties.console_identifier == 'Dispatch console' ? 'console' : 'client') : 'broker';
+ if (role === 'normal') {
+ node.user = QDRService.valFor(attrs, conns[j], "user")
+ node.isEncrypted = QDRService.valFor(attrs, conns[j], "isEncrypted")
+ node.host = QDRService.valFor(attrs, conns[j], "host")
+
+ if (!normalsParent[nodeType]) {
+ normalsParent[nodeType] = node;
+ nodes.push( node );
+ node.normals = [node];
+ // now add a link
+ getLink(parent, nodes.length-1, dir);
+ client++;
+ } else {
+
+ normalsParent[nodeType].normals.push(node)
+ }
+ } else {
+ nodes.push( node)
+ // now add a link
+ getLink(parent, nodes.length-1, dir);
+ client++;
+ }
}
}
source++;
}
$scope.schema = QDRService.schema;
- // add a row for each attribute in .router attributeNames array
- for (var id in nodeInfo) {
- var onode = nodeInfo[id];
-
- initForm(onode['.connection'].attributeNames, onode['.connection'].results[0], QDRService.schema.entityTypes.connection, $scope.connAttributes);
- initForm(onode['.router'].attributeNames, onode['.router'].results[0], QDRService.schema.entityTypes.router, $scope.attributes);
-
- break;
- }
// init D3 force layout
force = d3.layout.force()
.nodes(nodes)
@@ -506,69 +544,54 @@ var QDR = (function (QDR) {
// app starts here
restart(false);
force.start();
- }
-/*
- function dragstart(d) {
- d3.select(this).classed("fixed", d.fixed = true);
- }
+ setTimeout(function () {
+ updateForm(Object.keys(QDRService.topology.nodeInfo())[0], 'router', 0);
+ }, 10)
- function dblclick(d) {
- d3.select(this).classed("fixed", d.fixed = false);
}
-*/
- // called when we mouseover a node
- // we need to update the table
- function updateNodeForm (d) {
- //QDR.log.debug("update form info for ");
- //console.dump(d);
+
+ function updateForm (key, entity, resultIndex) {
var nodeInfo = QDRService.topology.nodeInfo();
- var onode = nodeInfo[d.key];
+ var onode = nodeInfo[key]
if (onode) {
- var nodeResults = onode['.router'].results[0];
- var nodeAttributes = onode['.router'].attributeNames;
-
- for (var i=0; i<$scope.attributes.length; ++i) {
- var idx = nodeAttributes.indexOf($scope.attributes[i].attributeName);
- if (idx > -1) {
- if ($scope.attributes[i].attributeValue != nodeResults[idx]) {
- // highlight the changed data
- $scope.attributes[i].attributeValue = nodeResults[idx];
-
- }
- }
- }
- }
- $scope.topoForm = "general";
- $scope.$apply();
- }
+ var nodeResults = onode['.' + entity].results[resultIndex]
+ var nodeAttributes = onode['.' + entity].attributeNames
+ var attributes = nodeResults.map( function (row, i) {
+ return {
+ attributeName: nodeAttributes[i],
+ attributeValue: row
+ }
+ })
+ // sort by attributeName
+ attributes.sort( function (a, b) { return a.attributeName.localeCompare(b.attributeName) })
- function updateConnForm (d, resultIndex) {
- var nodeInfo = QDRService.topology.nodeInfo();
- var onode = nodeInfo[d.key];
- if (onode && onode['.connection']) {
- var nodeResults = onode['.connection'].results[resultIndex];
- var nodeAttributes = onode['.connection'].attributeNames;
-
- for (var i=0; i<$scope.connAttributes.length; ++i) {
- var idx = nodeAttributes.indexOf($scope.connAttributes[i].attributeName);
- if (idx > -1) {
- try {
- if ($scope.connAttributes[i].attributeValue != nodeResults[idx]) {
- // highlight the changed data
- $scope.connAttributes[i].attributeValue = nodeResults[idx];
+ // move the Name first
+ var nameIndex = attributes.findIndex ( function (attr) {
+ return attr.attributeName === 'name'
+ })
+ if (nameIndex >= 0)
+ attributes.splice(0, 0, attributes.splice(nameIndex, 1)[0]);
+ // get the list of ports this router is listening on
+ if (entity === 'router') {
+ var listeners = onode['.listener'].results;
+ var listenerAttributes = onode['.listener'].attributeNames;
+ var normals = listeners.filter ( function (listener) {
+ return QDRService.valFor( listenerAttributes, listener, 'role') === 'normal';
+ })
+ var ports = []
+ normals.forEach (function (normalListener) {
+ ports.push(QDRService.valFor( listenerAttributes, normalListener, 'port'))
+ })
+ // add as 2nd row
+ if (ports.length)
+ attributes.splice(1, 0, {attributeName: 'Listening on', attributeValue: ports});
+ }
- }
- } catch (err) {
- QDR.log.error("error updating form" + err)
- }
- }
- }
+ $scope.$broadcast('showEntityForm', {entity: entity, attributes: attributes})
}
- $scope.topoForm = "connections";
- $scope.$apply();
+ $scope.$apply();
}
-
function getContainerIndex(_id) {
var nodeIndex = 0;
var nodeInfo = QDRService.topology.nodeInfo();
@@ -738,6 +761,12 @@ var QDR = (function (QDR) {
d3.select("#crosssection svg").remove();
d3.select("#crosssection").style("display","none");
});
+ d3.select("#multiple_details").transition()
+ .duration(500)
+ .style("opacity", 0)
+ .each("end", function (d) {
+ d3.select("#multiple_details").style("display", "none")
+ })
}
// takes the nodes and links array of objects and adds svg elements for everything that hasn't already
@@ -793,7 +822,7 @@ var QDR = (function (QDR) {
var conn = onode['.connection'].results[resultIndex];
/// find the connection whose container is the right's name
var name = QDRService.valFor(onode['.connection'].attributeNames, conn, "container");
- if (name == right.name) {
+ if (name == right.containerName) {
break;
}
}
@@ -803,7 +832,7 @@ var QDR = (function (QDR) {
left = d.target;
resultIndex = left.resultIndex;
}
- updateConnForm(left, resultIndex);
+ updateForm(left.key, 'connection', resultIndex);
}
// select link
@@ -944,33 +973,30 @@ var QDR = (function (QDR) {
circle.selectAll('circle')
.classed('selected', function (d) { return (d === selected_node) })
.classed('fixed', function (d) { return (d.fixed & 0b1) })
+ //.classed('multiple', function(d) { return (d.normals && d.normals.length > 1) } )
// add new circle nodes. if nodes[] is longer than the existing paths, add a new path for each new element
- var g = circle.enter().append('svg:g');
-
- // add new circles and set their attr/class/behavior
- g.append('svg:circle')
- .attr('class', 'node')
- .attr('r', function (d) {
- return radii[d.nodeType];
- })
- .classed('fixed', function (d) {return d.fixed})
- .classed('temp', function(d) { return QDRService.nameFromId(d.key) == '__internal__'; } )
- .classed('normal', function(d) { return d.nodeType == 'normal' } )
- .classed('inter-router', function(d) { return d.nodeType == 'inter-router' } )
- .classed('on-demand', function(d) { return d.nodeType == 'on-demand' } )
-
-/*
- .style('fill', function (d) {
- var sColor = colors[d.nodeType];
- return (d === selected_node) ? d3.rgb(sColor).brighter().toString() : d3.rgb(sColor);
- })
- .style('stroke', function (d) {
- var sColor = colors[d.nodeType];
- return d3.rgb(sColor).darker().toString();
- })
-*/
- .on('mouseover', function (d) {
+ var g = circle.enter().append('svg:g')
+ .classed('multiple', function(d) { return (d.normals && d.normals.length > 1) } )
+
+ var appendCircle = function (g) {
+ // add new circles and set their attr/class/behavior
+ return g.append('svg:circle')
+ .attr('class', 'node')
+ .attr('r', function (d) {
+ return radii[d.nodeType];
+ })
+ .classed('fixed', function (d) {return d.fixed})
+ .classed('temp', function(d) { return QDRService.nameFromId(d.key) == '__internal__'; } )
+ .classed('normal', function(d) { return d.nodeType == 'normal' } )
+ .classed('inter-router', function(d) { return d.nodeType == 'inter-router' } )
+ .classed('on-demand', function(d) { return d.nodeType == 'on-demand' } )
+ .classed('console', function(d) { return d.properties.console_identifier == 'Dispatch console' } )
+ .classed('artemis', function(d) { return QDRService.isArtemis(d) } )
+ .classed('qpid-cpp', function(d) { return QDRService.isQpid(d) } )
+ .classed('client', function(d) { return d.nodeType === 'normal' && !d.properties.console_identifier } )
+ }
+ appendCircle(g).on('mouseover', function (d) {
if ($scope.addingNode.step > 0) {
d3.select(this).attr('transform', 'scale(1.1)');
return;
@@ -978,10 +1004,10 @@ var QDR = (function (QDR) {
if (!selected_node) {
if (d.nodeType === 'inter-router') {
//QDR.log.debug("showing general form");
- updateNodeForm(d);
+ updateForm(d.key, 'router', 0);
} else if (d.nodeType === 'normal' || d.nodeType === 'on-demand') {
//QDR.log.debug("showing connections form");
- updateConnForm(d, d.resultIndex);
+ updateForm(d.key, 'connection', d.resultIndex);
}
}
@@ -1057,19 +1083,11 @@ var QDR = (function (QDR) {
// if this node was selected, unselect it
if (mousedown_node === selected_node) {
selected_node = null;
- $scope.topoFormSelected = "";
}
else {
- selected_node = mousedown_node;
- if (d.nodeType === 'inter-router') {
- //QDR.log.debug("showing general form");
- updateNodeForm(d);
- $scope.topoFormSelected = "general";
- } else if (d.nodeType === 'normal' || d.nodeType === 'on-demand') {
- //QDR.log.debug("showing connections form");
- updateConnForm(d, d.resultIndex);
- $scope.topoFormSelected = "connections";
- }
+ // don't select nodes that represent multiple clients/consoles
+ if (!d.normals || d.normals.length < 2)
+ selected_node = mousedown_node;
}
for (var i=0; i<links.length; ++i) {
links[i]['highlighted'] = false;
@@ -1099,21 +1117,136 @@ var QDR = (function (QDR) {
.style('top', (mouseY + $(document).scrollTop()) + "px")
.style('display', 'block');
- });
+ })
+ .on("click", function (d) {
+ if (!d.normals || d.normals.length < 2) {
+ if ( QDRService.isArtemis(d) && Core.ConnectionName === 'Artemis' ) {
+ $location.path('/jmx/attributes?tab=artemis&con=Artemis')
+ }
+ return;
+ }
+ clickPos = d3.mouse(this);
+ d3.event.stopPropagation();
+ $scope.multiData = []
+ d.normals.forEach( function (n) {
+ $scope.multiData.push(n)
+ })
+ $scope.$apply();
+ d3.select('#multiple_details')
+ .style({
+ display: 'block',
+ opacity: 1,
+ height: (d.normals.length + 1) * 30 + "px",
+ 'overflow-y': d.normals.length > 10 ? 'scroll' : 'hidden',
+ left: (mouseX + $(document).scrollLeft()) + "px",
+ top: (mouseY + $(document).scrollTop()) + "px"})
+ })
- // show node IDs
- g.append('svg:text')
- .attr('x', 0)
- .attr('y', 4)
- .attr('class', 'id')
- .text(function (d) {
- return (d.nodeType === 'normal' || d.nodeType == 'on-demand') ? d.name.slice(-1) :
- d.name.length>7 ? d.name.substr(0,6)+'...' : d.name;
- });
+ var appendContent = function (g) {
+ // show node IDs
+ g.append('svg:text')
+ .attr('x', 0)
+ .attr('y', function (d) {
+ var y = 6;
+ if (QDRService.isArtemis(d))
+ y = 8;
+ else if (QDRService.isQpid(d))
+ y = 9;
+ else if (d.nodeType === 'inter-router')
+ y = 4;
+ return y;})
+ .attr('class', 'id')
+ .classed('console', function(d) { return d.properties.console_identifier == 'Dispatch console' } )
+ .classed('normal', function(d) { return d.nodeType === 'normal' } )
+ .classed('on-demand', function(d) { return d.nodeType === 'on-demand' } )
+ .classed('artemis', function(d) { return QDRService.isArtemis(d) } )
+ .classed('qpid-cpp', function(d) { return QDRService.isQpid(d) } )
+ .text(function (d) {
+ if (d.properties.console_identifier == 'Dispatch console') {
+ return '\uf108'; // icon-desktop for this console
+ }
+ if (QDRService.isArtemis(d)) {
+ return '\ue900'
+ }
+ if (QDRService.isQpid(d)) {
+ return '\ue901';
+ }
+ if (d.nodeType === 'normal')
+ return '\uf109'; // icon-laptop for clients
+ return d.name.length>7 ? d.name.substr(0,6)+'...' : d.name;
+ });
+ }
+ appendContent(g)
+
+ var appendTitle = function (g) {
+ g.append("svg:title").text(function (d) {
+ var x = '';
+ if (d.normals && d.normals.length > 1)
+ x = " x " + d.normals.length;
+ if (d.properties.console_identifier == 'Dispatch console') {
+ return 'Dispatch console' + x
+ }
+ if (d.properties.product == 'qpid-cpp') {
+ return 'Broker - qpid-cpp' + x
+ }
+ if ( QDRService.isArtemis(d) ) {
+ return 'Broker - Artemis' + x
+ }
+ return d.nodeType == 'normal' ? 'client' + x : (d.nodeType == 'on-demand' ? 'broker' : 'Router ' + d.name)
+ })
+ }
+ appendTitle(g);
// remove old nodes
circle.exit().remove();
+ // add subcircles
+ svg.selectAll('.subcircle').remove();
+
+ svg.selectAll('.multiple')
+ .insert('svg:circle', '.normal')
+ .attr('class', 'subcircle')
+ .attr('r', 18)
+
+
+ // dynamically create the legend based on which node types are present
+ var legendNodes = [];
+ legendNodes.push(aNode("Router", "", "inter-router", undefined, 0, 0, 0, 0, false, {}))
+
+ if (!svg.selectAll('circle.console').empty()) {
+ legendNodes.push(aNode("Dispatch console", "", "normal", undefined, 1, 0, 0, 0, false, {console_identifier: 'Dispatch console'}))
+ }
+ if (!svg.selectAll('circle.client').empty()) {
+ legendNodes.push(aNode("Client", "", "normal", undefined, 2, 0, 0, 0, false, {}))
+ }
+ if (!svg.selectAll('circle.qpid-cpp').empty()) {
+ legendNodes.push(aNode("Qpid cpp broker", "", "on-demand", undefined, 3, 0, 0, 0, false, {product: 'qpid-cpp'}))
+ }
+ if (!svg.selectAll('circle.artemis').empty()) {
+ legendNodes.push(aNode("Artemis broker", "", "on-demand", undefined, 4, 0, 0, 0, false, {}))
+ }
+ lsvg = lsvg.data(legendNodes, function (d) {
+ return d.id;
+ });
+ var lg = lsvg.enter().append('svg:g')
+ .attr('transform', function (d, i) {
+ // 45px between lines and add 10px space after 1st line
+ return "translate(0, "+(45*i+(i>0?10:0))+")"
+ })
+ appendCircle(lg)
+ appendContent(lg)
+ appendTitle(lg)
+ lg.append('svg:text')
+ .attr('x', 35)
+ .attr('y', 6)
+ .attr('class', "label")
+ .text(function (d) {return d.key })
+ lsvg.exit().remove();
+ var svgEl = document.getElementById("svglegend"),
+ bb = svgEl.getBBox();
+ svgEl.style.height = bb.y + bb.height;
+ svgEl.style.width = bb.x + bb.width;
+
if (!mousedown_node || !selected_node)
return;
@@ -1161,6 +1294,7 @@ var QDR = (function (QDR) {
saveChanged();
// TODO: update graph nodes instead of rebuilding entire graph
d3.select("#SVG_ID").remove();
+ d3.select("#svg_legend svg").remove();
animate = true;
initForceGraph();
//if ($location.path().startsWith("/topology"))
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org