This is an automated email from the ASF dual-hosted git repository. eallen pushed a commit to branch eallen-DISPATCH-1385 in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git
The following commit(s) were added to refs/heads/eallen-DISPATCH-1385 by this push: new ad6919d Fix address legend ad6919d is described below commit ad6919d40de426ee03fd9702bf7e53234f50b7c2 Author: Ernest Allen <eal...@redhat.com> AuthorDate: Mon Sep 30 17:58:35 2019 -0400 Fix address legend --- console/react/src/App.css | 5 +- console/react/src/amqp/management.js | 33 +++---- console/react/src/amqp/topology.js | 143 +++++++++++++++++++----------- console/react/src/qdrService.js | 12 +-- console/react/src/topology/qdrTopology.js | 50 +++++++---- console/react/src/topology/traffic.js | 43 ++------- 6 files changed, 154 insertions(+), 132 deletions(-) diff --git a/console/react/src/App.css b/console/react/src/App.css index e018298..6782444 100644 --- a/console/react/src/App.css +++ b/console/react/src/App.css @@ -490,6 +490,10 @@ path.hittarget { stroke-width: 15px; stroke: transparent; } +path.hittarget.highlighted { + stroke: #6f6; + opacity: 0.5; +} path.link.small { stroke-width: 2.5; @@ -525,7 +529,6 @@ circle.node.reflexive { circle.node.selected { stroke: #6f6 !important; stroke-width: 2px; - fill: #e0e0ff !important; } circle.node.highlighted { stroke: #6f6; diff --git a/console/react/src/amqp/management.js b/console/react/src/amqp/management.js index 4b3bb32..0bdb748 100644 --- a/console/react/src/amqp/management.js +++ b/console/react/src/amqp/management.js @@ -16,45 +16,46 @@ /* global Promise */ -import { ConnectionManager } from './connection.js'; -import Topology from './topology.js'; +import { ConnectionManager } from "./connection.js"; +import Topology from "./topology.js"; export class Management { - constructor(protocol) { + constructor(protocol, interval) { this.connection = new ConnectionManager(protocol); - this.topology = new Topology(this.connection); + this.topology = new Topology(this.connection, interval); } getSchema(callback) { var self = this; - return new Promise(function (resolve, reject) { - self.connection.sendMgmtQuery('GET-SCHEMA') - .then(function (responseAndContext) { + return new Promise(function(resolve, reject) { + self.connection.sendMgmtQuery("GET-SCHEMA").then( + function(responseAndContext) { var response = responseAndContext.response; for (var entityName in response.entityTypes) { var entity = response.entityTypes[entityName]; if (entity.deprecated) { // deprecated entity delete response.entityTypes[entityName]; - } - else { + } else { for (var attributeName in entity.attributes) { var attribute = entity.attributes[attributeName]; if (attribute.deprecated) { // deprecated attribute - delete response.entityTypes[entityName].attributes[attributeName]; + delete response.entityTypes[entityName].attributes[ + attributeName + ]; } } } } self.connection.setSchema(response); - if (callback) - callback(response); + if (callback) callback(response); resolve(response); - }, function (error) { - if (callback) - callback(error); + }, + function(error) { + if (callback) callback(error); reject(error); - }); + } + ); }); } schema() { diff --git a/console/react/src/amqp/topology.js b/console/react/src/amqp/topology.js index 0e8b2e4..dbbc00f 100644 --- a/console/react/src/amqp/topology.js +++ b/console/react/src/amqp/topology.js @@ -22,14 +22,17 @@ class Topology { constructor(connectionManager, interval) { this.connection = connectionManager; this.updatedActions = {}; + this.changedActions = {}; this.entities = []; // which entities to request each topology update this.entityAttribs = { connection: [] }; this._nodeInfo = {}; // info about all known nodes and entities this.filtering = false; // filter out nodes that don't have connection info this.timeout = 5000; this.updateInterval = interval; + console.log(`topology constructed with interval of ${interval}`); this._getTimer = null; this.updating = false; + this.counter = 0; } addUpdatedAction(key, action) { if (typeof action === "function") { @@ -59,8 +62,25 @@ class Topology { this.entityAttribs[entity] = entityAttribs[i].attrs || []; } } + addChangedAction(key, action) { + if (typeof action === "function") { + this.changedActions[key] = action; + } + } + delChangedAction(key) { + if (key in this.changedActions) delete this.changedActions[key]; + } + executeChangedActions(error) { + for (var action in this.changedActions) { + this.changedActions[action].apply(this, [error]); + } + } on(eventName, fn, key) { - if (eventName === "updated") this.addUpdatedAction(key, fn); + if (eventName === "updated") { + this.addUpdatedAction(key, fn); + } else if (eventName === "changed") { + this.addChangedAction(key, fn); + } } unregister(eventName, key) { if (eventName === "updated") this.delUpdatedAction(key); @@ -68,15 +88,12 @@ class Topology { nodeInfo() { return this._nodeInfo; } - saveResults(workInfo) { + saveResults(workInfo, all) { + const changes = { newRouters: [], lostRouters: [], connections: [] }; + let changed = false; let workSet = new Set(Object.keys(workInfo)); 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; - } else { - if (this._nodeInfo[rId]["removed"]) - delete this._nodeInfo[rId]["removed"]; + if (workSet.has(rId)) { // copy entities for (let entity in workInfo[rId]) { if ( @@ -84,9 +101,30 @@ class Topology { workInfo[rId][entity]["timestamp"] + "" > this._nodeInfo[rId][entity]["timestamp"] + "" ) { + // check for changed number of connections + if (entity === "connection") { + const oldConnections = + this._nodeInfo && + this._nodeInfo[rId] && + this._nodeInfo[rId].connection + ? this._nodeInfo[rId].connection.results.length + : 0; + const newConnections = workInfo[rId].connection.results.length; + if (oldConnections !== newConnections) { + changes.connections.push({ + router: rId, + from: oldConnections, + to: newConnections + }); + changed = true; + } + } this._nodeInfo[rId][entity] = utils.copy(workInfo[rId][entity]); } } + } else if (all) { + changes.lostRouters.push(rId); + changed = true; } } // add any new routers @@ -94,19 +132,20 @@ class Topology { for (let rId in workInfo) { if (!nodeSet.has(rId)) { this._nodeInfo[rId] = utils.copy(workInfo[rId]); + changes.newRouters.push(rId); + changed = true; } } - } - // 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]; - } + if (changed) { + this.executeChangedActions(changes); } } + get() { + if (typeof this.getCounter === "undefined") { + this.getCounter = 0; + } + console.log(`topology: get - ${this.getCounter++}`); return new Promise( function(resolve, reject) { this.connection.sendMgmtQuery("GET-MGMT-NODES").then( @@ -122,7 +161,7 @@ class Topology { routerIds.push(parts.join("/")); } let finish = function(workInfo) { - this.saveResults(workInfo); + this.saveResults(workInfo, true); this.onDone(this._nodeInfo); resolve(this._nodeInfo); }; @@ -194,45 +233,41 @@ class Topology { ); } doget(ids) { - return new Promise( - function(resolve) { - let workInfo = {}; - for (var i = 0; i < ids.length; ++i) { - workInfo[ids[i]] = {}; + return new Promise(resolve => { + let workInfo = {}; + for (var i = 0; i < ids.length; ++i) { + workInfo[ids[i]] = {}; + } + var gotResponse = (nodeName, entity, response) => { + workInfo[nodeName][entity] = response; + workInfo[nodeName][entity]["timestamp"] = new Date(); + }; + var q = 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 + ); } - var gotResponse = function(nodeName, entity, response) { - workInfo[nodeName][entity] = response; - workInfo[nodeName][entity]["timestamp"] = new Date(); - }; - var q = 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 - ); + } + q.await(() => { + // 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]; + } } } - 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) - ); + resolve(workInfo); + }); + }); } onDone(result) { @@ -365,7 +400,7 @@ class Topology { this.addUpdateEntities(entityAttribs); this.doget(nodes).then( function(results) { - this.saveResults(results); + this.saveResults(results, false); callback(extra, results); }.bind(this) ); diff --git a/console/react/src/qdrService.js b/console/react/src/qdrService.js index 93bb7b5..55a6cc9 100644 --- a/console/react/src/qdrService.js +++ b/console/react/src/qdrService.js @@ -20,17 +20,14 @@ Licensed to the Apache Software Foundation (ASF) under one import { Management as dm } from "./amqp/management.js"; import { utils } from "./amqp/utilities.js"; -import { QDR_LAST_LOCATION, QDR_INTERVAL } from "./qdrGlobals.js"; +import { QDR_LAST_LOCATION } from "./qdrGlobals.js"; // number of milliseconds between topology updates const DEFAULT_INTERVAL = 5000; export class QDRService { constructor(hooks) { const url = utils.getUrlParts(window.location); - this.management = new dm( - url.protocol, - localStorage[QDR_INTERVAL] || DEFAULT_INTERVAL - ); + this.management = new dm(url.protocol, DEFAULT_INTERVAL); this.utilities = utils; this.hooks = hooks; } @@ -84,10 +81,7 @@ export class QDRService { disconnect() { this.management.connection.disconnect(); delete this.management; - this.management = new dm( - this.$location.protocol(), - localStorage[QDR_INTERVAL] || DEFAULT_INTERVAL - ); + this.management = new dm(this.$location.protocol(), DEFAULT_INTERVAL); } } diff --git a/console/react/src/topology/qdrTopology.js b/console/react/src/topology/qdrTopology.js index 0722c4a..f5eda9e 100644 --- a/console/react/src/topology/qdrTopology.js +++ b/console/react/src/topology/qdrTopology.js @@ -143,10 +143,18 @@ class TopologyPage extends Component { } // called only once when the component is initialized - componentDidMount() { + componentDidMount = () => { this.init(); - } + this.props.service.management.topology.startUpdating(); + this.props.service.management.topology.addChangedAction("topology", () => { + this.init(); + }); + }; + componentWillUnmount = () => { + this.props.service.management.topology.stopUpdating(); + this.props.service.management.topology.delChangedAction("topology"); + }; setFixed = (item, data) => { data.setFixed(item.title !== "Unfreeze"); }; @@ -162,9 +170,7 @@ class TopologyPage extends Component { }); // set the selected attr for this node data.selected = item.title === "Select"; - if (item.title === "Select") { - this.selected_node = data; - } + this.selected_node = data.selected ? data : null; this.restart(); }; isSelected = data => { @@ -223,10 +229,8 @@ class TopologyPage extends Component { .attr("class", "nodes") .selectAll("g"); - /* - this.traffic.remove(); + this.traffic.remove(); if (this.state.legendOptions.traffic.open) { - if (this.state.legendOptions.traffic.dots) this.traffic.addAnimationType( "dots", @@ -240,7 +244,7 @@ class TopologyPage extends Component { Nodes.radius("inter-router") ); } -*/ + // mouse event vars this.mousedown_node = null; @@ -535,7 +539,10 @@ class TopologyPage extends Component { return !d.right && !d.left; }); - enterpath.append("path").attr("class", "hittarget"); + enterpath + .append("path") + .attr("class", "hittarget") + .attr("id", d => `hitpath-${d.source.uid()}-${d.target.uid()}`); // remove old links this.path.exit().remove(); @@ -757,6 +764,10 @@ class TopologyPage extends Component { let link = this.forceData.links.linkFor(selected_node, connected_node); if (link) { link.highlighted = true; + d3.select(`path[id='hitpath-${link.uid}']`).classed( + "highlighted", + true + ); } // start at the router selected_node = connected_node; @@ -771,6 +782,10 @@ class TopologyPage extends Component { let link = this.forceData.links.linkFor(d, connected_node); if (link) { link.highlighted = true; + d3.select(`path[id='hitpath-${link.uid}']`).classed( + "highlighted", + true + ); } // end at the router d = connected_node; @@ -784,15 +799,13 @@ class TopologyPage extends Component { selected_node, (link, fnode, tnode) => { link.highlighted = true; + d3.select(`path[id='hitpath-${link.uid}']`).classed( + "highlighted", + true + ); fnode.highlighted = true; tnode.highlighted = true; } - /* - function(hlLink, hnode) { - hlLink.highlighted = true; - hnode.highlighted = true; - } - */ ); let hnode = this.forceData.nodes.nodeFor(d.name); hnode.highlighted = true; @@ -845,6 +858,7 @@ class TopologyPage extends Component { clearAllHighlights = () => { this.forceData.links.clearHighlighted(); this.forceData.nodes.clearHighlighted(); + d3.selectAll(".hittarget").classed("highlighted", false); }; saveLegendOptions = legendOptions => { @@ -920,12 +934,13 @@ class TopologyPage extends Component { this.handleLegendOptionsChange(legendOptions, this.addressFilterChanged); } }; + handleUpdateAddressColors = addressColors => { const { legendOptions } = this.state; let changed = false; // set any new keys to the passed in value Object.keys(addressColors).forEach(address => { - if (typeof legendOptions.traffic.addresses[address] === "undefined") { + if (typeof legendOptions.traffic.addressColors[address] === "undefined") { legendOptions.traffic.addressColors[address] = addressColors[address]; changed = true; } @@ -971,7 +986,6 @@ class TopologyPage extends Component { }; render() { - console.log("rendering qdrTopology"); return ( <div className="qdrTopology"> <LegendComponent diff --git a/console/react/src/topology/traffic.js b/console/react/src/topology/traffic.js index 24a7643..4cc51b0 100644 --- a/console/react/src/topology/traffic.js +++ b/console/react/src/topology/traffic.js @@ -334,29 +334,6 @@ class Dots extends TrafficAnimation { // set excludedAddresses this.updateAddresses(); }); - let self = this; - // event notification that an address checkbox has changed - traffic.$scope.addressFilterChanged = function() { - self.updateAddresses(); - // don't wait for the next polling cycle. update now - self.traffic.stop(); - self.traffic.start(); - }; - // called when mouse enters one of the address legends - 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() { - self.unFadeAll(); - }; - // clicked on the address name. toggle the address checkbox - traffic.$scope.addressClick = function(address) { - self.toggleAddress(address).then(function() { - self.updateAddresses(); - }); - }; } remove() { d3.select("#SVG_ID") @@ -378,14 +355,6 @@ class Dots extends TrafficAnimation { this.chordData.setFilter(this.excludedAddresses); } } - toggleAddress(address) { - 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) { return d.address !== address; @@ -417,8 +386,14 @@ class Dots extends TrafficAnimation { } render(matrix) { if (this.stopped === false) { - this.traffic.$scope.addresses = this.chordData.getAddresses(); - this.traffic.$scope.handleUpdatedAddresses(this.traffic.$scope.addresses); + const addresses = this.chordData.getAddresses(); + this.traffic.$scope.handleUpdatedAddresses(addresses); + const addressColors = {}; + for (let address in addresses) { + this.fillColor(address, addressColors); + } + this.traffic.$scope.handleUpdateAddressColors(addressColors); + // get the rate of message flow between routers let hops = {}; // every hop between routers that is involved in message flow let matrixMessages = matrix.matrixMessages(); @@ -639,7 +614,7 @@ class Dots extends TrafficAnimation { } } addressIndex(vis, address) { - return Object.keys(vis.traffic.$scope.addresses).indexOf(address); + return Object.keys(vis.traffic.addresses).indexOf(address); } // calculate the translation for each dot along the path translateDots(radius, path, count, back) { --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org For additional commands, e-mail: commits-h...@qpid.apache.org