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 2018/12/03 15:49:15 UTC
[1/2] qpid-dispatch git commit: DISPATCH-1195 Periodically update
popup detail on topology page
Repository: qpid-dispatch
Updated Branches:
refs/heads/master 3adde8e5d -> 55b7ae55e
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/plugin/js/topology/nodes.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/topology/nodes.js b/console/stand-alone/plugin/js/topology/nodes.js
index 5d003c6..50c9a37 100644
--- a/console/stand-alone/plugin/js/topology/nodes.js
+++ b/console/stand-alone/plugin/js/topology/nodes.js
@@ -17,70 +17,74 @@ specific language governing permissions and limitations
under the License.
*/
-import { utils } from '../amqp/utilities.js';
+import { utils } from "../amqp/utilities.js";
/* global d3 Promise */
export class Node {
- constructor(id, name, nodeType, properties, routerId, x, y, nodeIndex, resultIndex, fixed, connectionContainer) {
- this.key = id; // the router uri for this node (or group of clients) like: amqp:/_topo/0/<router id>/$management
- this.name = name; // the router id portion of the key
- this.nodeType = nodeType; // router.role
+ constructor(
+ id,
+ name,
+ nodeType,
+ properties,
+ routerId,
+ x,
+ y,
+ nodeIndex,
+ resultIndex,
+ fixed,
+ connectionContainer
+ ) {
+ this.key = id; // the router uri for this node (or group of clients) like: amqp:/_topo/0/<router id>/$management
+ this.name = name; // the router id portion of the key
+ this.nodeType = nodeType; // router.role
this.properties = properties;
- this.routerId = routerId; // the router uri of the router we are connected to (for groups)
+ this.routerId = routerId; // the router uri of the router we are connected to (for groups)
this.x = x;
this.y = y;
this.id = nodeIndex;
this.resultIndex = resultIndex;
this.fixed = !!+fixed;
- this.cls = '';
+ this.cls = "";
this.container = connectionContainer;
this.isConsole = utils.isConsole(this);
this.isArtemis = utils.isArtemis(this);
}
- title (hide) {
- let x = '';
+ title(hide) {
+ let x = "";
if (this.normals && this.normals.length > 1 && !hide)
- x = ' x ' + this.normals.length;
- if (this.isConsole)
- return 'Dispatch console' + x;
- else if (this.isArtemis)
- return 'Broker - Artemis' + x;
- else if (this.properties.product == 'qpid-cpp')
- return 'Broker - qpid-cpp' + x;
- else if (this.nodeType === 'edge')
- return 'Edge Router';
- else if (this.cdir === 'in')
- return 'Sender' + x;
- else if (this.cdir === 'out')
- return 'Receiver' + x;
- else if (this.cdir === 'both')
- return 'Sender/Receiver' + x;
- else if (this.nodeType === 'normal')
- return 'client' + x;
- else if (this.nodeType === 'on-demand')
- return 'broker';
+ x = " x " + this.normals.length;
+ if (this.isConsole) return "Dispatch console" + x;
+ else if (this.isArtemis) return "Broker - Artemis" + x;
+ else if (this.properties.product == "qpid-cpp")
+ return "Broker - qpid-cpp" + x;
+ else if (this.nodeType === "edge") return "Edge Router";
+ else if (this.cdir === "in") return "Sender" + x;
+ else if (this.cdir === "out") return "Receiver" + x;
+ else if (this.cdir === "both") return "Sender/Receiver" + x;
+ else if (this.nodeType === "normal") return "client" + x;
+ else if (this.nodeType === "on-demand") return "broker";
else if (this.properties.product) {
return this.properties.product;
- }
- else {
- return '';
+ } else {
+ return "";
}
}
- toolTip (topology) {
- return new Promise( (function (resolve) {
- if (this.nodeType === 'normal' || this.nodeType === 'edge') {
- resolve(this.clientTooltip());
- } else
- this.routerTooltip(topology)
- .then( function (toolTip) {
+ toolTip(topology) {
+ return new Promise(
+ function(resolve) {
+ if (this.nodeType === "normal" || this.nodeType === "edge") {
+ resolve(this.clientTooltip());
+ } else
+ this.routerTooltip(topology).then(function(toolTip) {
resolve(toolTip);
});
- }.bind(this)));
+ }.bind(this)
+ );
}
- clientTooltip () {
+ clientTooltip() {
let type = this.title(true);
- let title = '';
+ let title = "";
title += `<table class="popupTable"><tr><td>Type</td><td>${type}</td></tr>`;
if (!this.normals || this.normals.length < 2)
title += `<tr><td>Host</td><td>${this.host}</td></tr>`;
@@ -88,77 +92,103 @@ export class Node {
title += `<tr><td>Count</td><td>${this.normals.length}</td></tr>`;
}
if (!this.isConsole && !this.isArtemis)
- title += '<tr><td colspan=2 class="more-info">Click circle for more info</td></tr></table>';
+ title +=
+ '<tr><td colspan=2 class="more-info">Click circle for more info</td></tr></table>';
return title;
}
- routerTooltip (topology) {
- return new Promise( (function (resolve) {
- topology.ensureEntities(this.key, [
- {entity: 'listener', attrs: ['role', 'port', 'http']},
- {entity: 'router', attrs: ['name', 'version', 'hostName']}
- ], function (foo, nodes) {
- // update all the router title text
- let node = nodes[this.key];
- const err = `<table class="popupTable"><tr><td>Error</td><td>Unable to get router info for ${this.key}</td></tr></table>`;
- if (!node) {
- resolve(err);
- return;
- }
- let listeners = node['listener'];
- let router = node['router'];
- if (!listeners || !router) {
- resolve(err);
- return;
- }
- let r = utils.flatten(router.attributeNames, router.results[0]);
- let title = '<table class="popupTable">';
- title += ('<tr><td>Router</td><td>' + r.name + '</td></tr>');
- if (r.hostName)
- title += ('<tr><td>Host Name</td><td>' + r.hostHame + '</td></tr>');
- title += ('<tr><td>Version</td><td>' + r.version + '</td></tr>');
- let ports = [];
- for (let l=0; l<listeners.results.length; l++) {
- let listener = utils.flatten(listeners.attributeNames, listeners.results[l]);
- if (listener.role === 'normal') {
- ports.push(listener.port+'');
- }
- }
- if (ports.length > 0) {
- title += ('<tr><td>Ports</td><td>' + ports.join(', ') + '</td></tr>');
- }
- title += '</table>';
- resolve(title);
- return title;
- }.bind(this));
- }.bind(this)));
+ routerTooltip(topology) {
+ return new Promise(
+ function(resolve) {
+ topology.ensureEntities(
+ this.key,
+ [
+ { entity: "listener", attrs: ["role", "port", "http"] },
+ { entity: "router", attrs: ["name", "version", "hostName"] }
+ ],
+ function(foo, nodes) {
+ // update all the router title text
+ let node = nodes[this.key];
+ const err = `<table class="popupTable"><tr><td>Error</td><td>Unable to get router info for ${
+ this.key
+ }</td></tr></table>`;
+ if (!node) {
+ resolve(err);
+ return;
+ }
+ let listeners = node["listener"];
+ let router = node["router"];
+ if (!listeners || !router) {
+ resolve(err);
+ return;
+ }
+ let r = utils.flatten(router.attributeNames, router.results[0]);
+ let title = '<table class="popupTable">';
+ title += "<tr><td>Router</td><td>" + r.name + "</td></tr>";
+ if (r.hostName)
+ title += "<tr><td>Host Name</td><td>" + r.hostHame + "</td></tr>";
+ title += "<tr><td>Version</td><td>" + r.version + "</td></tr>";
+ let ports = [];
+ for (let l = 0; l < listeners.results.length; l++) {
+ let listener = utils.flatten(
+ listeners.attributeNames,
+ listeners.results[l]
+ );
+ if (listener.role === "normal") {
+ ports.push(listener.port + "");
+ }
+ }
+ if (ports.length > 0) {
+ title +=
+ "<tr><td>Ports</td><td>" + ports.join(", ") + "</td></tr>";
+ }
+ title += "</table>";
+ resolve(title);
+ return title;
+ }.bind(this)
+ );
+ }.bind(this)
+ );
}
radius() {
return nodeProperties[this.nodeType].radius;
}
uid() {
- if (!this.uuid)
- this.uuid = this.container;
+ if (!this.uuid) this.uuid = this.container;
return this.normals ? `${this.uuid}-${this.normals.length}` : this.uuid;
}
setFixed(fixed) {
- if (!fixed)
- this.lat = this.lon = null;
+ if (!fixed) this.lat = this.lon = null;
this.fixed = fixed;
}
}
const nodeProperties = {
// router types
- 'inter-router': {radius: 28, refX: {end: 32, start: -19}, linkDistance: [150, 70], charge: [-1800, -900]},
- 'edge': {radius: 20, refX: {end: 24, start: -12}, linkDistance: [110, 55], charge: [-1350, -900]},
+ "inter-router": {
+ radius: 28,
+ refX: { end: 32, start: -19 },
+ linkDistance: [150, 70],
+ charge: [-1800, -900]
+ },
+ edge: {
+ radius: 20,
+ refX: { end: 24, start: -12 },
+ linkDistance: [110, 55],
+ charge: [-1350, -900]
+ },
// generated nodes from connections. key is from connection.role
- 'normal': {radius: 15, refX: {end: 20, start: -7}, linkDistance: [75, 40], charge: [-900, -900]},
+ normal: {
+ radius: 15,
+ refX: { end: 20, start: -7 },
+ linkDistance: [75, 40],
+ charge: [-900, -900]
+ }
};
// aliases
-nodeProperties._topo = nodeProperties['inter-router'];
-nodeProperties._edge = nodeProperties['edge'];
-nodeProperties['on-demand'] = nodeProperties['normal'];
-nodeProperties['route-container'] = nodeProperties['normal'];
+nodeProperties._topo = nodeProperties["inter-router"];
+nodeProperties._edge = nodeProperties["edge"];
+nodeProperties["on-demand"] = nodeProperties["normal"];
+nodeProperties["route-container"] = nodeProperties["normal"];
export class Nodes {
constructor(logger) {
@@ -166,8 +196,7 @@ export class Nodes {
this.logger = logger;
}
static radius(type) {
- if (nodeProperties[type].radius)
- return nodeProperties[type].radius;
+ if (nodeProperties[type].radius) return nodeProperties[type].radius;
return 15;
}
static maxRadius() {
@@ -179,8 +208,7 @@ export class Nodes {
}
static refX(end, r) {
for (let key in nodeProperties) {
- if (nodeProperties[key].radius == r)
- return nodeProperties[key].refX[end];
+ if (nodeProperties[key].radius == r) return nodeProperties[key].refX[end];
}
return 0;
}
@@ -193,97 +221,98 @@ export class Nodes {
return Object.keys(values);
}
// vary the following force graph attributes based on nodeCount
- static forceScale (nodeCount, minmax) {
+ static forceScale(nodeCount, minmax) {
let count = Math.max(Math.min(nodeCount, 80), 6);
- let x = d3.scale.linear()
- .domain([6,80])
+ let x = d3.scale
+ .linear()
+ .domain([6, 80])
.range(minmax);
return x(count);
}
- linkDistance (d, nodeCount) {
+ linkDistance(d, nodeCount) {
let range = nodeProperties[d.target.nodeType].linkDistance;
return Nodes.forceScale(nodeCount, range);
}
- charge (d, nodeCount) {
+ charge(d, nodeCount) {
let charge = nodeProperties[d.nodeType].charge;
return Nodes.forceScale(nodeCount, charge);
}
- gravity (d, nodeCount) {
+ gravity(d, nodeCount) {
return Nodes.forceScale(nodeCount, [0.0001, 0.1]);
}
- getLength () {
+ getLength() {
return this.nodes.length;
}
- get (index) {
+ get(index) {
if (index < this.getLength()) {
return this.nodes[index];
}
- this.logger.error(`Attempted to get node[${index}] but there were only ${this.getLength()} nodes`);
+ this.logger.error(
+ `Attempted to get node[${index}] but there were only ${this.getLength()} nodes`
+ );
return undefined;
}
- setNodesFixed (name, b) {
- this.nodes.some(function (n) {
+ setNodesFixed(name, b) {
+ this.nodes.some(function(n) {
if (n.name === name) {
n.fixed(b);
return true;
}
});
}
- nodeFor (name) {
+ nodeFor(name) {
for (let i = 0; i < this.nodes.length; ++i) {
- if (this.nodes[i].name == name)
- return this.nodes[i];
+ if (this.nodes[i].name == name) return this.nodes[i];
}
return null;
}
- nodeExists (connectionContainer) {
- return this.nodes.findIndex( function (node) {
+ nodeExists(connectionContainer) {
+ return this.nodes.findIndex(function(node) {
return node.container === connectionContainer;
});
}
- normalExists (connectionContainer) {
+ normalExists(connectionContainer) {
let normalInfo = {};
- for (let i=0; i<this.nodes.length; ++i) {
+ for (let i = 0; i < this.nodes.length; ++i) {
if (this.nodes[i].normals) {
- if (this.nodes[i].normals.some(function (normal, j) {
- if (normal.container === connectionContainer && i !== j) {
- normalInfo = {nodesIndex: i, normalsIndex: j};
- return true;
- }
- return false;
- }))
+ if (
+ this.nodes[i].normals.some(function(normal, j) {
+ if (normal.container === connectionContainer && i !== j) {
+ normalInfo = { nodesIndex: i, normalsIndex: j };
+ return true;
+ }
+ return false;
+ })
+ )
break;
}
}
return normalInfo;
}
- savePositions (nodes) {
- if (!nodes)
- nodes = this.nodes;
- if (Object.prototype.toString.call(nodes) !== '[object Array]') {
+ savePositions(nodes) {
+ if (!nodes) nodes = this.nodes;
+ if (Object.prototype.toString.call(nodes) !== "[object Array]") {
nodes = [nodes];
}
- this.nodes.forEach( function (d) {
+ this.nodes.forEach(function(d) {
localStorage[d.name] = JSON.stringify({
x: Math.round(d.x),
y: Math.round(d.y),
- fixed: (d.fixed & 1) ? 1 : 0,
+ fixed: d.fixed & 1 ? 1 : 0
});
});
}
// Convert node's x,y coordinates to longitude, lattitude
- saveLonLat (backgroundMap, nodes) {
- if (!backgroundMap || !backgroundMap.initialized)
- return;
+ saveLonLat(backgroundMap, nodes) {
+ if (!backgroundMap || !backgroundMap.initialized) return;
// didn't pass nodes, use all nodes
- if (!nodes)
- nodes = this.nodes;
+ if (!nodes) nodes = this.nodes;
// passed a single node, wrap it in an array
- if (Object.prototype.toString.call(nodes) !== '[object Array]') {
+ if (Object.prototype.toString.call(nodes) !== "[object Array]") {
nodes = [nodes];
}
- for (let i=0; i<nodes.length; i++) {
+ for (let i = 0; i < nodes.length; i++) {
let n = nodes[i];
if (n.fixed) {
let lonlat = backgroundMap.getLonLat(n.x, n.y);
@@ -297,10 +326,9 @@ export class Nodes {
}
}
// convert all nodes' longitude,lattitude to x,y coordinates
- setXY (backgroundMap) {
- if (!backgroundMap)
- return;
- for (let i=0; i<this.nodes.length; i++) {
+ setXY(backgroundMap) {
+ if (!backgroundMap) return;
+ for (let i = 0; i < this.nodes.length; i++) {
let n = this.nodes[i];
if (n.lon && n.lat) {
let xy = backgroundMap.getXY(n.lon, n.lat);
@@ -312,68 +340,128 @@ export class Nodes {
}
}
- find (connectionContainer, properties, name) {
+ find(connectionContainer, properties, name) {
properties = properties || {};
- for (let i=0; i<this.nodes.length; ++i) {
- if (this.nodes[i].name === name || this.nodes[i].container === connectionContainer) {
- if (properties.product)
- this.nodes[i].properties = properties;
+ for (let i = 0; i < this.nodes.length; ++i) {
+ if (
+ this.nodes[i].name === name ||
+ this.nodes[i].container === connectionContainer
+ ) {
+ if (properties.product) this.nodes[i].properties = properties;
return this.nodes[i];
}
}
return undefined;
}
- getOrCreateNode (id, name, nodeType, nodeIndex, x, y,
- connectionContainer, resultIndex, fixed, properties) {
+ getOrCreateNode(
+ id,
+ name,
+ nodeType,
+ nodeIndex,
+ x,
+ y,
+ connectionContainer,
+ resultIndex,
+ fixed,
+ properties
+ ) {
properties = properties || {};
let gotNode = this.find(connectionContainer, properties, name);
if (gotNode) {
return gotNode;
}
let routerId = utils.nameFromId(id);
- return new Node(id, name, nodeType, properties, routerId, x, y,
- nodeIndex, resultIndex, fixed, connectionContainer);
- }
- add (obj) {
+ return new Node(
+ id,
+ name,
+ nodeType,
+ properties,
+ routerId,
+ x,
+ y,
+ nodeIndex,
+ resultIndex,
+ fixed,
+ connectionContainer
+ );
+ }
+ add(obj) {
this.nodes.push(obj);
return obj;
}
- addUsing (id, name, nodeType, nodeIndex, x, y,
- connectContainer, resultIndex, fixed, properties) {
- let obj = this.getOrCreateNode(id, name, nodeType, nodeIndex, x, y,
- connectContainer, resultIndex, fixed, properties);
+ addUsing(
+ id,
+ name,
+ nodeType,
+ nodeIndex,
+ x,
+ y,
+ connectContainer,
+ resultIndex,
+ fixed,
+ properties
+ ) {
+ let obj = this.getOrCreateNode(
+ id,
+ name,
+ nodeType,
+ nodeIndex,
+ x,
+ y,
+ connectContainer,
+ resultIndex,
+ fixed,
+ properties
+ );
this.nodes.push(obj);
return obj;
}
- clearHighlighted () {
- for (let i = 0; i<this.nodes.length; ++i) {
+ clearHighlighted() {
+ for (let i = 0; i < this.nodes.length; ++i) {
this.nodes[i].highlighted = false;
}
}
- initialize (nodeInfo, localStorage, width, height) {
+ initialize(nodeInfo, localStorage, width, height) {
let nodeCount = Object.keys(nodeInfo).length;
let yInit = 50;
let animate = false;
for (let id in nodeInfo) {
let name = utils.nameFromId(id);
// if we have any new nodes, animate the force graph to position them
- let position = localStorage[name] ? JSON.parse(localStorage[name]) : undefined;
+ let position = localStorage[name]
+ ? JSON.parse(localStorage[name])
+ : undefined;
if (!position) {
animate = true;
position = {
- x: Math.round(width / 4 + ((width / 2) / nodeCount) * this.nodes.length),
- y: Math.round(height / 2 + Math.sin(this.nodes.length / (Math.PI*2.0)) * height / 4),
- fixed: false,
+ x: Math.round(
+ width / 4 + (width / 2 / nodeCount) * this.nodes.length
+ ),
+ y: Math.round(
+ height / 2 +
+ (Math.sin(this.nodes.length / (Math.PI * 2.0)) * height) / 4
+ ),
+ fixed: false
};
}
if (position.y > height) {
position.y = 200 - yInit;
yInit *= -1;
}
- let parts = id.split('/');
- this.addUsing(id, name, parts[1], this.nodes.length, position.x, position.y, name, undefined, position.fixed, {});
+ let parts = id.split("/");
+ this.addUsing(
+ id,
+ name,
+ parts[1],
+ this.nodes.length,
+ position.x,
+ position.y,
+ name,
+ undefined,
+ position.fixed,
+ {}
+ );
}
return animate;
}
}
-
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/plugin/js/topology/qdrTopology.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/topology/qdrTopology.js b/console/stand-alone/plugin/js/topology/qdrTopology.js
index e5cb783..b20e69e 100644
--- a/console/stand-alone/plugin/js/topology/qdrTopology.js
+++ b/console/stand-alone/plugin/js/topology/qdrTopology.js
@@ -146,20 +146,26 @@ export class TopologyController {
});
}
+ // called from the html page's popup menu
$scope.setFixed = function(b) {
if ($scope.contextNode) {
$scope.contextNode.setFixed(b);
nodes.savePositions();
nodes.saveLonLat(backgroundMap, $scope.contextNode);
}
- if (!b)
- animate = true;
+ // redraw the circles/links
restart();
+
+ if (!b) {
+ // let the nodes move to a new position
+ animate = true;
+ force.start();
+ }
};
$scope.isFixed = function() {
if (!$scope.contextNode)
return false;
- return ($scope.contextNode.fixed & 1);
+ return ($scope.contextNode.fixed);
};
let mouseX, mouseY;
@@ -255,13 +261,15 @@ export class TopologyController {
});
// the legend
- d3.select('#topo_svg_legend svg').remove();
- lsvg = d3.select('#topo_svg_legend')
- .append('svg')
- .attr('id', 'svglegend');
- lsvg = lsvg.append('svg:g')
- .attr('transform', `translate(${Nodes.maxRadius()}, ${Nodes.maxRadius()})`)
- .selectAll('g');
+ //d3.select('#topo_svg_legend svg').remove();
+ if (d3.select('#svglegend').empty()) {
+ lsvg = d3.select('#topo_svg_legend')
+ .append('svg')
+ .attr('id', 'svglegend');
+ lsvg = lsvg.append('svg:g')
+ .attr('transform', `translate(${Nodes.maxRadius()}, ${Nodes.maxRadius()})`)
+ .selectAll('g');
+ }
// mouse event vars
$scope.mousedown_node = null;
@@ -342,8 +350,8 @@ export class TopologyController {
circle = svg.append('svg:g').attr('class', 'nodes').selectAll('g');
// app starts here
- if (unknowns.length === 0)
- restart();
+ //if (unknowns.length === 0)
+ restart();
if (oldSelectedNode) {
d3.selectAll('circle.inter-router').classed('selected', function (d) {
if (d.key === oldSelectedNode.key) {
@@ -510,11 +518,12 @@ export class TopologyController {
};
// update the contents of the popup tooltip each time the data is polled
QDRService.management.topology.addUpdatedAction('connectionPopupHTML', updateTooltip);
+ // request the data and update the tooltip as soon as it arrives
QDRService.management.topology.ensureAllEntities(
[{ entity: 'router.link', force: true},{entity: 'connection'}], function () {
updateTooltip();
});
- // show the tooltip
+ // just show the tooltip with whatever data we have
updateTooltip();
restart();
@@ -572,7 +581,7 @@ export class TopologyController {
return (d === selected_node);
})
.classed('fixed', function(d) {
- return d.fixed & 1;
+ return d.fixed;
});
circle
.classed('multiple', function (d) {
@@ -648,9 +657,8 @@ export class TopologyController {
if (cur_mouse[0] != initial_mouse_down_position[0] ||
cur_mouse[1] != initial_mouse_down_position[1]) {
d.setFixed(true);
- nodes.savePositions(d);
- nodes.saveLonLat(backgroundMap, d);
- console.log('savedLonLat for fixed node');
+ nodes.savePositions();
+ nodes.saveLonLat(backgroundMap);
resetMouseVars();
restart();
return;
@@ -670,17 +678,17 @@ export class TopologyController {
$scope.mousedown_node = null;
if (!$scope.$$phase) $scope.$apply();
// handle clicking on nodes that represent multiple sub-nodes
- if (d.normals && !d.isConsole && !d.isArtemis) {
+ if (d.normals && !d.isArtemis && !d.isQpid) {
doDialog(d);
}
+ // apply any data changes to the interface
restart();
})
.on('dblclick', function(d) { // circle
d3.event.preventDefault();
if (d.fixed) {
- d.fixed = false;
- nodes.setNodesFixed(d.name, false);
+ d.setFixed(false);
restart(); // redraw the node without a dashed line
force.start(); // let the nodes move to a new position
}
@@ -841,7 +849,7 @@ export class TopologyController {
return null;
})
.classed('fixed', function(d) {
- return d.fixed & 1;
+ return d.fixed;
})
.classed('normal', function(d) {
return d.nodeType == 'normal' || QDRService.utilities.isConsole(d);
@@ -997,11 +1005,8 @@ export class TopologyController {
if (!savedKeys.hasOwnProperty(key))
return 1;
// if the number of connections for this node chaanged
- if (!nodeInfo[key]['connection'])
- return -1;
- if (nodeInfo[key]['connection'].results.length != savedKeys[key]) {
- return -1;
- }
+ if (nodeInfo[key]['connection'].results.length !== savedKeys[key])
+ return nodeInfo[key]['connection'].results.length - savedKeys[key];
}
return 0;
}
@@ -1061,25 +1066,9 @@ export class TopologyController {
setupInitialUpdate();
} else if (changed === -1) {
// we lost a node (or a client), we can draw the new svg immediately
- animate = false;
+ QDRService.management.topology.purge();
+ initForceGraph();
saveChanged();
- let nodeInfo = QDRService.management.topology.nodeInfo();
- forceData.nodes = nodes = new Nodes(QDRLog);
- animate = nodes.initialize(nodeInfo, localStorage, width, height);
-
- let unknowns = [];
- forceData.links = links = new Links(QDRLog);
- if (links.initialize(nodeInfo, nodes, unknowns, localStorage, height)) {
- animate = true;
- }
- if (unknowns.length > 0) {
- resolveUnknowns(nodeInfo, unknowns);
- }
- else {
- force.nodes(nodes.nodes).links(links.links).start();
- restart();
- }
- //initForceGraph();
} else {
//QDRLog.debug("topology didn't change")
}
@@ -1102,7 +1091,7 @@ export class TopologyController {
animate = true;
setupInitialUpdate();
- QDRService.management.topology.startUpdating(false);
+ QDRService.management.topology.startUpdating(true);
}
}
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/plugin/js/topology/topoUtils.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/topology/topoUtils.js b/console/stand-alone/plugin/js/topology/topoUtils.js
index cbed6c0..71e5e4c 100644
--- a/console/stand-alone/plugin/js/topology/topoUtils.js
+++ b/console/stand-alone/plugin/js/topology/topoUtils.js
@@ -16,6 +16,9 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
+
+/* global Set */
+
// highlight the paths between the selected node and the hovered node
function findNextHopNode(from, d, QDRService, selected_node, nodes) {
// d is the node that the mouse is over
@@ -35,7 +38,7 @@ function findNextHopNode(from, d, QDRService, selected_node, nodes) {
let vAr = sInfo['router.node'].results;
for (let hIdx = 0; hIdx < vAr.length; ++hIdx) {
let addrT = QDRService.utilities.valFor(aAr, vAr[hIdx], 'id');
- if (addrT == d.name) {
+ if (d.name && (addrT == d.name)) {
let next = QDRService.utilities.valFor(aAr, vAr[hIdx], 'nextHop');
return (next == null) ? nodes.nodeFor(addrT) : nodes.nodeFor(next);
}
@@ -67,23 +70,44 @@ export function connectionPopupHTML (d, QDRService) {
return;
}
let utils = QDRService.utilities;
- let getConnsArray = function (d, conn) {
- let conns = [conn];
- if (d.cls === 'small') {
- conns = [];
- let normals = d.target.normals ? d.target.normals : d.source.normals;
- for (let n=0; n<normals.length; n++) {
- if (normals[n].resultIndex !== undefined) {
- conns.push(utils.flatten(onode['connection'].attributeNames,
- onode['connection'].results[normals[n].resultIndex]));
+ // return all of onode's connections that connecto to right
+ let getConnsArray = function (onode, key, right) {
+ if (right.normals) {
+ // if we want connections between a router and a client[s]
+ let connIds = new Set();
+ let connIndex = onode.connection.attributeNames.indexOf('identity');
+ for (let n=0; n<right.normals.length; n++) {
+ let normal = right.normals[n];
+ if (normal.key === key) {
+ connIds.add(normal.connectionId);
+ } else if (normal.alsoConnectsTo) {
+ normal.alsoConnectsTo.forEach( function (ac2) {
+ if (ac2.key === key)
+ connIds.add(ac2.connectionId);
+ });
}
}
+ return onode.connection.results.filter( function (result) {
+ return connIds.has(result[connIndex]);
+ }).map( function (c) {
+ return utils.flatten(onode.connection.attributeNames, c);
+ });
+ }
+ else {
+ // we want the connection between two routers
+ let container = utils.nameFromId(right.key);
+ let containerIndex = onode.connection.attributeNames.indexOf('container');
+ let roleIndex = onode.connection.attributeNames.indexOf('role');
+ return onode.connection.results.filter( function (conn) {
+ return conn[containerIndex] === container && conn[roleIndex] === 'inter-router';
+ }).map( function (c) {
+ return utils.flatten(onode.connection.attributeNames, c);
+ });
}
- return conns;
};
// construct HTML to be used in a popup when the mouse is moved over a link.
// The HTML is sanitized elsewhere before it is displayed
- let linksHTML = function (onode, conn, d) {
+ let linksHTML = function (onode, conns) {
const max_links = 10;
const fields = ['deliveryCount', 'undeliveredCount', 'unsettledCount', 'rejectedCount', 'releasedCount', 'modifiedCount'];
// local function to determine if a link's connectionId is in any of the connections
@@ -103,7 +127,6 @@ export function connectionPopupHTML (d, QDRService) {
}
return out;
};
- let conns = getConnsArray(d, conn);
// if the data for the line is from a client (small circle), we may have multiple connections
// loop through all links for this router and accumulate those belonging to the connection(s)
let nodeLinks = onode['router.link'];
@@ -189,50 +212,39 @@ export function connectionPopupHTML (d, QDRService) {
});
HTML += `<tr><td> ${joinedVals} </td></tr>`;
}
- // no rows were added
- if (links.length === 0) {
- HTML += `<tr><td align="center" colspan="${th.length}">Calculating rates, or rates were all zero</td></tr>`;
- }
- HTML += '</table>';
- return HTMLHeading + HTML;
+ return links.length > 0 ? `${HTMLHeading}${HTML}</table>` : '';
};
- let left = d.left ? d.source : d.target;
- // left is the connection with dir 'in'
- let right = d.left ? d.target : d.source;
- let onode = QDRService.management.topology.nodeInfo()[left.key];
- // loop through all the connections for left, and find the one for right
- let rightIndex = onode['connection'].results.findIndex( function (conn) {
- return utils.valFor(onode['connection'].attributeNames, conn, 'container') === right.routerId;
- });
- if (rightIndex < 0) {
- // we have a connection to a client/service
- rightIndex = +left.resultIndex;
+ let left, right;
+ if (d.left) {
+ left = d.source;
+ right = d.target;
+ } else {
+ left = d.target;
+ right = d.source;
}
- if (isNaN(rightIndex)) {
- // we have a connection to a console
- rightIndex = +right.resultIndex;
+ if (left.normals) {
+ // swap left and right
+ [left, right] = [right, left];
}
+ // left is a router. right is either a router or a client[s]
+ let onode = QDRService.management.topology.nodeInfo()[left.key];
+ // find all the connections for left that go to right
+ let conns = getConnsArray(onode, left.key, right);
+
let HTML = '';
- if (rightIndex >= 0) {
- let conn = onode['connection'].results[rightIndex];
- conn = utils.flatten(onode['connection'].attributeNames, conn);
- let conns = getConnsArray(d, conn);
- if (conns.length === 1) {
- HTML += '<h5>Connection'+(conns.length > 1 ? 's' : '')+'</h5>';
- HTML += '<table class="popupTable"><tr class="header"><td>Security</td><td>Authentication</td><td>Tenant</td><td>Host</td>';
+ HTML += '<h5>Connection'+(conns.length > 1 ? 's' : '')+'</h5>';
+ HTML += '<table class="popupTable"><tr class="header"><td>Security</td><td>Authentication</td><td>Tenant</td><td>Host</td>';
- for (let c=0; c<conns.length; c++) {
- HTML += ('<tr><td>' + utils.connSecurity(conns[c]) + '</td>');
- HTML += ('<td>' + utils.connAuth(conns[c]) + '</td>');
- HTML += ('<td>' + (utils.connTenant(conns[c]) || '--') + '</td>');
- HTML += ('<td>' + conns[c].host + '</td>');
- HTML += '</tr>';
- }
- HTML += '</table>';
- }
- HTML += linksHTML(onode, conn, d);
+ for (let c=0; c<Math.min(conns.length, 10); c++) {
+ HTML += ('<tr><td>' + utils.connSecurity(conns[c]) + '</td>');
+ HTML += ('<td>' + utils.connAuth(conns[c]) + '</td>');
+ HTML += ('<td>' + (utils.connTenant(conns[c]) || '--') + '</td>');
+ HTML += ('<td>' + conns[c].host + '</td>');
+ HTML += '</tr>';
}
+ HTML += '</table>';
+ HTML += linksHTML(onode, conns);
return HTML;
}
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/plugin/js/topology/traffic.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/topology/traffic.js b/console/stand-alone/plugin/js/topology/traffic.js
index a6079fc..ff46d63 100644
--- a/console/stand-alone/plugin/js/topology/traffic.js
+++ b/console/stand-alone/plugin/js/topology/traffic.js
@@ -19,15 +19,25 @@ under the License.
/* global d3 Promise */
-import { ChordData } from '../chord/data.js';
-import { MIN_CHORD_THRESHOLD } from '../chord/matrix.js';
-import { nextHop } from './topoUtils.js';
+import { ChordData } from "../chord/data.js";
+import { MIN_CHORD_THRESHOLD } from "../chord/matrix.js";
+import { nextHop } from "./topoUtils.js";
const transitionDuration = 1000;
-const CHORDFILTERKEY = 'chordFilter';
+const CHORDFILTERKEY = "chordFilter";
-export class Traffic { // eslint-disable-line no-unused-vars
- constructor($scope, $timeout, QDRService, converter, radius, topology, type, prefix) {
+export class Traffic {
+ // eslint-disable-line no-unused-vars
+ constructor(
+ $scope,
+ $timeout,
+ QDRService,
+ converter,
+ radius,
+ topology,
+ type,
+ prefix
+ ) {
$scope.addressColors = {};
this.QDRService = QDRService;
this.type = type; // moving dots or colored path
@@ -53,16 +63,17 @@ export class Traffic { // eslint-disable-line no-unused-vars
}
// remove any animations that are in progress
remove() {
- if (this.vis)
- this.vis.remove();
+ if (this.vis) this.vis.remove();
}
// called when one of the address checkboxes is toggled
setAnimationType(type, converter, radius) {
this.stop();
this.remove();
this.type = type;
- this.vis = type === 'dots' ? new Dots(this, converter, radius) :
- new Congestion(this);
+ this.vis =
+ type === "dots"
+ ? new Dots(this, converter, radius)
+ : new Congestion(this);
}
// called periodically to refresh the traffic flow
doUpdate() {
@@ -70,7 +81,6 @@ export class Traffic { // eslint-disable-line no-unused-vars
}
}
-
/* Base class for congestion and dots visualizations */
class TrafficAnimation {
constructor(traffic) {
@@ -79,18 +89,16 @@ class TrafficAnimation {
nodeIndexFor(nodes, name) {
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i];
- if (node.container === name)
- return i;
+ if (node.container === name) return i;
}
// not found. loop through normals
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i];
if (node.normals) {
- let normalIndex = node.normals.findIndex( function (normal) {
+ let normalIndex = node.normals.findIndex(function(normal) {
return normal.container === name;
});
- if (normalIndex >= 0)
- return i;
+ if (normalIndex >= 0) return i;
}
}
return -1;
@@ -98,15 +106,20 @@ class TrafficAnimation {
}
/* Color the links between router to show how heavily used the links are. */
-class Congestion extends TrafficAnimation{
+class Congestion extends TrafficAnimation {
constructor(traffic) {
super(traffic);
this.init_markerDef();
}
init_markerDef() {
- this.custom_markers_def = d3.select('#SVG_ID').select('defs.custom-markers');
+ this.custom_markers_def = d3
+ .select("#SVG_ID")
+ .select("defs.custom-markers");
if (this.custom_markers_def.empty()) {
- this.custom_markers_def = d3.select('#SVG_ID').append('svg:defs').attr('class', 'custom-markers');
+ this.custom_markers_def = d3
+ .select("#SVG_ID")
+ .append("svg:defs")
+ .attr("class", "custom-markers");
}
}
findResult(node, entity, attribute, value) {
@@ -114,7 +127,10 @@ class Congestion extends TrafficAnimation{
if (attrIndex >= 0) {
for (let i = 0; i < node[entity].results.length; i++) {
if (node[entity].results[i][attrIndex] === value) {
- return this.traffic.QDRService.utilities.flatten(node[entity].attributeNames, node[entity].results[i]);
+ return this.traffic.QDRService.utilities.flatten(
+ node[entity].attributeNames,
+ node[entity].results[i]
+ );
}
}
}
@@ -122,107 +138,146 @@ class Congestion extends TrafficAnimation{
}
doUpdate() {
let self = this;
- this.traffic.QDRService.management.topology.ensureAllEntities([{ entity: 'router.link', force: true }, { entity: 'connection' }], function () {
- let links = {};
- let nodeInfo = self.traffic.QDRService.management.topology.nodeInfo();
- const nodes = self.traffic.topology.nodes.nodes;
- const srv = self.traffic.QDRService;
- // accumulate all the inter-router links in an object
- // keyed by the svgs path id
- for (let nodeId in nodeInfo) {
- let node = nodeInfo[nodeId];
- let nodeLinks = node['router.link'];
- if (!nodeLinks)
- continue;
- for (let n = 0; n < nodeLinks.results.length; n++) {
- let link = srv.utilities.flatten(nodeLinks.attributeNames, nodeLinks.results[n]);
- if (link.linkType !== 'router-control') {
- let f = self.nodeIndexFor(nodes, srv.utilities.nameFromId(nodeId));
- let connection = self.findResult(node, 'connection', 'identity', link.connectionId);
- if (connection) {
- let t = self.nodeIndexFor(nodes, connection.container);
- let little = Math.min(f, t);
- let big = Math.max(f, t);
- if (little >= 0) {
- let key = ['#path', nodes[little].uid(srv),
- nodes[big].uid(srv)].join('-');
- if (!links[key])
- links[key] = [];
- links[key].push(link);
+ this.traffic.QDRService.management.topology.ensureAllEntities(
+ [{ entity: "router.link", force: true }, { entity: "connection" }],
+ function() {
+ let links = {};
+ let nodeInfo = self.traffic.QDRService.management.topology.nodeInfo();
+ const nodes = self.traffic.topology.nodes.nodes;
+ const srv = self.traffic.QDRService;
+ // accumulate all the inter-router links in an object
+ // keyed by the svgs path id
+ for (let nodeId in nodeInfo) {
+ let node = nodeInfo[nodeId];
+ let nodeLinks = node["router.link"];
+ if (!nodeLinks) continue;
+ for (let n = 0; n < nodeLinks.results.length; n++) {
+ let link = srv.utilities.flatten(
+ nodeLinks.attributeNames,
+ nodeLinks.results[n]
+ );
+ if (link.linkType !== "router-control") {
+ let f = self.nodeIndexFor(
+ nodes,
+ srv.utilities.nameFromId(nodeId)
+ );
+ let connection = self.findResult(
+ node,
+ "connection",
+ "identity",
+ link.connectionId
+ );
+ if (connection) {
+ let t = self.nodeIndexFor(nodes, connection.container);
+ let little = Math.min(f, t);
+ let big = Math.max(f, t);
+ if (little >= 0) {
+ let key = [
+ "#path",
+ nodes[little].uid(srv),
+ nodes[big].uid(srv)
+ ].join("-");
+ if (!links[key]) links[key] = [];
+ links[key].push(link);
+ }
}
}
}
}
- }
- // accumulate the colors/directions to be used
- let colors = {};
- for (let key in links) {
- let congestion = self.congestion(links[key]);
- let pathId = key.replace(/\./g, '\\.').replace(/ /g, '\\ ');
- let path = d3.select(pathId);
- if (path && !path.empty()) {
- let dir = path.attr('marker-end') === '' ? 'start' : 'end';
- let small = path.attr('class').indexOf('small') > -1;
- let id = dir + '-' + congestion.substr(1) + (small ? '-s' : '');
- colors[id] = { dir: dir, color: congestion, small: small };
- path
- .classed('traffic', true)
- .attr('marker-start', function (d) {
- return null;
- //return d.left ? 'url(' + self.traffic.prefix + '#' + id + ')' : null;
- })
- .attr('marker-end', function (d) {
- return null;
- //return d.right ? 'url(' + self.traffic.prefix + '#' + id + ')' : null;
- });
- path
- .transition()
- .duration(1000)
- .attr('stroke', congestion);
+ // accumulate the colors/directions to be used
+ let colors = {};
+ for (let key in links) {
+ let congestion = self.congestion(links[key]);
+ let pathId = key.replace(/\./g, "\\.").replace(/ /g, "\\ ");
+ let path = d3.select(pathId);
+ if (path && !path.empty()) {
+ let dir = path.attr("marker-end") === "" ? "start" : "end";
+ let small = path.attr("class").indexOf("small") > -1;
+ let id = dir + "-" + congestion.substr(1) + (small ? "-s" : "");
+ colors[id] = { dir: dir, color: congestion, small: small };
+ path
+ .classed("traffic", true)
+ .attr("marker-start", function() {
+ return null;
+ //return d.left ? 'url(' + self.traffic.prefix + '#' + id + ')' : null;
+ })
+ .attr("marker-end", function() {
+ return null;
+ //return d.right ? 'url(' + self.traffic.prefix + '#' + id + ')' : null;
+ });
+ path
+ .transition()
+ .duration(1000)
+ .attr("stroke", congestion);
+ }
}
+ // create the svg:def that holds the custom markers
+ self.init_markerDef();
+ let colorKeys = Object.keys(colors);
+ let custom_markers = self.custom_markers_def
+ .selectAll("marker")
+ .data(colorKeys, function(d) {
+ return d;
+ });
+ custom_markers
+ .enter()
+ .append("svg:marker")
+ .attr("id", function(d) {
+ return d;
+ })
+ .attr("viewBox", "0 -5 10 10")
+ .attr("refX", function(d) {
+ return colors[d].dir === "end" ? 24 : colors[d].small ? -24 : -14;
+ })
+ .attr("markerWidth", 14)
+ .attr("markerHeight", 14)
+ .attr("markerUnits", "userSpaceOnUse")
+ .attr("orient", "auto")
+ .style("fill", function(d) {
+ return colors[d].color;
+ })
+ .append("svg:path")
+ .attr("d", function(d) {
+ return colors[d].dir === "end"
+ ? "M 0 -5 L 10 0 L 0 5 z"
+ : "M 10 -5 L 0 0 L 10 5 z";
+ });
+ custom_markers.exit().remove();
}
- // create the svg:def that holds the custom markers
- self.init_markerDef();
- let colorKeys = Object.keys(colors);
- let custom_markers = self.custom_markers_def.selectAll('marker')
- .data(colorKeys, function (d) { return d; });
- custom_markers.enter().append('svg:marker')
- .attr('id', function (d) { return d; })
- .attr('viewBox', '0 -5 10 10')
- .attr('refX', function (d) {
- return colors[d].dir === 'end' ? 24 : (colors[d].small) ? -24 : -14;
- })
- .attr('markerWidth', 14)
- .attr('markerHeight', 14)
- .attr('markerUnits', 'userSpaceOnUse')
- .attr('orient', 'auto')
- .style('fill', function (d) { return colors[d].color; })
- .append('svg:path')
- .attr('d', function (d) {
- return colors[d].dir === 'end' ? 'M 0 -5 L 10 0 L 0 5 z' : 'M 10 -5 L 0 0 L 10 5 z';
- });
- custom_markers.exit().remove();
- });
+ );
}
congestion(links) {
let v = 0;
for (let l = 0; l < links.length; l++) {
let link = links[l];
- v = Math.max(v, (link.undeliveredCount + link.unsettledCount) / link.capacity);
+ v = Math.max(
+ v,
+ (link.undeliveredCount + link.unsettledCount) / link.capacity
+ );
}
return this.fillColor(v);
}
fillColor(v) {
- let color = d3.scale.linear().domain([0, 1, 2, 3])
+ let color = d3.scale
+ .linear()
+ .domain([0, 1, 2, 3])
.interpolate(d3.interpolateHcl)
- .range([d3.rgb('#000000'), d3.rgb('#00FF00'), d3.rgb('#FFA500'), d3.rgb('#FF0000')]);
+ .range([
+ d3.rgb("#000000"),
+ d3.rgb("#00FF00"),
+ d3.rgb("#FFA500"),
+ d3.rgb("#FF0000")
+ ]);
return color(Math.max(0, Math.min(3, v)));
}
remove() {
- d3.select('#SVG_ID').selectAll('path.traffic')
- .classed('traffic', false);
- d3.select('#SVG_ID').select('defs.custom-markers')
- .selectAll('marker').remove();
+ d3.select("#SVG_ID")
+ .selectAll("path.traffic")
+ .classed("traffic", false);
+ d3.select("#SVG_ID")
+ .select("defs.custom-markers")
+ .selectAll("marker")
+ .remove();
}
}
@@ -231,55 +286,61 @@ class Congestion extends TrafficAnimation{
class Dots extends TrafficAnimation {
constructor(traffic, converter, radius) {
super(traffic);
- this.excludedAddresses = localStorage[CHORDFILTERKEY] ? JSON.parse(localStorage[CHORDFILTERKEY]) : [];
+ this.excludedAddresses = localStorage[CHORDFILTERKEY]
+ ? JSON.parse(localStorage[CHORDFILTERKEY])
+ : [];
this.radius = radius; // the radius of a router circle
this.lastFlows = {}; // the number of dots animated between routers
this.stopped = false;
this.chordData = new ChordData(this.traffic.QDRService, true, converter); // gets ingressHistogram data
this.chordData.setFilter(this.excludedAddresses);
traffic.$scope.addresses = {};
- this.chordData.getMatrix().then(function () {
- this.traffic.$timeout(function () {
- this.traffic.$scope.addresses = this.chordData.getAddresses();
- for (let address in this.traffic.$scope.addresses) {
- this.fillColor(address);
- }
- }.bind(this));
- }.bind(this));
+ this.chordData.getMatrix().then(
+ function() {
+ this.traffic.$timeout(
+ function() {
+ this.traffic.$scope.addresses = this.chordData.getAddresses();
+ for (let address in this.traffic.$scope.addresses) {
+ this.fillColor(address);
+ }
+ }.bind(this)
+ );
+ }.bind(this)
+ );
// colors
this.colorGen = d3.scale.category10();
- for (let i=0; i<10; i++) {
+ for (let i = 0; i < 10; i++) {
this.colorGen(i);
}
let self = this;
// event notification that an address checkbox has changed
- traffic.$scope.addressFilterChanged = function () {
- self.updateAddresses()
- .then(function () {
- // don't wait for the next polling cycle. update now
- self.traffic.stop();
- self.traffic.start();
- });
+ traffic.$scope.addressFilterChanged = function() {
+ self.updateAddresses().then(function() {
+ // don't wait for the next polling cycle. update now
+ self.traffic.stop();
+ self.traffic.start();
+ });
};
// called by angular when mouse enters one of the address legends
- traffic.$scope.enterLegend = function (address) {
+ traffic.$scope.enterLegend = function(address) {
// fade all flows that aren't for this address
self.fadeOtherAddresses(address);
};
// called when the mouse leaves one of the address legends
- traffic.$scope.leaveLegend = function () {
+ traffic.$scope.leaveLegend = function() {
self.unFadeAll();
};
// clicked on the address name. toggle the address checkbox
- traffic.$scope.addressClick = function (address) {
- self.toggleAddress(address)
- .then(function () {
- self.updateAddresses();
- });
+ traffic.$scope.addressClick = function(address) {
+ self.toggleAddress(address).then(function() {
+ self.updateAddresses();
+ });
};
}
remove() {
- d3.select('#SVG_ID').selectAll('circle.flow').remove();
+ d3.select("#SVG_ID")
+ .selectAll("circle.flow")
+ .remove();
this.lastFlows = {};
this.stopped = true;
}
@@ -290,88 +351,130 @@ class Dots extends TrafficAnimation {
this.excludedAddresses.push(address);
}
localStorage[CHORDFILTERKEY] = JSON.stringify(this.excludedAddresses);
- if (this.chordData)
- this.chordData.setFilter(this.excludedAddresses);
- return new Promise(function (resolve) {
+ if (this.chordData) this.chordData.setFilter(this.excludedAddresses);
+ return new Promise(function(resolve) {
return resolve();
});
}
toggleAddress(address) {
- this.traffic.$scope.addresses[address] = !this.traffic.$scope.addresses[address];
- return new Promise(function (resolve) {
+ this.traffic.$scope.addresses[address] = !this.traffic.$scope.addresses[
+ address
+ ];
+ return new Promise(function(resolve) {
return resolve();
});
}
fadeOtherAddresses(address) {
- d3.selectAll('circle.flow').classed('fade', function (d) {
+ d3.selectAll("circle.flow").classed("fade", function(d) {
return d.address !== address;
});
}
unFadeAll() {
- d3.selectAll('circle.flow').classed('fade', false);
+ d3.selectAll("circle.flow").classed("fade", false);
}
doUpdate() {
let self = this;
this.stopped = false;
// we need the nextHop data to show traffic between routers that are connected by intermediaries
- this.traffic.QDRService.management.topology.ensureAllEntities([{ entity: 'router.node', attrs: ['id', 'nextHop'] }], function () {
- // get the ingressHistogram data for all routers
- self.chordData.getMatrix().then(self.render.bind(self), function (e) {
- console.log('Could not get message histogram' + e);
- });
- });
+ this.traffic.QDRService.management.topology.ensureAllEntities(
+ [{ entity: "router.node", attrs: ["id", "nextHop"] }],
+ function() {
+ // get the ingressHistogram data for all routers
+ self.chordData.getMatrix().then(self.render.bind(self), function(e) {
+ console.log("Could not get message histogram" + e);
+ });
+ }
+ );
}
render(matrix) {
if (this.stopped === false) {
- this.traffic.$timeout(function () {
- this.traffic.$scope.addresses = this.chordData.getAddresses();
- }.bind(this));
+ this.traffic.$timeout(
+ function() {
+ this.traffic.$scope.addresses = this.chordData.getAddresses();
+ }.bind(this)
+ );
// get the rate of message flow between routers
let hops = {}; // every hop between routers that is involved in message flow
let matrixMessages = matrix.matrixMessages();
// the fastest traffic rate gets 3 times as many dots as the slowest
let minmax = matrix.getMinMax();
- let flowScale = d3.scale.linear().domain(minmax).range([1, 1.1]);
+ let flowScale = d3.scale
+ .linear()
+ .domain(minmax)
+ .range([1, 1.1]);
// row is ingress router, col is egress router. Value at [row][col] is the rate
- matrixMessages.forEach(function (row, r) {
- row.forEach(function (val, c) {
- if (val > MIN_CHORD_THRESHOLD) {
- // translate between matrix row/col and node index
- let f = this.nodeIndexFor(this.traffic.topology.nodes.nodes, matrix.rows[r].egress);
- let t = this.nodeIndexFor(this.traffic.topology.nodes.nodes, matrix.rows[r].ingress);
- let address = matrix.getAddress(r, c);
- if (r !== c) {
- // accumulate the hops between the ingress and egress routers
- nextHop(this.traffic.topology.nodes.nodes[f],
- this.traffic.topology.nodes.nodes[t],
- this.traffic.topology.nodes,
- this.traffic.topology.links,
- this.traffic.QDRService,
- this.traffic.topology.nodes.nodes[f],
- function (link, fnode, tnode) {
- let key = '-' + link.uid;
- let back = fnode.index < tnode.index;
- if (!hops[key])
- hops[key] = [];
- hops[key].push({ val: val, back: back, address: address });
- });
- }
- // Find the senders connected to nodes[f] and the receivers connected to nodes[t]
- // and add their links to the animation
- this.addClients(hops, this.traffic.topology.nodes.nodes, f, val, true, address);
- this.addClients(hops, this.traffic.topology.nodes.nodes, t, val, false, address);
- }
- }.bind(this));
- }.bind(this));
+ matrixMessages.forEach(
+ function(row, r) {
+ row.forEach(
+ function(val, c) {
+ if (val > MIN_CHORD_THRESHOLD) {
+ // translate between matrix row/col and node index
+ let f = this.nodeIndexFor(
+ this.traffic.topology.nodes.nodes,
+ matrix.rows[r].egress
+ );
+ let t = this.nodeIndexFor(
+ this.traffic.topology.nodes.nodes,
+ matrix.rows[r].ingress
+ );
+ let address = matrix.getAddress(r, c);
+ if (r !== c) {
+ // accumulate the hops between the ingress and egress routers
+ nextHop(
+ this.traffic.topology.nodes.nodes[f],
+ this.traffic.topology.nodes.nodes[t],
+ this.traffic.topology.nodes,
+ this.traffic.topology.links,
+ this.traffic.QDRService,
+ this.traffic.topology.nodes.nodes[f],
+ function(link, fnode, tnode) {
+ let key = "-" + link.uid;
+ let back = fnode.index < tnode.index;
+ if (!hops[key]) hops[key] = [];
+ hops[key].push({
+ val: val,
+ back: back,
+ address: address
+ });
+ }
+ );
+ }
+ // Find the senders connected to nodes[f] and the receivers connected to nodes[t]
+ // and add their links to the animation
+ this.addClients(
+ hops,
+ this.traffic.topology.nodes.nodes,
+ f,
+ val,
+ true,
+ address
+ );
+ this.addClients(
+ hops,
+ this.traffic.topology.nodes.nodes,
+ t,
+ val,
+ false,
+ address
+ );
+ }
+ }.bind(this)
+ );
+ }.bind(this)
+ );
// for each link between routers that has traffic, start an animation
let keep = {};
for (let id in hops) {
let hop = hops[id];
for (let h = 0; h < hop.length; h++) {
let ahop = hop[h];
- let pathId = id.replace(/\./g, '\\.').replace(/ /g, '\\ ');
- let flowId = id.replace(/\./g, '').replace(/ /g, '') + '-' + this.addressIndex(this, ahop.address) + (ahop.back ? 'b' : '');
- let path = d3.select('#path' + pathId);
+ let pathId = id.replace(/\./g, "\\.").replace(/ /g, "\\ ");
+ let flowId =
+ id.replace(/\./g, "").replace(/ /g, "") +
+ "-" +
+ this.addressIndex(this, ahop.address) +
+ (ahop.back ? "b" : "");
+ let path = d3.select("#path" + pathId);
// start the animation. If the animation is already running, this will have no effect
this.startAnimation(path, flowId, ahop, flowScale(ahop.val));
keep[flowId] = true;
@@ -381,7 +484,9 @@ class Dots extends TrafficAnimation {
for (let id in this.lastFlows) {
if (this.lastFlows[id] && !keep[id]) {
this.lastFlows[id] = 0;
- d3.select('#SVG_ID').selectAll('circle.flow' + id).remove();
+ d3.select("#SVG_ID")
+ .selectAll("circle.flow" + id)
+ .remove();
}
}
}
@@ -389,11 +494,15 @@ class Dots extends TrafficAnimation {
// animate the d3 selection (flow) along the given path
animateFlow(flow, path, count, back, rate) {
let l = path.node().getTotalLength();
- flow.transition()
- .ease('easeLinear')
- .duration(l * 10 / rate)
- .attrTween('transform', this.translateDots(this.radius, path, count, back))
- .each('end', () => {
+ flow
+ .transition()
+ .ease("easeLinear")
+ .duration((l * 10) / rate)
+ .attrTween(
+ "transform",
+ this.translateDots(this.radius, path, count, back)
+ )
+ .each("end", () => {
if (this.stopped === false) {
this.animateFlow(flow, path, count, back, rate);
}
@@ -401,12 +510,12 @@ class Dots extends TrafficAnimation {
}
// create dots along the path between routers
startAnimation(selection, id, hop, rate) {
- if (selection.empty())
- return;
+ if (selection.empty()) return;
this.animateDots(selection, id, hop, rate);
}
animateDots(path, id, hop, rate) {
- let back = hop.back, address = hop.address;
+ let back = hop.back,
+ address = hop.address;
// the density of dots is determined by the rate of this traffic relative to the other traffic
let len = Math.max(Math.floor(path.node().getTotalLength() / 50), 1);
let dots = [];
@@ -415,24 +524,29 @@ class Dots extends TrafficAnimation {
}
// keep track of the number of dots for each link. If the length of the link is changed,
// re-create the animation
- if (!this.lastFlows[id])
- this.lastFlows[id] = len;
+ if (!this.lastFlows[id]) this.lastFlows[id] = len;
else {
if (this.lastFlows[id] !== len) {
this.lastFlows[id] = len;
- d3.select('#SVG_ID').selectAll('circle.flow' + id).remove();
+ d3.select("#SVG_ID")
+ .selectAll("circle.flow" + id)
+ .remove();
}
}
- let flow = d3.select('#SVG_ID').selectAll('circle.flow' + id)
- .data(dots, function (d) { return d.i + d.address; });
+ let flow = d3
+ .select("#SVG_ID")
+ .selectAll("circle.flow" + id)
+ .data(dots, function(d) {
+ return d.i + d.address;
+ });
let circles = flow
- .enter().append('circle')
- .attr('class', 'flow flow' + id)
- .attr('fill', this.fillColor(address))
- .attr('r', 5);
+ .enter()
+ .append("circle")
+ .attr("class", "flow flow" + id)
+ .attr("fill", this.fillColor(address))
+ .attr("r", 5);
this.animateFlow(circles, path, dots.length, back, rate);
- flow.exit()
- .remove();
+ flow.exit().remove();
}
fillColor(n) {
if (!(n in this.traffic.$scope.addressColors)) {
@@ -441,51 +555,53 @@ class Dots extends TrafficAnimation {
}
return this.traffic.$scope.addressColors[n];
}
- // find the link that carries traffic for this address
+ // find the link that carries traffic for this address
// going to nodes[f] if sender is true
// coming from nodes[f] if sender if false.
// Add the link's id to the hops array
addClients(hops, nodes, f, val, sender, address) {
- const cdir = sender ? 'out' : 'in';
- const uuid = nodes[f].uid(this.traffic.QDRService);
+ if (!nodes[f])
+ return;
+ const cdir = sender ? "out" : "in";
+ const uuid = nodes[f].uid();
const key = nodes[f].key;
- const links = this.traffic.QDRService.management.topology._nodeInfo[key]['router.link'];
+ const links = this.traffic.QDRService.management.topology._nodeInfo[key][
+ "router.link"
+ ];
if (links) {
- const ilt = links.attributeNames.indexOf('linkType');
- const ioa = links.attributeNames.indexOf('owningAddr');
- const ici = links.attributeNames.indexOf('connectionId');
- const ild = links.attributeNames.indexOf('linkDir');
- let foundLinks = links.results.filter( function (l) {
- return (l[ilt] === 'endpoint' || l[ilt] === 'edge-downlink') &&
+ const ilt = links.attributeNames.indexOf("linkType");
+ const ioa = links.attributeNames.indexOf("owningAddr");
+ const ici = links.attributeNames.indexOf("connectionId");
+ const ild = links.attributeNames.indexOf("linkDir");
+ let foundLinks = links.results.filter(function(l) {
+ return (
+ (l[ilt] === "endpoint" || l[ilt] === "edge-downlink") &&
address === this.traffic.QDRService.utilities.addr_text(l[ioa]) &&
- l[ild] === cdir;
+ l[ild] === cdir
+ );
}, this);
// we now have the links involved in traffic for this address that
// ingress/egress to/from this router (f).
- // Now find the created node that the link is to
- for (let linkIndex=0; linkIndex<foundLinks.length; linkIndex++) {
- let nodeIndex = nodes.findIndex( function (node) {
- if (node.normals && node.key === key && (node.cdir === cdir || node.cdir === 'both')) {
- return node.normals.some( function (normal) {
- return normal.connectionId == foundLinks[linkIndex][ici];
- });
- } else if (node.alsoConnectsTo) {
- return node.alsoConnectsTo.some( function (ac2) {
- return ac2.key === key && ac2.connectionId === foundLinks[linkIndex][ici] &&
- (ac2.dir === cdir || ac2.dir === 'both');
- });
+ // Now find the created node that each link is associated with
+ for (let linkIndex = 0; linkIndex < foundLinks.length; linkIndex++) {
+ // use .some so the loop stops at the 1st match
+ nodes.some( function (node) {
+ if (
+ node.normals &&
+ node.normals.some(function(normal) {
+ return testNode(normal, key, cdir, foundLinks[linkIndex][ici]);
+ })
+ ) {
+ // one of the normals for this node has the traffic
+ const uuid2 = node.uid();
+ const key = ["", uuid, uuid2].join("-");
+ if (!hops[key])
+ hops[key] = [];
+ hops[key].push({ val: val, back: !sender, address: address });
+ return true;
}
- else
- return false;
+ return false;
});
- if (nodeIndex >= 0) {
- // one of the normals for this node has the traffic
- const uuid2 = nodes[nodeIndex].uid(this.traffic.QDRService);
- const key = ['', uuid, uuid2].join('-');
- if (!hops[key])
- hops[key] = [];
- hops[key].push({ val: val, back: !sender, address: address });
- }
}
}
}
@@ -496,20 +612,36 @@ class Dots extends TrafficAnimation {
translateDots(radius, path, count, back) {
let pnode = path.node();
// will be called for each element in the flow selection (for each dot)
- return function (d) {
+ return function(d) {
// will be called with t going from 0 to 1 for each dot
- return function (t) {
+ return function(t) {
// start the points at different positions depending on their value (d)
let tt = t * 1000;
- let f = ((tt + (d.i * 1000 / count)) % 1000) / 1000;
- if (back)
- f = 1 - f;
+ let f = ((tt + (d.i * 1000) / count) % 1000) / 1000;
+ if (back) f = 1 - f;
// l needs to be calculated each tick because the path's length might be changed during the animation
let l = pnode.getTotalLength();
let p = pnode.getPointAtLength(f * l);
- return 'translate(' + p.x + ',' + p.y + ')';
+ return "translate(" + p.x + "," + p.y + ")";
};
};
}
}
+// see if this node, or any of the nodes it also connects to
+// match the key, dir, and connectionId
+let testNode = function(node, key, dir, connectionId) {
+ // does the node match
+ if (
+ node.key === key &&
+ node.connectionId == connectionId &&
+ (node.cdir === dir || node.cdir === "both")
+ )
+ return true;
+ if (!node.alsoConnectsTo)
+ return false;
+ // do any of the alsoConnectsTo nodes match
+ return node.alsoConnectsTo.some(function(ac2) {
+ return testNode(ac2, key, dir, connectionId);
+ });
+};
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/test/links.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/test/links.js b/console/stand-alone/test/links.js
index f6aff44..c3aad88 100644
--- a/console/stand-alone/test/links.js
+++ b/console/stand-alone/test/links.js
@@ -27,11 +27,11 @@ import { QDRService } from '../plugin/js/qdrService.js';
class Log {
constructor() {
}
- log (msg) {}
- debug (msg) {}
- error (msg) {}
- info (msg) {}
- warn (msg) {}
+ log (msg) {console.log(msg);}
+ debug (msg) {console.log(msg);}
+ error (msg) {console.log(msg);}
+ info (msg) {console.log(msg);}
+ warn (msg) {console.log(msg);}
}
var log = new Log();
var loc = {protocol: function () { return 'http://';}};
@@ -85,7 +85,7 @@ describe('Links', function() {
});
describe('#initializes', function() {
it('should initialize', function() {
- links.initializeLinks(nodeInfo, nodes, unknowns, {}, width);
+ links.initialize(nodeInfo, nodes, unknowns, {}, width);
assert.equal(links.links.length, 10);
});
});
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/tslint.json
----------------------------------------------------------------------
diff --git a/console/stand-alone/tslint.json b/console/stand-alone/tslint.json
index ad645d3..06ee45b 100644
--- a/console/stand-alone/tslint.json
+++ b/console/stand-alone/tslint.json
@@ -27,13 +27,7 @@ under the License.
"max-line-length": [true, 140],
"no-arg": true,
"no-bitwise": true,
- "no-console": [true,
- "debug",
- "info",
- "time",
- "timeEnd",
- "trace"
- ],
+ "no-console": [true, "debug", "info", "time", "timeEnd", "trace"],
"no-construct": true,
"no-debugger": true,
"no-duplicate-variable": true,
@@ -43,22 +37,24 @@ under the License.
"no-trailing-whitespace": true,
"no-unused-variable": false,
//"no-use-before-declare": true,
- "one-line": [true,
+ "one-line": [
+ true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
- "quotemark": [true, "single"],
+ "quotemark": [true, "double"],
"radix": true,
"semicolon": true,
"triple-equals": [true, "allow-null-check"],
"variable-name": false,
- "whitespace": [true,
+ "whitespace": [
+ true,
"check-branch",
"check-decl",
"check-operator",
"check-separator"
]
}
-}
\ No newline at end of file
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[2/2] qpid-dispatch git commit: DISPATCH-1195 Periodically update
popup detail on topology page
Posted by ea...@apache.org.
DISPATCH-1195 Periodically update popup detail on topology page
Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/55b7ae55
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/55b7ae55
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/55b7ae55
Branch: refs/heads/master
Commit: 55b7ae55e4f4c2f89f25a928fdd0e98049372f5e
Parents: 3adde8e
Author: Ernest Allen <ea...@redhat.com>
Authored: Mon Dec 3 10:48:50 2018 -0500
Committer: Ernest Allen <ea...@redhat.com>
Committed: Mon Dec 3 10:48:50 2018 -0500
----------------------------------------------------------------------
console/.eslintrc.json | 53 +-
console/stand-alone/main.js | 2 +-
console/stand-alone/plugin/css/dispatch.css | 3 +
.../plugin/html/tmplClientDetail.html | 258 +++++---
console/stand-alone/plugin/js/amqp/topology.js | 434 +++++++------
console/stand-alone/plugin/js/amqp/utilities.js | 8 +-
console/stand-alone/plugin/js/chord/data.js | 3 +
.../plugin/js/dlgDetailController.js | 207 +++++--
console/stand-alone/plugin/js/topology/links.js | 345 +++++------
console/stand-alone/plugin/js/topology/map.js | 4 +
console/stand-alone/plugin/js/topology/nodes.js | 416 ++++++++-----
.../plugin/js/topology/qdrTopology.js | 79 ++-
.../stand-alone/plugin/js/topology/topoUtils.js | 112 ++--
.../stand-alone/plugin/js/topology/traffic.js | 604 +++++++++++--------
console/stand-alone/test/links.js | 12 +-
console/stand-alone/tslint.json | 18 +-
16 files changed, 1470 insertions(+), 1088 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/.eslintrc.json
----------------------------------------------------------------------
diff --git a/console/.eslintrc.json b/console/.eslintrc.json
index 64d913c..f9c80bb 100644
--- a/console/.eslintrc.json
+++ b/console/.eslintrc.json
@@ -1,35 +1,22 @@
{
- "env": {
- "browser": true,
- "node": true,
- "amd": true,
- "jquery": true
- },
- "extends": "eslint:recommended",
- "parserOptions": {
- "ecmaVersion": 6,
- "sourceType": "module",
- "ecmaFeatures": {
- "jsx": true
- }
- },
- "rules": {
- "indent": [
- "error",
- 2
- ],
- "linebreak-style": [
- "error",
- "unix"
- ],
- "quotes": [
- "error",
- "single"
- ],
- "semi": [
- "error",
- "always"
- ],
- "no-console": "off"
+ "env": {
+ "browser": true,
+ "node": true,
+ "amd": true,
+ "jquery": true
+ },
+ "extends": "eslint:recommended",
+ "parserOptions": {
+ "ecmaVersion": 6,
+ "sourceType": "module",
+ "ecmaFeatures": {
+ "jsx": true
}
-}
\ No newline at end of file
+ },
+ "rules": {
+ "indent": ["error", 2],
+ "linebreak-style": ["error", "unix"],
+ "semi": ["error", "always"],
+ "no-console": "off"
+ }
+}
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/main.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/main.js b/console/stand-alone/main.js
index a02b87a..4cf2d32 100644
--- a/console/stand-alone/main.js
+++ b/console/stand-alone/main.js
@@ -90,7 +90,7 @@ import { posint } from './plugin/js/posintDirective.js';
QDR.module.filter('to_trusted', ['$sce', function($sce){
return function(text) {
- return $sce.trustAsHtml(text);
+ return $sce.trustAsHtml(text+'');
};
}]);
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/plugin/css/dispatch.css
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/css/dispatch.css b/console/stand-alone/plugin/css/dispatch.css
index 000b961..6b0ef2e 100644
--- a/console/stand-alone/plugin/css/dispatch.css
+++ b/console/stand-alone/plugin/css/dispatch.css
@@ -1064,6 +1064,9 @@ svg {
circle.node.inter-router {
fill: #EAEAEA;
}
+ circle.node.normal {
+ fill: #FAFAFA;
+ }
circle.node.normal.in {
fill: #F0F000;
}
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/plugin/html/tmplClientDetail.html
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/html/tmplClientDetail.html b/console/stand-alone/plugin/html/tmplClientDetail.html
index b2ef1f9..d96cda3 100644
--- a/console/stand-alone/plugin/html/tmplClientDetail.html
+++ b/console/stand-alone/plugin/html/tmplClientDetail.html
@@ -46,6 +46,64 @@
div.details span.right {
float: right;
}
+
+ div.sub-table {
+ border: 1px solid #CCCCCC;
+ margin: 1em 0;
+ }
+ div.sub-table-row.body {
+ background-color: #FFFFFF;
+ }
+ div.sub-table-row {
+ border-bottom: 1px solid #CCCCCC;
+ }
+ div.sub-table-row:last-child {
+ border-bottom: 0px;
+ }
+ div.sub-table-row.header {
+ background-clip: padding-box;
+ background-color: #f5f5f5;
+ background-image: linear-gradient(to bottom,#fafafa 0,#ededed 100%);
+ background-repeat: repeat-x;
+ }
+
+ span.sub-table-col {
+ display: inline-block;
+ border-right: 1px solid #CCCCCC;
+ padding: 2px 10px 3px;
+ }
+ span.sub-table-col:last-child {
+ border-right: 0px;
+ }
+
+
+ dl.sub-table {
+ display: grid;
+ grid-template-columns: max-content auto;
+ margin-left: 0.5em;
+ background-color: white;
+ border: 1px solid #CCCCCC;
+ }
+
+ dl.sub-table dt {
+ grid-column-start: 1;
+ padding: 3px 3em 3px 10px;
+ border-bottom: 1px solid #CCCCCC;
+ border-right: 1px solid #CCCCCC;
+ }
+
+ dl.sub-table dd {
+ grid-column-start: 2;
+ padding: 3px 10px;
+ border-bottom: 1px solid #CCCCCC;
+ }
+ dl.sub-table dd:last-child, dl.sub-table dt:last-of-type {
+ border-bottom: 0px;
+ }
+
+ dl.sub-table dd.odd, dl.sub-table dt.odd {
+ background-color: #f0f0f0;
+ }
</style>
<!--
This is the template for the client detail popup displayed when a group
@@ -78,47 +136,47 @@
<th>Links</th>
</tr>
</thead>
- <tr ng-repeat-start="(key, value) in detail.infoPerId"
+ <tr ng-repeat-start="info in detail.infoPerId"
ng-class="{even: $even, odd: $odd}"
- ng-click="expandClicked(key)">
+ ng-click="expandClicked(info.container)">
<td class="expander">
<span class="fa"
- ng-class="expanded(key) ? 'fa-angle-down' : 'fa-angle-right'"
+ ng-class="expanded(info.container) ? 'fa-angle-down' : 'fa-angle-right'"
></span>
</td>
- <td>{{key}}</td><!-- Id -->
- <td class="right">{{value.encrypted}}</td>
- <td class="right">{{value.host}}</td>
- <td class="right">{{value.linkCount}}</td>
+ <td>{{info.container}}</td><!-- Id -->
+ <td class="right">{{info.encrypted}}</td>
+ <td class="right">{{info.host}}</td>
+ <td class="right">{{info.linkCount}}</td>
</tr>
<tr ng-repeat-end
- ng-class="{hiddenRow: !expanded(key)}"
- ng-click="expandClicked(key)"
+ ng-class="{hiddenRow: !expanded(info.container)}"
+ ng-click="expandClicked(info.container)"
>
<td colspan="6">
- <table class="table table-striped table-bordered dataTable no-footer">
- <thead>
- <tr>
- <td ng-repeat="field in linkFields">
- {{field | humanify}}
- </td>
- </tr>
- </thead>
- <tbody>
- <tr ng-repeat="link in value.links">
- <td ng-repeat="field in linkFields">
- {{link[field] | pretty }}
- </td>
- </tr>
- </tbody>
- </table>
+ <div class="sub-table">
+ <div class="sub-table-row header">
+ <span class="sub-table-col client"
+ ng-style="{ width: fieldWidth(field, info.sizes) }"
+ ng-repeat="field in fields.linkFields.cols">
+ {{field | humanify}}
+ </span>
+ </div>
+ <div class="sub-table-row body" ng-repeat="link in info.links">
+ <span class="sub-table-col client"
+ ng-style="{ width: fieldWidth(field, info.sizes) }"
+ ng-repeat="field in fields.linkFields.cols">
+ {{link[field] | pretty}}
+ </span>
+ </div>
+ </div>
</td>
</tr>
</table>
</script>
<script type="text/ng-template" id="consoles.html">
- here be console info
+
</script>
<script type="text/ng-template" id="edgeRouters.html">
@@ -134,84 +192,94 @@
<th>Accepted</td>
</tr>
</thead>
- <tr ng-repeat-start="(key, value) in detail.infoPerId"
+ <tr ng-repeat-start="info in detail.infoPerId"
ng-class="{even: $even, odd: $odd}"
- ng-click="expandClicked(key)">
+ ng-click="expandClicked(info.name)">
<td class="expander">
<span class="fa"
- ng-class="expanded(key) ? 'fa-angle-down' : 'fa-angle-right'"
+ ng-class="expanded(info.name) ? 'fa-angle-down' : 'fa-angle-right'"
></span>
</td>
- <td>{{key}}</td><!-- Id -->
- <td class="right">{{value.linkRouteCount}}</td>
- <td class="right">{{value.autoLinkCount}}</td>
- <td class="right">{{value.connectionCount}}</td>
- <td class="right">{{value.addrCount}}</td>
- <td class="right">{{value.acceptedDeliveries | pretty}}</td>
+ <td>{{info.name}}</td><!-- Id -->
+ <td class="right">{{info.linkRouteCount}}</td>
+ <td class="right">{{info.autoLinkCount}}</td>
+ <td class="right">{{info.connectionCount}}</td>
+ <td class="right">{{info.addrCount}}</td>
+ <td class="right">{{info.acceptedDeliveries | pretty}}</td>
</tr>
<tr ng-repeat-end
- ng-class="{hiddenRow: !expanded(key)}"
- ng-click="expandClicked(key)"
+ ng-class="{hiddenRow: !expanded(info.name)}"
+ ng-click="expandClicked(info.name)"
>
<td colspan="7">
- <h4>Edge router details</h4>
- <table class="table table-striped table-bordered dataTable no-footer">
- <tr ng-repeat="field in detailFields">
- <td>{{field | humanify}}</td>
- <td>{{value[field] | pretty}}</td>
- </tr>
- </table>
- <h4>Link routes</h4>
- <table class="table table-striped table-bordered dataTable no-footer">
- <thead>
- <tr>
- <td ng-repeat="field in linkRouteFields">
- {{field | humanify}}
- </td>
- </tr>
- </thead>
- <tbody>
- <tr ng-repeat="link in value.linkRoutes">
- <td ng-repeat="field in linkRouteFields">
- {{link[field] | pretty }}
- </td>
- </tr>
- </tbody>
- </table>
- <h4>Autolinks</h4>
- <table class="table table-striped table-bordered dataTable no-footer">
- <thead>
- <tr>
- <td ng-repeat="field in autoLinkFields">
- {{field | humanify}}
- </td>
- </tr>
- </thead>
- <tbody>
- <tr ng-repeat="link in value.autoLinks">
- <td ng-repeat="field in autoLinkFields">
- {{link[field] | pretty }}
- </td>
- </tr>
- </tbody>
- </table>
- <h4>Addresses</h4>
- <table class="table table-striped table-bordered dataTable no-footer">
- <thead>
- <tr>
- <td ng-repeat="field in addressFields">
- {{field | humanify}}
- </td>
- </tr>
- </thead>
- <tbody>
- <tr ng-repeat="link in value.addresses">
- <td ng-repeat="field in addressFields">
- {{link[field] | pretty }}
- </td>
- </tr>
- </tbody>
- </table>
+ <h4>Details for edge router {{info.name}}</h4>
+ <dl class="sub-table">
+ <dt ng-repeat-start="field in fields.detailFields.cols">
+ {{field | humanify}}
+ </dt>
+ <dd ng-repeat-end>
+ {{info[field] | pretty}}
+ </dd>
+ </dl>
+
+ <h4>Link routes</h4>
+ <div class="sub-table">
+ <div class="sub-table-row header">
+ <span
+ class="sub-table-col client"
+ ng-style="{ width: fieldWidth(field, info.linkRouteSizes) }"
+ ng-repeat="field in fields.linkRouteFields.cols">
+ {{field | humanify}}
+ </span>
+ </div>
+ <div class="sub-table-row body" ng-repeat="link in info.linkRoutes">
+ <span
+ class="sub-table-col client"
+ ng-style="{ width: fieldWidth(field, info.linkRouteSizes) }"
+ ng-repeat="field in fields.linkRouteFields.cols">
+ {{link[field] | pretty}}
+ </span>
+ </div>
+ </div>
+
+ <h4>Autolinks</h4>
+ <div class="sub-table">
+ <div class="sub-table-row header">
+ <span
+ class="sub-table-col client"
+ ng-style="{ width: fieldWidth(field, info.autoLinkSizes) }"
+ ng-repeat="field in fields.autoLinkFields.cols">
+ {{field | humanify}}
+ </span>
+ </div>
+ <div class="sub-table-row body" ng-repeat="link in info.autoLinks">
+ <span
+ class="sub-table-col client"
+ ng-style="{ width: fieldWidth(field, info.autoLinkSizes) }"
+ ng-repeat="field in fields.autoLinkFields.cols">
+ {{link[field] | pretty}}
+ </span>
+ </div>
+ </div>
+ <h4>Addresses</h4>
+ <div class="sub-table">
+ <div class="sub-table-row header">
+ <span
+ class="sub-table-col client"
+ ng-style="{ width: fieldWidth(field, info.addressSizes) }"
+ ng-repeat="field in fields.addressFields.cols">
+ {{field | humanify}}
+ </span>
+ </div>
+ <div class="sub-table-row body" ng-repeat="link in info.addresses">
+ <span
+ class="sub-table-col client"
+ ng-style="{ width: fieldWidth(field, info.addressSizes) }"
+ ng-repeat="field in fields.addressFields.cols">
+ {{link[field] | pretty}}
+ </span>
+ </div>
+ </div>
</td>
</tr>
</table>
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/plugin/js/amqp/topology.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/amqp/topology.js b/console/stand-alone/plugin/js/amqp/topology.js
index 8c88e50..02f1fe9 100644
--- a/console/stand-alone/plugin/js/amqp/topology.js
+++ b/console/stand-alone/plugin/js/amqp/topology.js
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-/* global Promise d3 */
+/* global Promise d3 Set */
-import { utils } from './utilities.js';
+import { utils } from "./utilities.js";
class Topology {
constructor(connectionManager) {
@@ -32,13 +32,12 @@ class Topology {
this.updating = false;
}
addUpdatedAction(key, action) {
- if (typeof action === 'function') {
+ if (typeof action === "function") {
this.updatedActions[key] = action;
}
}
delUpdatedAction(key) {
- if (key in this.updatedActions)
- delete this.updatedActions[key];
+ if (key in this.updatedActions) delete this.updatedActions[key];
}
executeUpdatedActions(error) {
for (var action in this.updatedActions) {
@@ -52,7 +51,7 @@ class Topology {
}
}
addUpdateEntities(entityAttribs) {
- if (Object.prototype.toString.call(entityAttribs) !== '[object Array]') {
+ if (Object.prototype.toString.call(entityAttribs) !== "[object Array]") {
entityAttribs = [entityAttribs];
}
for (var i = 0; i < entityAttribs.length; i++) {
@@ -61,12 +60,10 @@ class Topology {
}
}
on(eventName, fn, key) {
- if (eventName === 'updated')
- this.addUpdatedAction(key, fn);
+ if (eventName === "updated") this.addUpdatedAction(key, fn);
}
unregister(eventName, key) {
- if (eventName === 'updated')
- this.delUpdatedAction(key);
+ if (eventName === "updated") this.delUpdatedAction(key);
}
nodeInfo() {
return this._nodeInfo;
@@ -76,14 +73,17 @@ class Topology {
for (let rId in this._nodeInfo) {
if (!workSet.has(rId)) {
// mark any routers that went away since the last request as removed
- this._nodeInfo[rId]['removed'] = true;
+ this._nodeInfo[rId]["removed"] = true;
} else {
- if (this._nodeInfo[rId]['removed'])
- delete this._nodeInfo[rId]['removed'];
+ if (this._nodeInfo[rId]["removed"])
+ delete this._nodeInfo[rId]["removed"];
// copy entities
for (let entity in workInfo[rId]) {
- if (!this._nodeInfo[rId][entity] ||
- (workInfo[rId][entity]['timestamp']+'' > this._nodeInfo[rId][entity]['timestamp']+'')) {
+ if (
+ !this._nodeInfo[rId][entity] ||
+ workInfo[rId][entity]["timestamp"] + "" >
+ this._nodeInfo[rId][entity]["timestamp"] + ""
+ ) {
this._nodeInfo[rId][entity] = utils.copy(workInfo[rId][entity]);
}
}
@@ -97,111 +97,148 @@ class Topology {
}
}
}
+ // remove any nodes that don't have connection info
+ purge() {
+ for (let id in this._nodeInfo) {
+ let node = this._nodeInfo[id];
+ if (node.removed) {
+ delete this._nodeInfo[id];
+ }
+ }
+ }
get() {
- return new Promise((function (resolve, reject) {
- this.connection.sendMgmtQuery('GET-MGMT-NODES')
- .then((function (results) {
- let routerIds = results.response;
- if (Object.prototype.toString.call(routerIds) === '[object Array]') {
- // if there is only one node, it will not be returned
- if (routerIds.length === 0) {
- var parts = this.connection.getReceiverAddress().split('/');
- parts[parts.length - 1] = '$management';
- routerIds.push(parts.join('/'));
- }
- let finish = function (workInfo) {
- this.saveResults(workInfo);
- this.onDone(this._nodeInfo);
- resolve(this._nodeInfo);
- };
- let connectedToEdge = function (response, workInfo) {
- let routerId = null;
- if (response.length === 1) {
- let parts = response[0].split('/');
- // we are connected to an edge router
- if (parts[1] === '_edge') {
- // find the role:edge connection
- let conn = workInfo[response[0]].connection;
- if (conn) {
- let roleIndex = conn.attributeNames.indexOf('role');
- for (let i=0; i<conn.results.length; i++) {
- if (conn.results[i][roleIndex] === 'edge') {
- let container = utils.valFor(conn.attributeNames, conn.results[i], 'container');
- return utils.idFromName(container, '_topo');
- }
- }
- }
- }
+ return new Promise(
+ function(resolve, reject) {
+ this.connection.sendMgmtQuery("GET-MGMT-NODES").then(
+ function(results) {
+ let routerIds = results.response;
+ if (
+ Object.prototype.toString.call(routerIds) === "[object Array]"
+ ) {
+ // if there is only one node, it will not be returned
+ if (routerIds.length === 0) {
+ var parts = this.connection.getReceiverAddress().split("/");
+ parts[parts.length - 1] = "$management";
+ routerIds.push(parts.join("/"));
}
- return routerId;
- };
- this.doget(routerIds)
- .then( function (workInfo) {
- // test for edge case
- let routerId = connectedToEdge(routerIds, workInfo);
- if (routerId) {
- this.connection.sendMgmtQuery('GET-MGMT-NODES', routerId)
- .then((function (results) {
- let response = results.response;
- if (Object.prototype.toString.call(response) === '[object Array]') {
- // special case of edge case:
- // we are connected to an edge router that is connected to
- // a router that is not connected to any other interior routers
- if (response.length === 0) {
- response = [routerId];
+ let finish = function(workInfo) {
+ this.saveResults(workInfo);
+ this.onDone(this._nodeInfo);
+ resolve(this._nodeInfo);
+ };
+ let connectedToEdge = function(response, workInfo) {
+ let routerId = null;
+ if (response.length === 1) {
+ let parts = response[0].split("/");
+ // we are connected to an edge router
+ if (parts[1] === "_edge") {
+ // find the role:edge connection
+ let conn = workInfo[response[0]].connection;
+ if (conn) {
+ let roleIndex = conn.attributeNames.indexOf("role");
+ for (let i = 0; i < conn.results.length; i++) {
+ if (conn.results[i][roleIndex] === "edge") {
+ let container = utils.valFor(
+ conn.attributeNames,
+ conn.results[i],
+ "container"
+ );
+ return utils.idFromName(container, "_topo");
}
- this.doget(response)
- .then( function (workInfo) {
- finish.call(this, workInfo);
- }.bind(this));
-
}
- }).bind(this));
- } else {
- finish.call(this, workInfo);
+ }
+ }
}
- }.bind(this));
+ return routerId;
+ };
+ this.doget(routerIds).then(
+ function(workInfo) {
+ // test for edge case
+ let routerId = connectedToEdge(routerIds, workInfo);
+ if (routerId) {
+ this.connection
+ .sendMgmtQuery("GET-MGMT-NODES", routerId)
+ .then(
+ function(results) {
+ let response = results.response;
+ if (
+ Object.prototype.toString.call(response) ===
+ "[object Array]"
+ ) {
+ // special case of edge case:
+ // we are connected to an edge router that is connected to
+ // a router that is not connected to any other interior routers
+ if (response.length === 0) {
+ response = [routerId];
+ }
+ this.doget(response).then(
+ function(workInfo) {
+ finish.call(this, workInfo);
+ }.bind(this)
+ );
+ }
+ }.bind(this)
+ );
+ } else {
+ finish.call(this, workInfo);
+ }
+ }.bind(this)
+ );
+ }
+ }.bind(this),
+ function(error) {
+ reject(error);
}
- }).bind(this), function (error) {
- reject(error);
- });
- }).bind(this));
+ );
+ }.bind(this)
+ );
}
doget(ids) {
- return new Promise((function (resolve) {
- let workInfo = {};
- for (var i = 0; i < ids.length; ++i) {
- workInfo[ids[i]] = {};
- }
- var gotResponse = function (nodeName, entity, response) {
- workInfo[nodeName][entity] = response;
- workInfo[nodeName][entity]['timestamp'] = new Date();
- };
- var q = d3.queue(this.connection.availableQeueuDepth());
- for (var id in workInfo) {
- for (var entity in this.entityAttribs) {
- q.defer((this.q_fetchNodeInfo).bind(this), id, entity, this.entityAttribs[entity], q, gotResponse);
+ return new Promise(
+ function(resolve) {
+ let workInfo = {};
+ for (var i = 0; i < ids.length; ++i) {
+ workInfo[ids[i]] = {};
}
- }
- q.await((function () {
- // filter out nodes that have no connection info
- if (this.filtering) {
- for (var id in workInfo) {
- if (!(workInfo[id].connection)) {
- this.flux = true;
- delete workInfo[id];
- }
+ var gotResponse = function(nodeName, entity, response) {
+ workInfo[nodeName][entity] = response;
+ workInfo[nodeName][entity]["timestamp"] = new Date();
+ };
+ var q = d3.queue(this.connection.availableQeueuDepth());
+ for (var id in workInfo) {
+ for (var entity in this.entityAttribs) {
+ q.defer(
+ this.q_fetchNodeInfo.bind(this),
+ id,
+ entity,
+ this.entityAttribs[entity],
+ q,
+ gotResponse
+ );
}
}
- resolve(workInfo);
- }).bind(this));
- }).bind(this));
+ q.await(
+ function() {
+ // filter out nodes that have no connection info
+ if (this.filtering) {
+ for (var id in workInfo) {
+ if (!workInfo[id].connection) {
+ this.flux = true;
+ delete workInfo[id];
+ }
+ }
+ }
+ resolve(workInfo);
+ }.bind(this)
+ );
+ }.bind(this)
+ );
}
onDone(result) {
clearTimeout(this._getTimer);
if (this.updating)
- this._getTimer = setTimeout((this.get).bind(this), this.updateInterval);
+ this._getTimer = setTimeout(this.get.bind(this), this.updateInterval);
this.executeUpdatedActions(result);
}
startUpdating(filter) {
@@ -219,18 +256,29 @@ class Topology {
}
fetchEntity(node, entity, attrs, callback) {
var results = {};
- var gotResponse = function (nodeName, dotentity, response) {
+ var gotResponse = function(nodeName, dotentity, response) {
results = response;
};
var q = d3.queue(this.connection.availableQeueuDepth());
- q.defer((this.q_fetchNodeInfo).bind(this), node, entity, attrs, q, gotResponse);
- q.await(function () {
+ q.defer(
+ this.q_fetchNodeInfo.bind(this),
+ node,
+ entity,
+ attrs,
+ q,
+ gotResponse
+ );
+ q.await(function() {
callback(node, entity, results);
});
}
// called from d3.queue.defer so the last argument (callback) is supplied by d3
q_fetchNodeInfo(nodeId, entity, attrs, q, heartbeat, callback) {
- this.getNodeInfo(nodeId, entity, attrs, q, function (nodeName, dotentity, response) {
+ this.getNodeInfo(nodeId, entity, attrs, q, function(
+ nodeName,
+ dotentity,
+ response
+ ) {
heartbeat(nodeName, dotentity, response);
callback(null);
});
@@ -240,23 +288,29 @@ class Topology {
var q = d3.queue(this.connection.availableQeueuDepth());
var results = {};
if (!resultCallback) {
- resultCallback = function (nodeName, dotentity, response) {
- if (!results[nodeName])
- results[nodeName] = {};
+ resultCallback = function(nodeName, dotentity, response) {
+ if (!results[nodeName]) results[nodeName] = {};
results[nodeName][dotentity] = response;
};
}
- var gotAResponse = function (nodeName, dotentity, response) {
+ var gotAResponse = function(nodeName, dotentity, response) {
resultCallback(nodeName, dotentity, response);
};
- if (Object.prototype.toString.call(entityAttribs) !== '[object Array]') {
+ if (Object.prototype.toString.call(entityAttribs) !== "[object Array]") {
entityAttribs = [entityAttribs];
}
for (var i = 0; i < entityAttribs.length; ++i) {
var ea = entityAttribs[i];
- q.defer((this.q_fetchNodeInfo).bind(this), node, ea.entity, ea.attrs || [], q, gotAResponse);
+ q.defer(
+ this.q_fetchNodeInfo.bind(this),
+ node,
+ ea.entity,
+ ea.attrs || [],
+ q,
+ gotAResponse
+ );
}
- q.await(function () {
+ q.await(function() {
doneCallback(results);
});
}
@@ -265,44 +319,56 @@ class Topology {
var q = d3.queue(this.connection.availableQeueuDepth());
var results = {};
if (!resultCallback) {
- resultCallback = function (nodeName, dotentity, response) {
- if (!results[nodeName])
- results[nodeName] = {};
+ resultCallback = function(nodeName, dotentity, response) {
+ if (!results[nodeName]) results[nodeName] = {};
results[nodeName][dotentity] = response;
};
}
- var gotAResponse = function (nodeName, dotentity, response) {
+ var gotAResponse = function(nodeName, dotentity, response) {
resultCallback(nodeName, dotentity, response);
};
- if (Object.prototype.toString.call(entityAttribs) !== '[object Array]') {
+ if (Object.prototype.toString.call(entityAttribs) !== "[object Array]") {
entityAttribs = [entityAttribs];
}
var nodes = Object.keys(this._nodeInfo);
for (var n = 0; n < nodes.length; ++n) {
for (var i = 0; i < entityAttribs.length; ++i) {
var ea = entityAttribs[i];
- q.defer((this.q_fetchNodeInfo).bind(this), nodes[n], ea.entity, ea.attrs || [], q, gotAResponse);
+ q.defer(
+ this.q_fetchNodeInfo.bind(this),
+ nodes[n],
+ ea.entity,
+ ea.attrs || [],
+ q,
+ gotAResponse
+ );
}
}
- q.await(function () {
+ q.await(function() {
doneCallback(results);
});
}
// enusre all the topology nones have all these entities
ensureAllEntities(entityAttribs, callback, extra) {
- this.ensureEntities(Object.keys(this._nodeInfo), entityAttribs, callback, extra);
+ this.ensureEntities(
+ Object.keys(this._nodeInfo),
+ entityAttribs,
+ callback,
+ extra
+ );
}
// ensure these nodes have all these entities. don't fetch unless forced to
ensureEntities(nodes, entityAttribs, callback, extra) {
- if (Object.prototype.toString.call(nodes) !== '[object Array]') {
+ if (Object.prototype.toString.call(nodes) !== "[object Array]") {
nodes = [nodes];
}
this.addUpdateEntities(entityAttribs);
- this.doget(nodes)
- .then( function (results) {
+ this.doget(nodes).then(
+ function(results) {
this.saveResults(results);
callback(extra, results);
- }.bind(this));
+ }.bind(this)
+ );
}
addNodeInfo(id, entity, values) {
// save the results in the nodeInfo object
@@ -312,7 +378,7 @@ class Topology {
}
// copy the values to allow garbage collection
this._nodeInfo[id][entity] = values;
- this._nodeInfo[id][entity]['timestamp'] = new Date();
+ this._nodeInfo[id][entity]["timestamp"] = new Date();
}
}
isLargeNetwork() {
@@ -321,10 +387,9 @@ class Topology {
getConnForLink(link) {
// find the connection for this link
var conns = this._nodeInfo[link.nodeId].connection;
- if (!conns)
- return {};
- var connIndex = conns.attributeNames.indexOf('identity');
- var linkCons = conns.results.filter(function (conn) {
+ if (!conns) return {};
+ var connIndex = conns.attributeNames.indexOf("identity");
+ var linkCons = conns.results.filter(function(conn) {
return conn[connIndex] === link.connectionId;
});
return utils.flatten(conns.attributeNames, linkCons[0]);
@@ -356,44 +421,71 @@ class Topology {
}
// d3.queue'd function to make a management query for entities/attributes
q_ensureNodeInfo(nodeId, entity, attrs, q, callback) {
- this.getNodeInfo(nodeId, entity, attrs, q, (function (nodeName, dotentity, response) {
- this.addNodeInfo(nodeName, dotentity, response);
- callback(null);
- }).bind(this));
+ this.getNodeInfo(
+ nodeId,
+ entity,
+ attrs,
+ q,
+ function(nodeName, dotentity, response) {
+ this.addNodeInfo(nodeName, dotentity, response);
+ callback(null);
+ }.bind(this)
+ );
return {
- abort: function () {
+ abort: function() {
delete this._nodeInfo[nodeId];
}
};
}
getNodeInfo(nodeName, entity, attrs, q, callback) {
- var timedOut = function (q) {
+ var timedOut = function(q) {
q.abort();
};
var atimer = setTimeout(timedOut, this.timeout, q);
- this.connection.sendQuery(nodeName, entity, attrs)
- .then(function (response) {
+ this.connection.sendQuery(nodeName, entity, attrs).then(
+ function(response) {
clearTimeout(atimer);
callback(nodeName, entity, response.response);
- }, function () {
+ },
+ function() {
q.abort();
- });
- }
- getMultipleNodeInfo(nodeNames, entity, attrs, callback, selectedNodeId, aggregate) {
+ }
+ );
+ }
+ getMultipleNodeInfo(
+ nodeNames,
+ entity,
+ attrs,
+ callback,
+ selectedNodeId,
+ aggregate
+ ) {
var self = this;
- if (typeof aggregate === 'undefined')
- aggregate = true;
+ if (typeof aggregate === "undefined") aggregate = true;
var responses = {};
- var gotNodesResult = function (nodeName, dotentity, response) {
+ var gotNodesResult = function(nodeName, dotentity, response) {
responses[nodeName] = response;
};
var q = d3.queue(this.connection.availableQeueuDepth());
- nodeNames.forEach(function (id) {
- q.defer((self.q_fetchNodeInfo).bind(self), id, entity, attrs, q, gotNodesResult);
+ nodeNames.forEach(function(id) {
+ q.defer(
+ self.q_fetchNodeInfo.bind(self),
+ id,
+ entity,
+ attrs,
+ q,
+ gotNodesResult
+ );
});
- q.await(function () {
+ q.await(function() {
if (aggregate)
- self.aggregateNodeInfo(nodeNames, entity, selectedNodeId, responses, callback);
+ self.aggregateNodeInfo(
+ nodeNames,
+ entity,
+ selectedNodeId,
+ responses,
+ callback
+ );
else {
callback(nodeNames, entity, responses);
}
@@ -401,10 +493,15 @@ class Topology {
}
quiesceLink(nodeId, name) {
var attributes = {
- adminStatus: 'disabled',
+ adminStatus: "disabled",
name: name
};
- return this.connection.sendMethod(nodeId, 'router.link', attributes, 'UPDATE');
+ return this.connection.sendMethod(
+ nodeId,
+ "router.link",
+ attributes,
+ "UPDATE"
+ );
}
aggregateNodeInfo(nodeNames, entity, selectedNodeId, responses, callback) {
// aggregate the responses
@@ -420,7 +517,7 @@ class Topology {
var result = thisNode.results[i];
var vals = [];
// there is a val for each attribute in this entity
- result.forEach(function (val) {
+ result.forEach(function(val) {
vals.push({
sum: val,
detail: []
@@ -428,25 +525,24 @@ class Topology {
});
newResponse.aggregates.push(vals);
}
- var nameIndex = thisNode.attributeNames.indexOf('name');
+ var nameIndex = thisNode.attributeNames.indexOf("name");
var ent = self.connection.schema.entityTypes[entity];
var ids = Object.keys(responses);
ids.sort();
- ids.forEach(function (id) {
+ ids.forEach(function(id) {
var response = responses[id];
var results = response.results;
- results.forEach(function (result) {
+ results.forEach(function(result) {
// find the matching result in the aggregates
- var found = newResponse.aggregates.some(function (aggregate) {
+ var found = newResponse.aggregates.some(function(aggregate) {
if (aggregate[nameIndex].sum === result[nameIndex]) {
// result and aggregate are now the same record, add the graphable values
- newResponse.attributeNames.forEach(function (key, i) {
+ newResponse.attributeNames.forEach(function(key, i) {
if (ent.attributes[key] && ent.attributes[key].graph) {
- if (id != selectedNodeId)
- aggregate[i].sum += result[i];
+ if (id != selectedNodeId) aggregate[i].sum += result[i];
}
aggregate[i].detail.push({
- node: utils.nameFromId(id) + ':',
+ node: utils.nameFromId(id) + ":",
val: result[i]
});
});
@@ -458,13 +554,15 @@ class Topology {
// this attribute was not found in the aggregates yet
// because it was not in the selectedNodeId's results
var vals = [];
- result.forEach(function (val) {
+ result.forEach(function(val) {
vals.push({
sum: val,
- detail: [{
- node: utils.nameFromId(id),
- val: val
- }]
+ detail: [
+ {
+ node: utils.nameFromId(id),
+ val: val
+ }
+ ]
});
});
newResponse.aggregates.push(vals);
@@ -475,4 +573,4 @@ class Topology {
}
}
-export default Topology;
\ No newline at end of file
+export default Topology;
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/plugin/js/amqp/utilities.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/amqp/utilities.js b/console/stand-alone/plugin/js/amqp/utilities.js
index c092bf4..517b4e1 100644
--- a/console/stand-alone/plugin/js/amqp/utilities.js
+++ b/console/stand-alone/plugin/js/amqp/utilities.js
@@ -46,10 +46,14 @@ var utils = {
});
return flat;
},
- flattenAll: function (entity) {
+ flattenAll: function (entity, filter) {
+ if (!filter)
+ filter = function (e) {return e;};
let results = [];
for (let i=0; i<entity.results.length; i++) {
- results.push(this.flatten(entity.attributeNames, entity.results[i]));
+ let f = filter(this.flatten(entity.attributeNames, entity.results[i]));
+ if (f)
+ results.push(f);
}
return results;
},
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/plugin/js/chord/data.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/chord/data.js b/console/stand-alone/plugin/js/chord/data.js
index 64a58fa..c1cd978 100644
--- a/console/stand-alone/plugin/js/chord/data.js
+++ b/console/stand-alone/plugin/js/chord/data.js
@@ -99,6 +99,9 @@ class ChordData { // eslint-disable-line no-unused-vars
// each routers has a different order for the routers
let ingressRouters = [];
let routerNode = results[nodeId]['router.node'];
+ if (!routerNode) {
+ continue;
+ }
let idIndex = routerNode.attributeNames.indexOf('id');
// ingressRouters is an array of router names in the same order that the ingressHistogram values will be in
for (let i = 0; i < routerNode.results.length; i++) {
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/plugin/js/dlgDetailController.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/dlgDetailController.js b/console/stand-alone/plugin/js/dlgDetailController.js
index 8efff28..0742f2a 100644
--- a/console/stand-alone/plugin/js/dlgDetailController.js
+++ b/console/stand-alone/plugin/js/dlgDetailController.js
@@ -27,44 +27,68 @@ export class DetailDialogController {
$scope.detail = {
template: 'loading.html',
};
- $scope.detailFields = [
- 'version',
- 'mode',
- 'presettledDeliveries',
- 'droppedPresettledDeliveries',
- 'acceptedDeliveries',
- 'rejectedDeliveries',
- 'releasedDeliveries',
- 'modifiedDeliveries',
- 'deliveriesIngress',
- 'deliveriesEgress',
- 'deliveriesTransit',
- 'deliveriesIngressRouteContainer',
- 'deliveriesEgressRouteContainer'
- ];
- $scope.linkFields = [
- 'linkType',
- 'owningAddr',
- 'priority',
- 'acceptedCount',
- 'unsettledCount'
- ];
- $scope.linkRouteFields = [
- 'prefix',
- 'direction',
- 'containerId'
- ];
- $scope.autoLinkFields = [
- 'addr',
- 'direction',
- 'containerId'
- ];
- $scope.addressFields = [
- 'prefix',
- 'distribution'
- ];
+ let countChars = function (ar) {
+ let count = 0;
+ ar.forEach( function (a) {
+ count += a.length;
+ });
+ return count;
+ };
+
+ $scope.fields = {
+ detailFields: {
+ cols: [
+ 'version',
+ 'mode',
+ 'presettledDeliveries',
+ 'droppedPresettledDeliveries',
+ 'acceptedDeliveries',
+ 'rejectedDeliveries',
+ 'releasedDeliveries',
+ 'modifiedDeliveries',
+ 'deliveriesIngress',
+ 'deliveriesEgress',
+ 'deliveriesTransit',
+ 'deliveriesIngressRouteContainer',
+ 'deliveriesEgressRouteContainer'
+ ]
+ },
+ linkFields: {
+ cols: [
+ 'linkType',
+ 'owningAddr',
+ 'priority',
+ 'acceptedCount',
+ 'unsettledCount'
+ ]
+ },
+ linkRouteFields: {
+ cols: [
+ 'prefix',
+ 'direction',
+ 'containerId'
+ ]
+ },
+ autoLinkFields: {
+ cols: [
+ 'addr',
+ 'direction',
+ 'containerId'
+ ]
+ },
+ addressFields: {
+ cols: [
+ 'prefix',
+ 'distribution'
+ ]
+ }
+ };
+ for (let f in $scope.fields) {
+ $scope.fields[f].count = countChars($scope.fields[f].cols);
+ }
$scope.okClick = function () {
+ clearInterval(updateTimer);
$uibModalInstance.close(true);
};
$scope.expandClicked = function (id) {
@@ -78,6 +102,30 @@ export class DetailDialogController {
$scope.expanded = function (id) {
return expandedRows.has(id);
};
+ $scope.cellWidth = function (key, val) {
+ if (key === 'autoLinkFields') {
+ return val === 'addr' ? '40%' : '20%';
+ }
+ let totalChars = $scope.fields[key].count;
+ return `${Math.round(val.length * 100 / totalChars)}%`;
+ };
+ $scope.fieldWidth = function (val, sizes) {
+ if (!sizes)
+ return '10%';
+ return `${Math.round(sizes[val] * 100 / sizes.total)}%`;
+ };
+ let updateSizes = function (fields, sizes, obj) {
+ fields.forEach( function (key) {
+ if (!sizes[key])
+ sizes[key] = QDRService.utilities.humanify(key).length;
+ sizes[key] = Math.max(sizes[key], QDRService.utilities.pretty(obj[key]).length);
+ });
+ sizes.total = 0;
+ for (let key in sizes) {
+ if (key !== 'total')
+ sizes.total += sizes[key];
+ }
+ };
let groupDetail = function () {
let q_getEdgeInfo = function (n, infoPerId, callback) {
@@ -101,15 +149,30 @@ export class DetailDialogController {
let nodeId = QDRService.utilities.idFromName(id, '_edge');
QDRService.management.topology.fetchEntities(nodeId,
[{entity: 'router.link', attrs: []},
- {entity: 'linkRoute', attrs: $scope.linkRouteFields},
- {entity: 'autoLink', attrs: $scope.autoLinkFields},
+ {entity: 'linkRoute', attrs: $scope.fields.linkRouteFields.cols},
+ {entity: 'autoLink', attrs: $scope.fields.autoLinkFields.cols},
{entity: 'address', attrs: []},
],
function (results) {
$timeout( function () {
- infoPerId[id].linkRoutes = QDRService.utilities.flattenAll(results[nodeId].linkRoute);
- infoPerId[id].autoLinks = QDRService.utilities.flattenAll(results[nodeId].autoLink);
- infoPerId[id].addresses = QDRService.utilities.flattenAll(results[nodeId].address);
+ infoPerId[id].linkRouteSizes = {};
+ infoPerId[id].linkRoutes = QDRService.utilities.flattenAll(results[nodeId].linkRoute,
+ function (route) {
+ updateSizes($scope.fields.linkRouteFields.cols, infoPerId[id].linkRouteSizes, route);
+ return route;
+ });
+ infoPerId[id].autoLinkSizes = {};
+ infoPerId[id].autoLinks = QDRService.utilities.flattenAll(results[nodeId].autoLink,
+ function (link) {
+ updateSizes($scope.fields.autoLinkFields.cols, infoPerId[id].autoLinkSizes, link);
+ return link;
+ });
+ infoPerId[id].addressSizes = {};
+ infoPerId[id].addresses = QDRService.utilities.flattenAll(results[nodeId].address,
+ function (addr) {
+ updateSizes($scope.fields.addressFields.cols, infoPerId[id].addressSizes, addr);
+ return addr;
+ });
});
});
};
@@ -117,43 +180,44 @@ export class DetailDialogController {
let q = d3.queue(10);
for (let n=0; n<d.normals.length; n++) {
q.defer(q_getEdgeInfo, d.normals[n], infoPerId);
+ if (expandedRows.has(d.normals[n].container)) {
+ $scope.detail.moreInfo(d.normals[n].container);
+ }
}
q.await(function () {
$scope.detail.template = 'edgeRouters.html';
- $scope.detail.title = 'for edge router';
+ $scope.detail.title = 'edge router';
resolve({
- description: 'Expand an edge router to see more info',
+ description: 'Select an edge router to see more info',
infoPerId: infoPerId
});
});
- } else if (d.isConsole) {
- $scope.detail.template = 'consoles.html';
- $scope.detail.title = 'for console';
- resolve({
- description: ''
- });
} else {
$scope.detail.moreInfo = function () {};
+ let attrs = QDRService.utilities.copy($scope.fields.linkFields.cols);
+ attrs.unshift('connectionId');
QDRService.management.topology.fetchEntities(d.key,
- [{entity: 'router.link', attrs: []}],
+ [{entity: 'router.link', attrs: attrs}],
function (results) {
let links = results[d.key]['router.link'];
for (let i=0; i<d.normals.length; i++) {
let n = d.normals[i];
let conn = {};
- let connectionIndex = links.attributeNames.indexOf('connectionId');
infoPerId[n.container] = conn;
conn.container = n.container;
- conn.encrypted = n.encrypted;
+ conn.encrypted = n.encrypted ? 'True' : 'False';
conn.host = n.host;
- conn.links = [];
- for (let l=0; l<links.results.length; l++) {
- if (links.results[l][connectionIndex] === n.connectionId) {
- let link = QDRService.utilities.flatten(links.attributeNames, links.results[l]);
+ //conn.links = [];
+ conn.sizes = {};
+ conn.links = QDRService.utilities.flattenAll(links, function (link) {
+ if (link.connectionId === n.connectionId) {
link.owningAddr = QDRService.utilities.addr_text(link.owningAddr);
- conn.links.push(link);
+ updateSizes($scope.fields.linkFields.cols, conn.sizes, link);
+ return link;
+ } else {
+ return null;
}
- }
+ });
conn.linkCount = conn.links.length;
}
let dir = d.cdir === 'in' ? 'inbound' : d.cdir === 'both' ? 'in and outbound' : 'outbound';
@@ -172,14 +236,23 @@ export class DetailDialogController {
}));
};
- groupDetail()
- .then( function (det) {
- $timeout( function () {
- $scope.detail.title = `for ${d.normals.length} ${$scope.detail.title}${d.normals.length > 1 ? 's' : ''}`;
- $scope.detail.description = det.description;
- $scope.detail.infoPerId = det.infoPerId;
- }, 10);
- });
+ let updateDetail = function () {
+ groupDetail()
+ .then( function (det) {
+ $timeout( function () {
+ $scope.detail.title = `for ${d.normals.length} ${$scope.detail.title}${d.normals.length > 1 ? 's' : ''}`;
+ $scope.detail.description = det.description;
+ $scope.detail.infoPerId = Object.keys(det.infoPerId).map( function (id) {
+ return det.infoPerId[id];
+ }).sort( function (a, b) {
+ return a.name > b.name ? 1 : -1;
+ });
+ }, 10);
+ });
+ };
+ let updateTimer = setInterval(updateDetail, 2000);
+ updateDetail();
+
}
}
-DetailDialogController.$inject = ['QDRService', '$scope', '$timeout', '$uibModalInstance', 'd'];
+DetailDialogController.$inject = ['QDRService', '$scope', '$timeout', '$uibModalInstance', 'd'];
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/plugin/js/topology/links.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/topology/links.js b/console/stand-alone/plugin/js/topology/links.js
index 264cb8c..16b086c 100644
--- a/console/stand-alone/plugin/js/topology/links.js
+++ b/console/stand-alone/plugin/js/topology/links.js
@@ -17,22 +17,27 @@ specific language governing permissions and limitations
under the License.
*/
-import { utils } from '../amqp/utilities.js';
+import { utils } from "../amqp/utilities.js";
class Link {
constructor(source, target, dir, cls, uid) {
this.source = source;
this.target = target;
- this.left = (dir == 'in' || dir == 'both');
- this.right = (dir == 'out' || dir == 'both');
+ this.left = dir == "in" || dir == "both";
+ this.right = dir == "out" || dir == "both";
this.cls = cls;
this.uid = uid;
}
- markerId (end) {
- let selhigh = this.highlighted ? 'highlighted' : this.selected ? 'selected' : '';
- if (selhigh === '' && (!this.left && !this.right))
- selhigh = 'unknown';
- return `-${selhigh}-${end === 'end' ? this.target.radius() : this.source.radius()}`;
+ markerId(end) {
+ let selhigh = this.highlighted
+ ? "highlighted"
+ : this.selected
+ ? "selected"
+ : "";
+ if (selhigh === "" && (!this.left && !this.right)) selhigh = "unknown";
+ return `-${selhigh}-${
+ end === "end" ? this.target.radius() : this.source.radius()
+ }`;
}
}
@@ -41,10 +46,9 @@ export class Links {
this.links = [];
this.logger = logger;
}
- getLinkSource (nodesIndex) {
- for (let i=0; i<this.links.length; ++i) {
- if (this.links[i].target === nodesIndex)
- return i;
+ getLinkSource(nodesIndex) {
+ for (let i = 0; i < this.links.length; ++i) {
+ if (this.links[i].target === nodesIndex) return i;
}
return -1;
}
@@ -52,7 +56,7 @@ export class Links {
for (let i = 0; i < this.links.length; i++) {
let s = this.links[i].source,
t = this.links[i].target;
- if (typeof this.links[i].source == 'object') {
+ if (typeof this.links[i].source == "object") {
s = s.id;
t = t.id;
}
@@ -65,119 +69,144 @@ export class Links {
}
}
//this.logger.debug("creating new link (" + (links.length) + ") between " + nodes[_source].name + " and " + nodes[_target].name);
- if (this.links.some( function (l) { return l.uid === uid;}))
- uid = uid + '.' + this.links.length;
+ if (
+ this.links.some(function(l) {
+ return l.uid === uid;
+ })
+ )
+ uid = uid + "." + this.links.length;
return this.links.push(new Link(_source, _target, dir, cls, uid)) - 1;
}
- linkFor (source, target) {
+ linkFor(source, target) {
for (let i = 0; i < this.links.length; ++i) {
- if ((this.links[i].source == source) && (this.links[i].target == target))
+ if (this.links[i].source == source && this.links[i].target == target)
return this.links[i];
- if ((this.links[i].source == target) && (this.links[i].target == source))
+ if (this.links[i].source == target && this.links[i].target == source)
return this.links[i];
}
// the selected node was a client/broker
return null;
}
- getPosition (name, nodes, source, client, localStorage, height) {
- let position = localStorage[name] ? JSON.parse(localStorage[name]) : undefined;
- if ((typeof position == 'undefined')) {
+ getPosition(name, nodes, source, client, localStorage, height) {
+ let position = localStorage[name]
+ ? JSON.parse(localStorage[name])
+ : undefined;
+ if (typeof position == "undefined") {
position = {
- x: Math.round(nodes.get(source).x + 40 * Math.sin(client / (Math.PI * 2.0))),
- y: Math.round(nodes.get(source).y + 40 * Math.cos(client / (Math.PI * 2.0))),
+ x: Math.round(
+ nodes.get(source).x + 40 * Math.sin(client / (Math.PI * 2.0))
+ ),
+ y: Math.round(
+ nodes.get(source).y + 40 * Math.cos(client / (Math.PI * 2.0))
+ ),
fixed: false,
animate: true
};
- } else
- position.animate = false;
+ } else position.animate = false;
if (position.y > height) {
- position.y = Math.round(nodes.get(source).y + 40 + Math.cos(client / (Math.PI * 2.0)));
+ position.y = Math.round(
+ nodes.get(source).y + 40 + Math.cos(client / (Math.PI * 2.0))
+ );
}
return position;
}
- initialize (nodeInfo, nodes, unknowns, localStorage, height) {
+ initialize(nodeInfo, nodes, unknowns, localStorage, height) {
let connectionsPerContainer = {};
let nodeIds = Object.keys(nodeInfo);
// collect connection info for each router
- for (let source=0; source<nodeIds.length; source++) {
+ for (let source = 0; source < nodeIds.length; source++) {
let onode = nodeInfo[nodeIds[source]];
// skip any routers without connections
- if (!onode.connection || !onode.connection.results || onode.connection.results.length === 0)
+ if (
+ !onode.connection ||
+ !onode.connection.results ||
+ onode.connection.results.length === 0
+ )
continue;
const suid = nodes.get(source).uid();
- for (let c=0; c<onode.connection.results.length; c++) {
- let connection = utils.flatten(onode.connection.attributeNames, onode.connection.results[c]);
+ for (let c = 0; c < onode.connection.results.length; c++) {
+ let connection = utils.flatten(
+ onode.connection.attributeNames,
+ onode.connection.results[c]
+ );
// this is a connection to another interior router
- if (connection.role === 'inter-router') {
+ if (connection.role === "inter-router") {
const target = getContainerIndex(connection.container, nodeInfo);
if (target >= 0) {
const tuid = nodes.get(target).uid();
- this.getLink(source, target, connection.dir, '', `${suid}-${tuid}`);
+ this.getLink(source, target, connection.dir, "", `${suid}-${tuid}`);
}
continue;
}
if (!connectionsPerContainer[connection.container])
connectionsPerContainer[connection.container] = [];
- let linksDir = getLinkDir(connection , onode);
- if (linksDir === 'unknown')
- unknowns.push(nodeIds[source]);
+ let linksDir = getLinkDir(connection, onode);
+ if (linksDir === "unknown") unknowns.push(nodeIds[source]);
connectionsPerContainer[connection.container].push({
- source: source,
+ source: source,
linksDir: linksDir,
connection: connection,
- resultsIndex: c});
+ resultsIndex: c
+ });
}
}
let unique = {};
// create map of type:id:dir to [containers]
for (let container in connectionsPerContainer) {
let key = getKey(connectionsPerContainer[container]);
- if (!unique[key])
- unique[key] = {c: [], nodes: []};
+ if (!unique[key]) unique[key] = { c: [], nodes: [] };
unique[key].c.push(container);
}
for (let key in unique) {
let containers = unique[key].c;
- for (let i=0; i<containers.length; i++) {
+ for (let i = 0; i < containers.length; i++) {
let containerId = containers[i];
let connections = connectionsPerContainer[containerId];
let container = connections[0];
- let name = utils.nameFromId(nodeIds[container.source]) + '.' + container.connection.identity;
- let position = this.getPosition (name,
- nodes,
- container.source,
- container.resultsIndex,
- localStorage,
- height);
+ let name =
+ utils.nameFromId(nodeIds[container.source]) +
+ "." +
+ container.connection.identity;
+ let position = this.getPosition(
+ name,
+ nodes,
+ container.source,
+ container.resultsIndex,
+ localStorage,
+ height
+ );
- let node = nodes.getOrCreateNode (nodeIds[container.source],
- name,
- container.connection.role,
- nodes.getLength(),
- position.x, position.y,
- container.connection.container,
- container.resultsIndex,
- position.fixed,
- container.connection.properties);
+ let node = nodes.getOrCreateNode(
+ nodeIds[container.source],
+ name,
+ container.connection.role,
+ nodes.getLength(),
+ position.x,
+ position.y,
+ container.connection.container,
+ container.resultsIndex,
+ position.fixed,
+ container.connection.properties
+ );
node.host = container.connection.host;
node.cdir = container.linksDir;
node.user = container.connection.user;
node.isEncrypted = container.connection.isEncrypted;
node.connectionId = container.connection.identity;
- node.uuid = `${node.routerId}${node.nodeType}${node.cdir}`;
+ node.uuid = `${containerId}-${node.routerId}-${node.nodeType}-${node.cdir}`;
// in case a created node (or group) is connected to multiple
// routers, we need to remember all the routers for traffic animations
- for (let c=1; c<connections.length; c++) {
- if (!node.alsoConnectsTo)
- node.alsoConnectsTo = [];
+ for (let c = 1; c < connections.length; c++) {
+ if (!node.alsoConnectsTo) node.alsoConnectsTo = [];
node.alsoConnectsTo.push({
key: nodeIds[connections[c].source],
- dir: connections[c].linksDir,
- connectionId: connections[c].connection.identity});
+ cdir: connections[c].linksDir,
+ connectionId: connections[c].connection.identity
+ });
}
unique[key].nodes.push(node);
}
@@ -186,184 +215,80 @@ export class Links {
nodes.add(unique[key].nodes[0]);
let target = nodes.nodes.length - 1;
unique[key].nodes[0].normals = [unique[key].nodes[0]];
- for (let n=1; n<unique[key].nodes.length; n++) {
+ for (let n = 1; n < unique[key].nodes.length; n++) {
unique[key].nodes[0].normals.push(unique[key].nodes[n]);
}
let containerId = unique[key].c[0];
let links = connectionsPerContainer[containerId];
- for (let l=0; l<links.length; l++) {
+ for (let l = 0; l < links.length; l++) {
let source = links[l].source;
const suid = nodes.get(source).uid();
const tuid = nodes.get(target).uid();
- this.getLink(links[l].source, target, links[l].linksDir, 'small', `${suid}-${tuid}`);
+ this.getLink(
+ links[l].source,
+ target,
+ links[l].linksDir,
+ "small",
+ `${suid}-${tuid}`
+ );
}
}
}
- initializeLinks (nodeInfo, nodes, unknowns, localStorage, height) {
- let animate = false;
- let client = 1.0;
- let nodeIds = Object.keys(nodeInfo);
- // loop through all the routers
- for (let source=0; source<nodeIds.length; source++) {
- let id = nodeIds[source];
- const suid = nodes.get(source).uid();
- let onode = nodeInfo[id];
- if (!onode['connection']) {
- continue;
- }
- let normalsParent = {}; // 1st normal node for this parent
- // loop through each connection for this router
- for (let j = 0; j < onode['connection'].results.length; j++) {
- let connection = utils.flatten(onode['connection'].attributeNames,
- onode['connection'].results[j]);
- let role = connection.role;
- let dir = connection.dir;
- // connection to another interior router, just create a link between them
- if (role == 'inter-router') {
- let connId = connection.container;
- let target = getContainerIndex(connId, nodeInfo);
- if (target >= 0) {
- const tuid = nodes.get(target).uid();
- this.getLink(source, target, dir, '', suid + '-' + tuid);
- }
- continue;
- }
- let properties = connection.properties || {};
- // handle external connections
- let name = utils.nameFromId(id) + '.' + connection.identity;
- // if we have any new clients, animate the force graph to position them
- let position = localStorage[name] ? JSON.parse(localStorage[name]) : undefined;
- if ((typeof position == 'undefined')) {
- animate = true;
- position = {
- x: Math.round(nodes.get(source).x + 40 * Math.sin(client / (Math.PI * 2.0))),
- y: Math.round(nodes.get(source).y + 40 * Math.cos(client / (Math.PI * 2.0))),
- fixed: false
- };
- }
- if (position.y > height) {
- position.y = Math.round(nodes.get(source).y + 40 + Math.cos(client / (Math.PI * 2.0)));
- }
- let existingNodeIndex = nodes.nodeExists(connection.container);
- let normalInfo = nodes.normalExists(connection.container);
- let node = nodes.getOrCreateNode(id, name, role, nodeInfo, nodes.getLength(), position.x, position.y, connection.container, j, position.fixed, properties);
- let nodeType = utils.isAConsole(properties, connection.identity, role, node.key) ? 'console' : 'client';
- let linksDir = getLinkDir(connection, onode);
- if (existingNodeIndex >= 0) {
- // make a link between the current router (source) and the existing node
- const tuid = nodes.get(existingNodeIndex).uid();
- this.getLink(source, existingNodeIndex, dir, 'small', suid + '-' + tuid);
- } else if (normalInfo.nodesIndex) {
- // get node index of node that contained this connection in its normals array
- let normalSource = this.getLinkSource(normalInfo.nodesIndex);
- if (normalSource >= 0) {
- if (linksDir === 'unknown')
- linksDir = dir;
- node.cdir = linksDir;
- nodes.add(node);
- const suidn = nodes.get(this.links[normalSource].source).uid();
- const tuid = node.uid();
- // create link from original node to the new node
- this.getLink(this.links[normalSource].source, nodes.getLength()-1, linksDir, 'small', suidn + '-' + tuid);
- // create link from this router to the new node
- this.getLink(source, nodes.getLength()-1, linksDir, 'small', suid + '-' + tuid);
- // remove the old node from the normals list
- nodes.get(normalInfo.nodesIndex).normals.splice(normalInfo.normalsIndex, 1);
- }
- } else if (role === 'normal' || role === 'edge') {
- // normal nodes can be collapsed into a single node if they are all the same dir
- if (linksDir !== 'unknown') {
- node.user = connection.user;
- node.isEncrypted = connection.isEncrypted;
- node.host = connection.host;
- node.connectionId = connection.identity;
- node.cdir = linksDir;
- node.uuid = `${node.routerId}${node.nodeType}${node.cdir}`;
- // determine arrow direction by using the link directions
- if (!normalsParent[nodeType+linksDir]) {
- normalsParent[nodeType+linksDir] = node;
- nodes.add(node);
- node.normals = [node];
- node.connectsTo = {id: linksDir};
- // now add a link
- this.getLink(source, nodes.getLength() - 1, linksDir, 'small', suid + '-' + node.uid());
- client++;
- } else {
- normalsParent[nodeType+linksDir].normals.push(node);
- }
- } else {
- node.id = nodes.getLength() - 1 + unknowns.length;
- unknowns.push(node);
- }
- } else {
- nodes.add(node);
- // now add a link
- this.getLink(source, nodes.getLength() - 1, dir, 'small', suid + '-' + node.uid());
- client++;
- }
- }
- }
- return animate;
- }
- clearHighlighted () {
+ clearHighlighted() {
for (let i = 0; i < this.links.length; ++i) {
this.links[i].highlighted = false;
}
}
}
-var getContainerIndex = function (_id, nodeInfo) {
+var getContainerIndex = function(_id, nodeInfo) {
let nodeIndex = 0;
for (let id in nodeInfo) {
- if (utils.nameFromId(id) === _id)
- return nodeIndex;
+ if (utils.nameFromId(id) === _id) return nodeIndex;
++nodeIndex;
}
return -1;
};
-var getLinkDir = function (connection, onode) {
- let links = onode['router.link'];
+var getLinkDir = function(connection, onode) {
+ let links = onode["router.link"];
if (!links) {
- return 'unknown';
+ return "unknown";
}
- let inCount = 0, outCount = 0;
- let typeIndex = links.attributeNames.indexOf('linkType');
- let connectionIdIndex = links.attributeNames.indexOf('connectionId');
- let dirIndex = links.attributeNames.indexOf('linkDir');
- links.results.forEach( function (linkResult) {
- if (linkResult[typeIndex] === 'endpoint' && linkResult[connectionIdIndex] === connection.identity)
- if (linkResult[dirIndex] === 'in')
- ++inCount;
- else
- ++outCount;
+ let inCount = 0,
+ outCount = 0;
+ let typeIndex = links.attributeNames.indexOf("linkType");
+ let connectionIdIndex = links.attributeNames.indexOf("connectionId");
+ let dirIndex = links.attributeNames.indexOf("linkDir");
+ links.results.forEach(function(linkResult) {
+ if (
+ linkResult[typeIndex] === "endpoint" &&
+ linkResult[connectionIdIndex] === connection.identity
+ )
+ if (linkResult[dirIndex] === "in") ++inCount;
+ else ++outCount;
});
- if (inCount > 0 && outCount > 0)
- return 'both';
- if (inCount > 0)
- return 'in';
- if (outCount > 0)
- return 'out';
- return 'unknown';
+ if (inCount > 0 && outCount > 0) return "both";
+ if (inCount > 0) return "in";
+ if (outCount > 0) return "out";
+ return "unknown";
};
-var getKey = function (containers) {
+var getKey = function(containers) {
let parts = [];
let connection = containers[0].connection;
- let d = {nodeType: connection.role, properties: connection.properties || {}};
- let connectionType = 'client';
- if (utils.isConsole(connection))
- connectionType = 'console';
- else if (utils.isArtemis(d))
- connectionType = 'artemis';
- else if (utils.isQpid(d))
- connectionType = 'qpid';
- else if (connection.role === 'edge')
- connectionType = 'edge';
- for (let c=0; c<containers.length; c++) {
+ let d = {
+ nodeType: connection.role,
+ properties: connection.properties || {}
+ };
+ let connectionType = "client";
+ if (utils.isConsole(connection)) connectionType = "console";
+ else if (utils.isArtemis(d)) connectionType = "artemis";
+ else if (utils.isQpid(d)) connectionType = "qpid";
+ else if (connection.role === "edge") connectionType = "edge";
+ for (let c = 0; c < containers.length; c++) {
let container = containers[c];
parts.push(`${container.source}-${container.linksDir}`);
}
- return `${connectionType}:${parts.join(':')}`;
+ return `${connectionType}:${parts.join(":")}`;
};
-
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/55b7ae55/console/stand-alone/plugin/js/topology/map.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/topology/map.js b/console/stand-alone/plugin/js/topology/map.js
index c14008d..972d894 100644
--- a/console/stand-alone/plugin/js/topology/map.js
+++ b/console/stand-alone/plugin/js/topology/map.js
@@ -57,6 +57,10 @@ export class BackgroundMap { // eslint-disable-line no-unused-vars
init($scope, svg, width, height) {
return new Promise( (function (resolve, reject) {
+ if (this.initialized) {
+ resolve();
+ return;
+ }
this.svg = svg;
this.width = width;
this.height = height;
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org