This is an automated email from the ASF dual-hosted git repository.

eallen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git


The following commit(s) were added to refs/heads/master by this push:
     new 681c330  DISPATCH-1592: Grey out unreachable routers. Added ability to 
suppress notification popups. Set browser window title.
681c330 is described below

commit 681c330c172595507457215b9bd3253dfcdd5181
Author: Ernest Allen <eal...@redhat.com>
AuthorDate: Thu Mar 12 19:36:08 2020 -0400

    DISPATCH-1592: Grey out unreachable routers. Added ability to suppress 
notification popups. Set browser window title.
---
 console/react/src/App.css                          | 24 ++++++
 console/react/src/common/DropdownMenu.js           | 15 +++-
 console/react/src/common/amqp/connection.js        | 20 +++--
 console/react/src/common/amqp/topology.js          |  5 ++
 console/react/src/common/contextMenuComponent.js   |  5 ++
 console/react/src/overview/dashboard/layout.js     | 19 ++++-
 .../src/overview/dashboard/notificationDrawer.js   |  2 +-
 console/react/src/topology/svgUtils.js             |  3 +-
 console/react/src/topology/topoUtils.js            | 20 +++++
 console/react/src/topology/topologyViewer.js       | 96 ++++++++++++----------
 10 files changed, 154 insertions(+), 55 deletions(-)

diff --git a/console/react/src/App.css b/console/react/src/App.css
index 7c25676..03270d4 100644
--- a/console/react/src/App.css
+++ b/console/react/src/App.css
@@ -82,9 +82,16 @@ g.selected line {
 .link {
   stroke: #000;
 }
+.link.dropped {
+  stroke: #888888;
+  opacity: 0.25;
+}
 .topology-header path.link {
   stroke: #fff;
 }
+.topology-header ul.context-menu.layout-dropdown {
+  right: 0;
+}
 
 #topologyPage,
 #messageFlowPage {
@@ -545,7 +552,20 @@ circle.node.route-container {
 circle.node.edge.multiple {
   fill: #e0e0ff;
 }
+circle.node.dropped,
+circle.node.normal.in.dropped,
+circle.node.normal.out.dropped {
+  fill: #f0f0f0;
+  stroke: #dddddd;
+  stroke-dasharray: 5 5;
+}
+circle.node.inter-router.dropped {
+  fill: #f0f0f0;
+}
 
+circle.node.dropped + text {
+  stroke: #dddddd;
+}
 text.console,
 text.on-demand,
 text.normal,
@@ -1504,3 +1524,7 @@ button.dropdown-panel-toggle.pf-c-accordion__toggle 
span.pf-c-accordion__toggle-
 .node-name {
   text-decoration: underline;
 }
+
+.menu-item-icon {
+  padding-right: 0.5em;
+}
diff --git a/console/react/src/common/DropdownMenu.js 
b/console/react/src/common/DropdownMenu.js
index 5f58b9d..9d82827 100644
--- a/console/react/src/common/DropdownMenu.js
+++ b/console/react/src/common/DropdownMenu.js
@@ -27,7 +27,9 @@ class DropdownMenu extends Component {
     handleDropdownLogout: PropTypes.func.isRequired,
     isConnected: PropTypes.func.isRequired,
     handleContextHide: PropTypes.func.isRequired,
-    parentClass: PropTypes.string.isRequired
+    parentClass: PropTypes.string.isRequired,
+    handleSuppress: PropTypes.func.isRequired,
+    suppress: PropTypes.any.isRequired
   };
   constructor(props) {
     super(props);
@@ -40,6 +42,12 @@ class DropdownMenu extends Component {
         title: "Logout",
         action: this.logout,
         enabled: this.isLoggedIn
+      },
+      {
+        title: "Suppress notifications",
+        action: this.suppress,
+        enabled: () => true,
+        suppressIcon: true
       }
     ];
   }
@@ -48,6 +56,10 @@ class DropdownMenu extends Component {
     this.props.handleDropdownLogout();
   };
 
+  suppress = () => {
+    this.props.handleSuppress();
+  };
+
   isLoggedIn = () => {
     return this.props.isConnected();
   };
@@ -64,6 +76,7 @@ class DropdownMenu extends Component {
           contextEventPosition={[-1, -1]} // show in-place
           handleContextHide={this.props.handleContextHide}
           menuItems={this.contextMenuItems}
+          suppress={this.props.suppress}
           parentClass={this.props.parentClass}
         />
       )
diff --git a/console/react/src/common/amqp/connection.js 
b/console/react/src/common/amqp/connection.js
index 773810e..748e647 100644
--- a/console/react/src/common/amqp/connection.js
+++ b/console/react/src/common/amqp/connection.js
@@ -357,14 +357,18 @@ class ConnectionManager {
     var _correlationId = this.correlator.corr();
     var self = this;
     return new Promise((resolve, reject) => {
-      self.correlator.register(_correlationId, resolve, reject);
-      self.sender.send({
-        body: body,
-        to: to,
-        reply_to: self.receiver.remote.attach.source.address,
-        correlation_id: _correlationId,
-        application_properties: application_properties
-      });
+      try {
+        self.correlator.register(_correlationId, resolve, reject);
+        self.sender.send({
+          body: body,
+          to: to,
+          reply_to: self.receiver.remote.attach.source.address,
+          correlation_id: _correlationId,
+          application_properties: application_properties
+        });
+      } catch (error) {
+        console.log(error);
+      }
     });
   };
   _fullAddr = toAddr => {
diff --git a/console/react/src/common/amqp/topology.js 
b/console/react/src/common/amqp/topology.js
index 7c86e7d..693fc04 100644
--- a/console/react/src/common/amqp/topology.js
+++ b/console/react/src/common/amqp/topology.js
@@ -141,8 +141,13 @@ class Topology {
             this._nodeInfo[rId][entity] = utils.copy(workInfo[rId][entity]);
           }
         }
+        // find routers that have no connection info
+        if (!workInfo[rId].connection) {
+          this._nodeInfo[rId].connection.stale = true;
+        }
       } else if (all) {
         changes.lostRouters.push(rId);
+        delete this._nodeInfo[rId];
       }
     }
     // add any new routers
diff --git a/console/react/src/common/contextMenuComponent.js 
b/console/react/src/common/contextMenuComponent.js
index 8e660fa..62292fe 100644
--- a/console/react/src/common/contextMenuComponent.js
+++ b/console/react/src/common/contextMenuComponent.js
@@ -62,6 +62,11 @@ class ContextMenuComponent extends React.Component {
             this.proxyClick(item, e);
           }}
         >
+          {this.props.suppress && item.suppressIcon && (
+            <span
+              className={`pficon pficon-${this.props.suppress} menu-item-icon`}
+            ></span>
+          )}
           {item.title}
         </li>
       );
diff --git a/console/react/src/overview/dashboard/layout.js 
b/console/react/src/overview/dashboard/layout.js
index e49ee26..1a0eef2 100644
--- a/console/react/src/overview/dashboard/layout.js
+++ b/console/react/src/overview/dashboard/layout.js
@@ -57,6 +57,8 @@ import { utils } from "../../common/amqp/utilities";
 import throughputData from "./throughputData";
 import inflightData from "./inflightData";
 
+const SUPPRESS_NOTIFICATIONS = "noNotify";
+
 class PageLayout extends React.PureComponent {
   constructor(props) {
     super(props);
@@ -70,7 +72,8 @@ class PageLayout extends React.PureComponent {
       isNavOpenMobile: false,
       isMobileView: false,
       user: "anonymous",
-      timePeriod: 60
+      timePeriod: 60,
+      suppress: JSON.parse(localStorage.getItem(SUPPRESS_NOTIFICATIONS)) || 
false
     };
     this.isDropdownOpen = false;
 
@@ -97,6 +100,7 @@ class PageLayout extends React.PureComponent {
     this.throughputChartData = new throughputData(this.service);
     this.inflightChartData = new inflightData(this.service);
     this.updateCharts();
+    document.title = this.props.config.title;
   };
 
   componentWillUnmount = () => {
@@ -273,6 +277,12 @@ class PageLayout extends React.PureComponent {
     }
   };
 
+  handleSuppress = () => {
+    this.setState({ suppress: !this.state.suppress ? "ok" : false }, () => {
+      localStorage.setItem(SUPPRESS_NOTIFICATIONS, 
JSON.stringify(this.state.suppress));
+    });
+  };
+
   render() {
     const { activeItem, activeGroup } = this.state;
     const { isNavOpenDesktop, isNavOpenMobile, isMobileView } = this.state;
@@ -327,7 +337,10 @@ class PageLayout extends React.PureComponent {
             </Button>
           </ToolbarItem>
           <ToolbarItem className="notification-button">
-            <NotificationDrawer ref={el => (this.notificationRef = el)} />
+            <NotificationDrawer
+              ref={el => (this.notificationRef = el)}
+              suppress={this.state.suppress}
+            />
           </ToolbarItem>
         </ToolbarGroup>
         <ToolbarGroup>
@@ -341,6 +354,8 @@ class PageLayout extends React.PureComponent {
               ref={el => (this.dropdownRef = el)}
               handleContextHide={this.handleUserMenuHide}
               handleDropdownLogout={this.handleDropdownLogout}
+              handleSuppress={this.handleSuppress}
+              suppress={this.state.suppress}
               isConnected={this.isConnected}
               parentClass="user-button"
             />
diff --git a/console/react/src/overview/dashboard/notificationDrawer.js 
b/console/react/src/overview/dashboard/notificationDrawer.js
index 81c8540..b6411e8 100644
--- a/console/react/src/overview/dashboard/notificationDrawer.js
+++ b/console/react/src/overview/dashboard/notificationDrawer.js
@@ -93,7 +93,7 @@ class NotificationDrawer extends React.Component {
     });
     event.isRead = false;
     accordionSections[section].events.unshift(event);
-    if (this.alertListRef && !silent) {
+    if (this.alertListRef && !silent && this.props.suppress === false) {
       this.alertListRef.addAlert(severity, message);
     }
     this.setState({
diff --git a/console/react/src/topology/svgUtils.js 
b/console/react/src/topology/svgUtils.js
index d441bcf..66ae160 100644
--- a/console/react/src/topology/svgUtils.js
+++ b/console/react/src/topology/svgUtils.js
@@ -35,7 +35,8 @@ export function updateState(circle) {
     })
     .classed("multiple", function(d) {
       return d.normals;
-    });
+    })
+    .classed("dropped", d => d.dropped);
 }
 
 export function appendCircle(g) {
diff --git a/console/react/src/topology/topoUtils.js 
b/console/react/src/topology/topoUtils.js
index 9acaa4b..8aed78a 100644
--- a/console/react/src/topology/topoUtils.js
+++ b/console/react/src/topology/topoUtils.js
@@ -292,6 +292,26 @@ export function reconcileArrays(existing, newArray) {
 // to the two nodes that it is linking.
 // So we need to fix the new links' source and target
 export function reconcileLinks(existingLinks, newLinks, existingNodes) {
+  // find links that are mirror images
+  newLinks.forEach(n => {
+    existingLinks.forEach(e => {
+      if (
+        e.suid === n.tuid &&
+        e.tuid === n.suid &&
+        e.left === n.right &&
+        e.right === n.left
+      ) {
+        e.suid = n.suid;
+        e.tuid = n.tuid;
+        e.left = n.left;
+        e.right = n.right;
+        e.uuid = n.uuid;
+        const tmp = e.source;
+        e.source = e.target;
+        e.target = tmp;
+      }
+    });
+  });
   reconcileArrays(existingLinks, newLinks);
   existingLinks.forEach(e => {
     // in new links, the source and target will be a number
diff --git a/console/react/src/topology/topologyViewer.js 
b/console/react/src/topology/topologyViewer.js
index 13d0e23..f7e400f 100644
--- a/console/react/src/topology/topologyViewer.js
+++ b/console/react/src/topology/topologyViewer.js
@@ -158,16 +158,14 @@ class TopologyViewer extends Component {
           if (!this.mounted) return;
 
           // create the svg
-          this.props.service.management.topology
-            .startUpdating(null, this.getEdgeNodes())
-            .then(() => {
-              this.init().then(() => {
-                if (!this.mounted) return;
-                // get notified when a router is added/dropped and when
-                // the number of connections for a router changes
-                this.topology.addChangedAction("topology", 
this.topologyChanged);
-              });
+          this.topology.startUpdating(null, this.getEdgeNodes()).then(() => {
+            this.init().then(() => {
+              if (!this.mounted) return;
+              // get notified when a router is added/dropped and when
+              // the number of connections for a router changes
+              this.topology.addChangedAction("topology", this.topologyChanged);
             });
+          });
         });
       });
   };
@@ -176,6 +174,21 @@ class TopologyViewer extends Component {
     let message;
     let silent = true;
     if (changed.connections.length > 0) {
+      // see if any routers have stale info
+      const nodeInfo = this.topology.nodeInfo();
+      for (let id in nodeInfo) {
+        const ds = this.forceData.nodes.nodes.filter(n => n.key === id);
+        ds.forEach(d => {
+          d.dropped = nodeInfo[id].connection.stale;
+        });
+        const links = this.forceData.links.links.filter(
+          l => l.source.key === id || l.target.key === id
+        );
+        links.forEach(l => {
+          l.dropped = nodeInfo[id].connection.stale;
+        });
+        this.restart();
+      }
       message = `${
         changed.connections[0].from > changed.connections[0].to ? "Lost" : 
"New"
       } connection for ${utils.nameFromId(changed.connections[0].router)}`;
@@ -581,6 +594,7 @@ class TopologyViewer extends Component {
       .classed("selected", d => d.selected)
       .classed("highlighted", d => d.highlighted)
       .classed("unknown", d => !d.right && !d.left)
+      .classed("dropped", d => d.dropped)
       // reset the markers based on current highlighted/selected
       .attr("marker-end", d => {
         if (!this.showMarker(d)) return null;
@@ -838,38 +852,36 @@ class TopologyViewer extends Component {
 
   reInit = () => {
     return new Promise(resolve => {
-      this.props.service.management.topology
-        .startUpdating(null, this.getEdgeNodes())
-        .then(() => {
-          const nodeInfo = this.topology.nodeInfo();
-          const newNodes = new Nodes(this.QDRLog);
-          const newLinks = new Links(this.QDRLog);
-          newNodes.initialize(nodeInfo, this.width, this.height, localStorage);
-          newLinks.initialize(
-            nodeInfo,
-            newNodes,
-            this.separateContainers,
-            [],
-            this.height,
-            localStorage
-          );
-          reconcileArrays(this.forceData.nodes.nodes, newNodes.nodes);
-          reconcileLinks(
-            this.forceData.links.links,
-            newLinks.links,
-            this.forceData.nodes.nodes
-          );
+      this.topology.startUpdating(null, this.getEdgeNodes()).then(() => {
+        const nodeInfo = this.topology.nodeInfo();
+        const newNodes = new Nodes(this.QDRLog);
+        const newLinks = new Links(this.QDRLog);
+        newNodes.initialize(nodeInfo, this.width, this.height, localStorage);
+        newLinks.initialize(
+          nodeInfo,
+          newNodes,
+          this.separateContainers,
+          [],
+          this.height,
+          localStorage
+        );
+        reconcileArrays(this.forceData.nodes.nodes, newNodes.nodes);
+        reconcileLinks(
+          this.forceData.links.links,
+          newLinks.links,
+          this.forceData.nodes.nodes
+        );
 
-          
this.force.nodes(this.forceData.nodes.nodes).links(this.forceData.links.links);
-          this.force.stop();
-          this.force.start();
-          this.restart();
-          this.circle.call(this.force.drag);
-          delete this.legend;
-          this.legend = new Legend(this.forceData.nodes, this.QDRLog);
-          this.updateLegend();
-          resolve();
-        });
+        
this.force.nodes(this.forceData.nodes.nodes).links(this.forceData.links.links);
+        this.force.stop();
+        this.force.start();
+        this.restart();
+        this.circle.call(this.force.drag);
+        delete this.legend;
+        this.legend = new Legend(this.forceData.nodes, this.QDRLog);
+        this.updateLegend();
+        resolve();
+      });
     });
   };
 
@@ -1102,14 +1114,14 @@ class TopologyViewer extends Component {
         {this.state.showRouterInfo && (
           <RouterInfoComponent
             d={this.d}
-            topology={this.props.service.management.topology}
+            topology={this.topology}
             handleCloseRouterInfo={this.handleCloseRouterInfo}
           />
         )}
         {this.state.showClientInfo && (
           <ClientInfoComponent
             d={this.d}
-            topology={this.props.service.management.topology}
+            topology={this.topology}
             handleCloseClientInfo={this.handleCloseClientInfo}
             handleSeparate={this.handleSeparate}
           />


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org
For additional commands, e-mail: commits-h...@qpid.apache.org

Reply via email to