GUI2 Bug fixes to Topo view

Change-Id: Ib40279fec94ffecb1d6c771aa376ad1cded03c02
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Traffic2Monitor.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Traffic2Monitor.java
index a4443062..4e78525 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Traffic2Monitor.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Traffic2Monitor.java
@@ -90,6 +90,7 @@
 
     @Override
     protected void sendSelectedIntentTraffic() {
+        log.debug("sendSelectedIntentTraffic: NOT IMPLEMENTED YET");
     }
 
     @Override
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/forcesvg.component.ts b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/forcesvg.component.ts
index b759997..b4bff8e 100644
--- a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/forcesvg.component.ts
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/forcesvg.component.ts
@@ -321,7 +321,7 @@
      */
     updateSelected(selectedNode: SelectedEvent): void {
         this.log.debug('Node or link ',
-            selectedNode.uiElement,
+            selectedNode.uiElement ? selectedNode.uiElement.id : '--',
             selectedNode.deselecting ? 'deselected' : 'selected',
             selectedNode.isShift ? 'Multiple' : '');
 
@@ -336,6 +336,12 @@
             this.selectedNodes.push(selectedNode.uiElement);
 
         } else if (selectedNode.deselecting) {
+            this.devices
+                .forEach((d) => d.deselect());
+            this.hosts
+                .forEach((h) => h.deselect());
+            this.links
+                .forEach((l) => l.deselect());
             this.selectedNodes = [];
 
         } else {
@@ -495,7 +501,7 @@
      * @param hosts - an array of host highlights
      * @param links - an array of link highlights
      */
-    handleHighlights(devices: Device[], hosts: Host[], links: LinkHighlight[]): void {
+    handleHighlights(devices: Device[], hosts: Host[], links: LinkHighlight[], fadeMs: number = 0): void {
 
         if (devices.length > 0) {
             this.log.debug(devices.length, 'Devices highlighted');
@@ -526,12 +532,15 @@
         if (links.length > 0) {
             this.log.debug(links.length, 'Links highlighted');
             links.forEach((lh) => {
-                const linkComponent: LinkSvgComponent = this.links.find((l) => l.link.id === lh.id );
+                const linkComponent: LinkSvgComponent =
+                    this.links.find((l) => l.link.id === Link.linkIdFromShowHighlights(lh.id) );
                 if (linkComponent) { // A link might not be present is hosts viewing is switched off
+                    if (fadeMs > 0) {
+                        lh.fadems = fadeMs;
+                    }
                     linkComponent.ngOnChanges(
                         {'linkHighlight': new SimpleChange(<LinkHighlight>{}, lh, true)}
                     );
-                    // this.log.debug('Highlighting link', linkComponent.link.id, lh.css, lh.label);
                 }
             });
         }
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/models/link.ts b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/models/link.ts
index 28f0b7c..7192de0 100644
--- a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/models/link.ts
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/models/link.ts
@@ -59,6 +59,29 @@
         return ep;
     }
 
+    /**
+     * The WSS event showHighlights is sent up with a slightly different
+     * name format on the link id using the "-" separator rather than the "~"
+     * @param linkId The id of the link in either format
+     */
+    public static linkIdFromShowHighlights(linkId: string) {
+        if (linkId.includes('-')) {
+            const parts: string[] = linkId.split('-');
+            const part0 = Link.removeHostPortNum(parts[0]);
+            const part1 = Link.removeHostPortNum(parts[1]);
+            return part0 + '~' + part1;
+        }
+        return linkId;
+    }
+
+    private static removeHostPortNum(hostStr: string) {
+        if (hostStr.includes('/None/')) {
+            const subparts = hostStr.split('/');
+            return subparts[0] + '/' + subparts[1];
+        }
+        return hostStr;
+    }
+
     constructor(source, target) {
         this.source = source;
         this.target = target;
@@ -88,4 +111,5 @@
     id: string;
     css: string;
     label: string;
+    fadems: number;
 }
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.html b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.html
index 8a5e1b5..35c3fd4 100644
--- a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.html
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.html
@@ -67,7 +67,7 @@
         overlaid on the above. This is the blue box, and its width and height does
         not change
     -->
-    <svg:rect x="-16" y="-16" width="32" height="32" style="fill: url(#diagonal_blue)">
+    <svg:rect x="-16" y="-16" width="32" height="32" [ngStyle]="{'fill': panelColour(0)}">
     </svg:rect>
     <svg:path *ngIf="device.location && device.location.locType != 'none'"
               d="M-15 12 v3 h5" style="stroke: white; stroke-width: 1; fill: none"></svg:path>
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.spec.ts b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.spec.ts
index b490605..b2f0592 100644
--- a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.spec.ts
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.spec.ts
@@ -16,7 +16,7 @@
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 
 import { DeviceNodeSvgComponent } from './devicenodesvg.component';
-import {IconService, LogService} from 'gui2-fw-lib';
+import {FnService, IconService, LogService} from 'gui2-fw-lib';
 import {ActivatedRoute, Params} from '@angular/router';
 import {of} from 'rxjs';
 import {ChangeDetectorRef} from '@angular/core';
@@ -35,9 +35,11 @@
 }
 
 describe('DeviceNodeSvgComponent', () => {
+    let fs: FnService;
     let logServiceSpy: jasmine.SpyObj<LogService>;
     let component: DeviceNodeSvgComponent;
     let fixture: ComponentFixture<DeviceNodeSvgComponent>;
+    let windowMock: Window;
     let ar: MockActivatedRoute;
     let testDevice: Device;
 
@@ -48,6 +50,19 @@
         testDevice = new Device('test:1');
         testDevice.online = true;
 
+        windowMock = <any>{
+            location: <any>{
+                hostname: 'foo',
+                host: 'foo',
+                port: '80',
+                protocol: 'http',
+                search: { debug: 'true' },
+                href: 'ws://foo:123/onos/ui/websock/path',
+                absUrl: 'ws://foo:123/onos/ui/websock/path'
+            }
+        };
+        fs = new FnService(ar, logSpy, windowMock);
+
         TestBed.configureTestingModule({
             imports: [ BrowserAnimationsModule ],
             declarations: [ DeviceNodeSvgComponent ],
@@ -55,7 +70,8 @@
                 { provide: LogService, useValue: logSpy },
                 { provide: ActivatedRoute, useValue: ar },
                 { provide: ChangeDetectorRef, useClass: ChangeDetectorRef },
-                { provide: IconService, useClass: MockIconService }
+                { provide: IconService, useClass: MockIconService },
+                { provide: 'Window', useValue: windowMock },
             ]
         })
         .compileComponents();
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.ts b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.ts
index 90bd2d3..d40f413 100644
--- a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.ts
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.ts
@@ -23,7 +23,7 @@
     SimpleChanges,
 } from '@angular/core';
 import {Device, LabelToggle, UiElement} from '../../models';
-import {IconService, LocMeta, LogService, MetaUi, ZoomUtils} from 'gui2-fw-lib';
+import {IconService, LocMeta, LogService, MetaUi, SvgUtilService, ZoomUtils} from 'gui2-fw-lib';
 import {NodeVisual, SelectedEvent} from '../nodevisual';
 import {animate, state, style, transition, trigger} from '@angular/animations';
 import {LocationType} from '../../../backgroundsvg/backgroundsvg.component';
@@ -73,6 +73,7 @@
     constructor(
         protected log: LogService,
         private is: IconService,
+        protected sus: SvgUtilService,
         private ref: ChangeDetectorRef
     ) {
         super();
@@ -131,4 +132,12 @@
             return 'm_' + this.device.type;
         }
     }
+
+    /**
+     * Get a colour for the banner of the nth panel
+     * @param idx The index of the panel (0-6)
+     */
+    panelColour(idx: number): string {
+        return this.sus.cat7().getColor(idx, false, '');
+    }
 }
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/linksvg/linksvg.component.ts b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/linksvg/linksvg.component.ts
index 9853889..85ef536 100644
--- a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/linksvg/linksvg.component.ts
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/forcesvg/visuals/linksvg/linksvg.component.ts
@@ -71,11 +71,14 @@
             this.highlighted = hl.css;
             this.label = hl.label;
             this.isHighlighted = true;
-            setTimeout(() => {
-                this.isHighlighted = false;
-                this.highlighted = '';
-                this.ref.markForCheck();
-            }, 4990);
+            this.log.debug('Link hightlighted', hl);
+            if (hl.fadems > 0) {
+                setTimeout(() => {
+                    this.isHighlighted = false;
+                    this.highlighted = '';
+                    this.ref.markForCheck();
+                }, hl.fadems);
+            }
 
         }
 
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/mapsvg/mapsvg.component.html b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/mapsvg/mapsvg.component.html
index cc2a794..d400ad5 100644
--- a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/mapsvg/mapsvg.component.html
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/layer/mapsvg/mapsvg.component.html
@@ -14,7 +14,7 @@
 ~ limitations under the License.
 -->
 <svg:desc xmlns:svg="http://www.w3.org/2000/svg">Map of {{map.id}} in SVG format</svg:desc>
-<svg:path class="topo-map"
+<svg:path id="bgmap" class="topo-map"
         *ngFor="let f of geodata?.features"
         xmlns:svg="http://www.w3.org/2000/svg"
         [attr.d]="pathGenerator(f)">
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/topology.service.ts b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/topology.service.ts
index 509a468..1f68444 100644
--- a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/topology.service.ts
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/topology.service.ts
@@ -78,6 +78,9 @@
                     this.log.debug('Region Data updated from WSS as topo2UiModelEvent', event.subject, event.data);
                 }
             ],
+            ['showHighlights', (event) => {
+                force.handleHighlights(event.devices, event.hosts, event.links);
+            }]
             // topo2Highlights is handled by TrafficService
         ]));
         this.handlers.push('topo2AllInstances');
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/topology/topology.component.html b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/topology/topology.component.html
index 1f6c07e..e7425d1 100644
--- a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/topology/topology.component.html
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/topology/topology.component.html
@@ -56,7 +56,7 @@
         are driven by the d3.force engine
     -->
     <svg:svg #svgZoom xmlns:svg="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" id="topo2"
-        preserveAspectRatio="xMaxYMax meet">
+        preserveAspectRatio="xMaxYMax meet" (click)="backgroundClicked($event)">
         <svg:desc>The main SVG canvas of the Topology View</svg:desc>
         <svg:g *ngIf="force.regionData?.devices[0].length +
                         force.regionData?.devices[1].length +
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/topology/topology.component.ts b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/topology/topology.component.ts
index 601159d..8ce1a6e 100644
--- a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/topology/topology.component.ts
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/topology/topology.component.ts
@@ -69,6 +69,7 @@
 import {ZoomableDirective} from '../layer/zoomable.directive';
 import {MapObject} from '../layer/maputils';
 import {LayoutService, LayoutType} from '../layout.service';
+import {SelectedEvent} from '../layer/forcesvg/visuals/nodevisual';
 
 const TOPO2_PREFS = 'topo2_prefs';
 const TOPO_MAPID_PREFS = 'topo_mapid';
@@ -86,6 +87,11 @@
 const PREF_TOOLBAR = 'toolbar';
 const PREF_PINNED = 'pinned';
 
+const BACKGROUND_ELEMENTS = [
+    'svg topo2',
+    'path bgmap'
+];
+
 /**
  * Model of the topo2_prefs object - this is a subset of the overall Prefs returned
  * by the server
@@ -599,7 +605,7 @@
     }
 
     protected equalizeMasters() {
-        this.wss.sendEvent('equalizeMasters', null);
+        this.wss.sendEvent('equalizeMasters', {});
         this.flashMsg = this.lionFn('fl_eq_masters');
         this.log.debug('equalizing masters');
     }
@@ -700,6 +706,18 @@
         this.log.debug('Map zoom prefs updated', zoomMapExtents);
     }
 
+    backgroundClicked(event: MouseEvent) {
+        const elemTagName = event.target['tagName'] + ' ' + event.target['id'];
+        if (BACKGROUND_ELEMENTS.includes(elemTagName)) {
+            this.force.updateSelected(
+                <SelectedEvent>{
+                    uiElement: undefined,
+                    deselecting: true
+                }
+            );
+        }
+    }
+
     /**
      * Read the LION bundle for Toolbar and set up the lionFn
      */
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/traffic.service.ts b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/traffic.service.ts
index 9aff0c7..6864414 100644
--- a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/traffic.service.ts
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/traffic.service.ts
@@ -54,7 +54,7 @@
     init(force: ForceSvgComponent) {
         this.wss.bindHandlers(new Map<string, (data) => void>([
             ['topo2Highlights', (data) => {
-                  force.handleHighlights(data.devices, data.hosts, data.links);
+                  force.handleHighlights(data.devices, data.hosts, data.links, 5000);
                 }
             ]
         ]));
@@ -75,6 +75,7 @@
     destroy() {
         this.wss.sendEvent('topo2CancelTraffic', {});
         this.wss.unbindHandlers(this.handlers);
+        this.handlers.pop();
         this.log.debug('Traffic monitoring canceled');
     }