GUI2 added in details panel, updated docs
Change-Id: I49a874deeb4de1082f190ea5d0d985c986a978f8
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/glyphdata.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/glyphdata.service.ts
index 2ff3e85..3703243 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/glyphdata.service.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/glyphdata.service.ts
@@ -546,6 +546,12 @@
['triangleUp', 'M0.5,6.2c0,0,3.8-3.8,4.2-4.2C5,1.7,5.3,2,5.3,2l4.3,' +
'4.3c0,0,0.4,0.4-0.1,0.4c-1.7,0-8.2,0-8.8,0C0,6.6,0.5,6.2,0.5,6.2z'],
+ ['triangleLeft', 'm 6.13,9.63 c 0,0 -3.8,-3.8 -4.2,-4.2 -0.3,-0.3 0,-0.6 0,' +
+ '-0.6 L 6.23,0.54 c 0,0 0.4,-0.4 0.4,0.1 0,1.7 0,8.2 0,8.8 -0.1,0.7 -0.5,0.2 -0.5,0.2 z'],
+
+ ['triangleRight', 'm 4.07,9.6 c 0,0 3.8,-3.8 4.2,-4.2 0.3,-0.3 0,-0.6 0,-0.6' +
+ 'l -4.3,-4.3 c 0,0 -0.4,-0.4 -0.4,0.1 0,1.7 0,8.2 0,8.8 0.1,0.7 0.5,0.2 0.5,0.2 z'],
+
['triangleDown', 'M9.5,4.2c0,0-3.8,3.8-4.2,4.2c-0.3,0.3-0.5,0-0.5,' +
'0L0.5,4.2c0,0-0.4-0.4,0.1-0.4c1.7,0,8.2,0,8.8,0C10,3.8,9.5,4.2,' +
'9.5,4.2z'],
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon.service.ts
index 5b801ab..766cc56 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon.service.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon.service.ts
@@ -40,11 +40,54 @@
['nonzero', 'nonzero'],
['close', 'xClose'],
+ ['m_cloud', 'm_cloud'],
+ ['m_map', 'm_map'],
+ ['m_selectMap', 'm_selectMap'],
+ ['thatsNoMoon', 'thatsNoMoon'],
['m_ports', 'm_ports'],
['m_switch', 'm_switch'],
['m_roadm', 'm_roadm'],
['m_router', 'm_router'],
+ ['m_uiAttached', 'm_uiAttached'],
['m_endstation', 'm_endstation'],
+ ['m_summary', 'm_summary'],
+ ['m_details', 'm_details'],
+ ['m_oblique', 'm_oblique'],
+ ['m_filters', 'm_filters'],
+ ['m_cycleLabels', 'm_cycleLabels'],
+ ['m_prev', 'm_prev'],
+ ['m_next', 'm_next'],
+ ['m_flows', 'm_flows'],
+ ['m_allTraffic', 'm_allTraffic'],
+ ['m_xMark', 'm_xMark'],
+ ['m_resetZoom', 'm_resetZoom'],
+ ['m_eqMaster', 'm_eqMaster'],
+ ['m_unknown', 'm_unknown'],
+ ['m_controller', 'm_controller'],
+ ['m_eqMaster', 'm_eqMaster'],
+ ['m_virtual', 'm_virtual'],
+ ['m_other', 'm_other'],
+ ['m_bgpSpeaker', 'm_bgpSpeaker'],
+ ['m_otn', 'm_otn'],
+ ['m_roadm_otn', 'm_roadm_otn'],
+ ['m_fiberSwitch', 'm_fiberSwitch'],
+ ['m_microwave', 'm_microwave'],
+ ['m_relatedIntents', 'm_relatedIntents'],
+ ['m_intentTraffic', 'm_intentTraffic'],
+ ['m_firewall', 'm_firewall'],
+ ['m_balancer', 'm_balancer'],
+ ['m_ips', 'm_ips'],
+ ['m_ids', 'm_ids'],
+ ['m_olt', 'm_olt'],
+ ['m_onu', 'm_onu'],
+ ['m_swap', 'm_swap'],
+ ['m_shortestGeoPath', 'm_shortestGeoPath'],
+ ['m_source', 'm_source'],
+ ['m_destination', 'm_destination'],
+ ['m_topo', 'm_topo'],
+ ['m_shortestPath', 'm_shortestPath'],
+ ['m_disjointPaths', 'm_disjointPaths'],
+ ['m_region', 'm_region'],
['topo', 'topo'],
['bird', 'bird'],
@@ -56,6 +99,8 @@
['upArrow', 'triangleUp'],
['downArrow', 'triangleDown'],
+ ['triangleLeft', 'triangleLeft'],
+ ['triangleRight', 'triangleRight'],
['appInactive', 'unknown'],
['uiAttached', 'uiAttached'],
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon/button-theme.css b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon/button-theme.css
new file mode 100644
index 0000000..8eff0a0
--- /dev/null
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon/button-theme.css
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Button Service (theme) -- CSS file
+ */
+
+
+/* === SELECTED BUTTONS === */
+
+/* Selected toggle / radio button */
+svg.embeddedIcon .toggleButton.selected .icon rect,
+svg.embeddedIcon .radioButton.selected .icon rect {
+ fill: #e4f0f6;
+}
+
+/* Selected:hover (normal) button */
+svg.embeddedIcon .button:hover .icon rect {
+ stroke: black;
+ stroke-width: 1px;
+}
+
+/* Selected:hover toggle-button */
+svg.embeddedIcon .toggleButton.selected:hover .icon rect {
+ fill: #c0d8f0;
+ stroke: black;
+ stroke-width: 1px;
+}
+
+/* Selected toggle/radio button and normal button glyph color */
+svg.embeddedIcon .button .glyph,
+svg.embeddedIcon .toggleButton.selected .glyph,
+svg.embeddedIcon .radioButton.selected .glyph {
+ fill: #5b99d2;
+}
+
+
+/* === UNSELECTED BUTTONS === */
+
+/* Unselected toggle / radio button */
+svg.embeddedIcon .toggleButton.icon rect,
+svg.embeddedIcon .radioButton.icon rect {
+ /* no fill */
+}
+
+/* Unselected:hover toggle / radio button */
+svg.embeddedIcon .icon.toggleButton:hover rect,
+svg.embeddedIcon .icon.radioButton:hover:not(.selected) rect {
+ fill: #e4f0f6;
+ stroke: black;
+ stroke-width: 1px;
+}
+
+/* Unselected toggle / radio button */
+svg.embeddedIcon .toggleButton .glyph,
+svg.embeddedIcon .radioButton .glyph {
+ fill: #bbb;
+}
+
+/* Unselected:hover toggle / radio button */
+svg.embeddedIcon .toggleButton:hover:not(.selected) .glyph,
+svg.embeddedIcon .radioButton:hover:not(.selected) .glyph {
+ fill: #5b99d2;
+}
+
+
+/* ========== DARK Theme ========== */
+
+/* Selected toggle / radio button */
+.dark .toggleButton.selected svg.embeddedIcon .icon rect,
+.dark .radioButton.selected svg.embeddedIcon .icon rect {
+ fill: #353e45;
+}
+
+/* Selected:hover (normal) button */
+.dark .button:hover svg.embeddedIcon .icon rect {
+ stroke: white;
+ stroke-width: 1px;
+}
+
+/* Selected:hover toggle-button */
+.dark .toggleButton.selected:hover svg.embeddedIcon .icon rect {
+ fill: #444d54;
+ stroke: white;
+ stroke-width: 1px;
+}
+
+/* Selected toggle/radio button and normal button glyph color */
+.dark .button svg.embeddedIcon .glyph,
+.dark .toggleButton.selected svg.embeddedIcon .glyph,
+.dark .radioButton.selected svg.embeddedIcon .glyph {
+ fill: #5b99d2;
+}
+
+
+/* === UNSELECTED BUTTONS === */
+
+/* Unselected toggle / radio button */
+.dark .toggleButton svg.embeddedIcon .icon rect,
+.dark .radioButton svg.embeddedIcon .icon rect {
+ /* no fill */
+}
+
+/* Unselected:hover toggle / radio button */
+.dark .toggleButton:hover svg.embeddedIcon .icon rect,
+.dark .radioButton:hover:not(.selected) svg.embeddedIcon .icon rect {
+ fill: #353e45;
+ stroke: white;
+ stroke-width: 1px;
+}
+
+/* Unselected toggle / radio button */
+.dark .toggleButton svg.embeddedIcon .glyph,
+.dark .radioButton svg.embeddedIcon .glyph {
+ fill: #bbb;
+}
+
+/* Unselected:hover toggle / radio button */
+.dark .toggleButton:hover:not(.selected) svg.embeddedIcon .glyph,
+.dark .radioButton:hover:not(.selected) svg.embeddedIcon .glyph {
+ fill: #5b99d2;
+}
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon/icon.component.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon/icon.component.ts
index d05c7ed..ad8d382 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon/icon.component.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/icon/icon.component.ts
@@ -33,7 +33,7 @@
styleUrls: [
'./icon.component.css', './icon.theme.css',
'./glyph.css', './glyph-theme.css',
- './tooltip.css', './tooltip-theme.css'
+ './tooltip.css', './button-theme.css'
]
})
export class IconComponent implements OnInit, OnChanges {
diff --git a/web/gui2/AngularMigration.md b/web/gui2/AngularMigration.md
index d706255..ad8ee7d 100644
--- a/web/gui2/AngularMigration.md
+++ b/web/gui2/AngularMigration.md
@@ -298,7 +298,7 @@
so that the enclosing context can be passed in to the lambda
-# Progress so far - Nov 2018
+# Progress so far - Dec 2018
The following services are most migrated:
* fw/util/FnService - full migrated with Unit tests
* fw/svg/GlyphDataService - mostly migrated. Values are stored in maps as constants
@@ -388,13 +388,15 @@
are the __layout__ components. In addition some are SVG components that are
designed to extend an SVG element tree, rather than a HTML one.
+Also the icons have got a fresh new look with gradients and drop shadows done in SVG.
+
All of this will ultimately lead to a framework that can support other paradigms
especially ones like tiles background maps, such as this from Google and other
providers.
-There is still quite a way to go to finish this consolidated Topology view (as of
-Nov '18), as there are updated vesions of the D3 Force library and the D3 Zoom
-library to migrate to.
+This has progressed a lot since the first version in Nov 18. Now traffic flows are
+represented as well as node and host labels and link hovering etc. Zoom and Pan
+have been added as well as many of the keyboard shortcuts, familiar from Topo1
The Topology view will eventually be broken out in to its own library, to promote
reuse.
\ No newline at end of file
diff --git a/web/gui2/README.md b/web/gui2/README.md
index 8f97312..50f5077 100644
--- a/web/gui2/README.md
+++ b/web/gui2/README.md
@@ -57,11 +57,12 @@
This will install all the vendor Javascript implementations that are listed in package.json
(including 'ng' - the Angular CLI command) in to ~/onos/web/gui2-fw-lib/node_modules
-After this you should be able to cd in to ~/onos/web/gui2-fw-lib and run 'ng -v' and see:
+After this you should be able to cd in to ~/onos/web/gui2-fw-lib and run 'ng version' and see:
```
-Angular CLI: 6.0.0
+Angular CLI: 7.0.4
Node: 8.11.1
OS: linux x64
+Angular: 7.0.2
```
## GUI FW Lib
@@ -77,7 +78,8 @@
ng build gui2-fw-lib && \
cd dist/gui2-fw-lib && \
npm pack && \
-popd
+popd && \
+npm install gui2-fw-lib
```
To test and lint it use
diff --git a/web/gui2/package-lock.json b/web/gui2/package-lock.json
index dcafb26..81356c1 100644
--- a/web/gui2/package-lock.json
+++ b/web/gui2/package-lock.json
@@ -5560,7 +5560,7 @@
},
"gui2-fw-lib": {
"version": "file:../gui2-fw-lib/dist/gui2-fw-lib/gui2-fw-lib-2.0.0.tgz",
- "integrity": "sha512-4PrjcISAfAmMAajZJ/BUXytnXjs+nuGxMIbSQqkzyWwIgMySql+NjavvAQkRyHX6551jm7ZMIo3p4J6Z4IlH8A==",
+ "integrity": "sha512-DRtcy4kDWJxMllozKJpiS4H820mxXmP01bU91qb5sYa/0HjiuihlOiJhvF4Kyg4hUfISNF+bhDeFwr3UgI5xtA==",
"requires": {
"tslib": "1.9.3"
}
diff --git a/web/gui2/src/main/webapp/app/view/topology/README.md b/web/gui2/src/main/webapp/app/view/topology/README.md
index 3f3e647..35acd31 100644
--- a/web/gui2/src/main/webapp/app/view/topology/README.md
+++ b/web/gui2/src/main/webapp/app/view/topology/README.md
@@ -2,7 +2,8 @@
This is the GUI2 version of the combined Topo and Topo2 views of the older version.
-It uses Angular 6 components extensively.
+It uses Angular 7 components extensively. TopologyComponent is the starting point
+for everything in it.
This should all be moved to its own separate library once all debugging is done
(it is slightly more difficult to debug the code when in a separate library)
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.html b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.html
index af33384..c4930c1 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.html
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.html
@@ -1,5 +1,5 @@
<!--
-~ Copyright 2018-present Open Networking Foundation
+~ Copyright 2019-present Open Networking Foundation
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -13,76 +13,67 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<svg:g class="topo2-force" xmlns:svg="http://www.w3.org/2000/svg">
- <svg:g id="new-zoom-layer">
- <svg:g class="topo2-links">
- <!-- Template explanation: Creates an SVG Group and in
- line 1) use the svg component onos-linksvg, setting it's link
- Input parameter to the link item from the next line
- line 2) Use the built in NgFor directive to iterate through the
- set of links filtered by the filteredLinks() function.
- -->
- <svg:g onos-linksvg [link]="link"
- *ngFor="let link of filteredLinks()"
- (selectedEvent)="updateSelected($event)">
- </svg:g>
- </svg:g>
- <svg:g class="topo2-linkLabels" />
- <svg:g class="topo2-numLinkLabels" />
- <svg:g class="topo2-nodes">
- <!-- Template explanation - create an SVG Group and
- line 1) use the svg component onos-devicenodesvg, setting it's device
- Input parameter to the device item from the next line
- line 2) Use the built in NgFor directive to iterate through all
- of the devices in the chosen layer index. The current iteration
- is in the device variable
- line 3) Use the onosDraggable directive and pass this device in to
- its draggableNode Input parameter and setting the draggableInGraph
- Input parameter to 'graph'
- line 4) when the onos-devicenodesvg component emits the selectedEvent
- call the updateSelected() method of this (forcesvg) component
- -->
- <svg:g onos-devicenodesvg [device]="device"
- *ngFor="let device of regionData.devices[visibleLayerIdx()]"
- onosDraggableNode [draggableNode]="device" [draggableInGraph]="graph"
- (selectedEvent)="updateSelected($event)">
- </svg:g>
- <!-- Template explanation - only display the hosts if 'showHosts' is set true -->
- <svg:g *ngIf="showHosts">
- <!-- Template explanation - create an SVG Group and
- line 1) use the svg component onos-hostnodesvg, setting it's host
- Input parameter to the host item from the next line
- line 2) Use the built in NgFor directive to iterate through all
- of the hosts in the chosen layer index. The current iteration
- is in the 'host' variable
- line 3) Use the onosDraggable directive and pass this host in to
- its draggableNode Input parameter and setting the draggableInGraph
- Input parameter to 'graph'
- line 4) when the onos-hostnodesvg component emits the selectedEvent
- call the updateSelected() method of this (forcesvg) component
- -->
- <svg:g onos-hostnodesvg [host]="host"
- *ngFor="let host of regionData.hosts[visibleLayerIdx()]"
- onosDraggableNode [draggableNode]="host" [draggableInGraph]="graph"
- (selectedEvent)="updateSelected($event)">
- </svg:g>
- </svg:g>
- <svg:g onos-subregionnodesvg [subRegion]="subRegion"
- *ngFor="let subRegion of regionData.subregions"
- onosDraggableNode [draggableNode]="host" [draggableInGraph]="graph">
- </svg:g>
+<svg:desc xmlns:svg="http://www.w3.org/2000/svg">The force layout layer. This is
+ an SVG component that displays Nodes (Devices, Hosts and SubRegions) and
+ Links. Positions of each are driven by a forces computation engine</svg:desc>
+<svg:g xmlns:svg="http://www.w3.org/2000/svg" class="topo2-links">
+ <svg:desc>Topology links</svg:desc>
+ <!-- Template explanation: Creates an SVG Group and in
+ line 1) use the svg component onos-linksvg, setting it's link
+ Input parameter to the link item from the next line
+ line 2) Use the built in NgFor directive to iterate through the
+ set of links filtered by the filteredLinks() function.
+ -->
+ <svg:g onos-linksvg [link]="link"
+ *ngFor="let link of filteredLinks()"
+ [highlightsEnabled]="highlightPorts"
+ (selectedEvent)="updateSelected($event)">
+ </svg:g>
+</svg:g>
+<svg:g xmlns:svg="http://www.w3.org/2000/svg" class="topo2-nodes">
+ <svg:desc>Topology nodes</svg:desc>
+ <!-- Template explanation - create an SVG Group and
+ line 1) use the svg component onos-devicenodesvg, setting it's device
+ Input parameter to the device item from the next line
+ line 2) Use the built in NgFor directive to iterate through all
+ of the devices in the chosen layer index. The current iteration
+ is in the device variable
+ line 3) Use the onosDraggable directive and pass this device in to
+ its draggableNode Input parameter and setting the draggableInGraph
+ Input parameter to 'graph'
+ line 4) when the onos-devicenodesvg component emits the selectedEvent
+ call the updateSelected() method of this (forcesvg) component
+ -->
+ <svg:g onos-devicenodesvg [device]="device"
+ *ngFor="let device of regionData.devices[visibleLayerIdx()]"
+ onosDraggableNode [draggableNode]="device" [draggableInGraph]="graph"
+ (selectedEvent)="updateSelected($event)">
+ <svg:desc>Device nodes</svg:desc>
+ </svg:g>
+ <!-- Template explanation - only display the hosts if 'showHosts' is set true -->
+ <svg:g *ngIf="showHosts">
+ <!-- Template explanation - create an SVG Group and
+ line 1) use the svg component onos-hostnodesvg, setting it's host
+ Input parameter to the host item from the next line
+ line 2) Use the built in NgFor directive to iterate through all
+ of the hosts in the chosen layer index. The current iteration
+ is in the 'host' variable
+ line 3) Use the onosDraggable directive and pass this host in to
+ its draggableNode Input parameter and setting the draggableInGraph
+ Input parameter to 'graph'
+ line 4) when the onos-hostnodesvg component emits the selectedEvent
+ call the updateSelected() method of this (forcesvg) component
+ -->
+ <svg:g onos-hostnodesvg [host]="host"
+ *ngFor="let host of regionData.hosts[visibleLayerIdx()]"
+ onosDraggableNode [draggableNode]="host" [draggableInGraph]="graph"
+ (selectedEvent)="updateSelected($event)">
+ <svg:desc>Host nodes</svg:desc>
</svg:g>
</svg:g>
- <!--<svg:g class="topo2-portLabels">-->
- <!--<!–TODO make each of these in to a component that can be inserted –>-->
- <!--<svg:g *ngIf="selectedLink !== null" id="topo-port-src" class="portLabel" opacity="1">-->
- <!--<rect x="0" y="0" width="1" height="1" [ngStyle]="{'transform': 'scale(1)'}"></rect>-->
- <!--<text dy="0.3em" [ngStyle]="{'transform': 'scale(1)'}">{{ selectedLink.portA }}</text>-->
- <!--</svg:g>-->
-
- <!--<svg:g *ngIf="selectedLink !== null" id="topo-port-tgt" class="portLabel" opacity="1">-->
- <!--<rect x="0" y="0" width="1" height="1" [ngStyle]="{'transform': 'scale(1)'}"></rect>-->
- <!--<text dy="0.3em" [ngStyle]="{'transform': 'scale(1)'}">{{ selectedLink.portA }}</text>-->
- <!--</svg:g>-->
- <!--</svg:g>-->
+ <svg:g onos-subregionnodesvg [subRegion]="subRegion"
+ *ngFor="let subRegion of regionData.subregions"
+ onosDraggableNode [draggableNode]="host" [draggableInGraph]="graph">
+ <svg:desc>Subregion nodes</svg:desc>
+ </svg:g>
</svg:g>
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.spec.ts
index 6b1980a..7a30d75 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.spec.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.spec.ts
@@ -16,7 +16,7 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ForceSvgComponent } from './forcesvg.component';
-import {IconService, LogService} from 'gui2-fw-lib';
+import {LogService} from 'gui2-fw-lib';
import {
DeviceNodeSvgComponent,
HostNodeSvgComponent, LinkSvgComponent,
@@ -33,10 +33,6 @@
}
}
-class MockIconService {
- loadIconDef() { }
-}
-
describe('ForceSvgComponent', () => {
let ar: MockActivatedRoute;
let windowMock: Window;
@@ -71,7 +67,6 @@
],
providers: [
{ provide: LogService, useValue: logSpy },
- { provide: IconService, useClass: MockIconService },
]
})
.compileComponents();
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.ts b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.ts
index 25e52ab..b0b4a0c 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.ts
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-present Open Networking Foundation
+ * Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@
SimpleChanges,
ViewChildren
} from '@angular/core';
-import {IconService, LogService} from 'gui2-fw-lib';
+import {LogService} from 'gui2-fw-lib';
import {
Device,
ForceDirectedGraph,
@@ -71,6 +71,7 @@
@Output() selectedNodeEvent = new EventEmitter<UiElement>();
@Input() selectedLink: RegionLink = null;
@Input() showHosts: boolean = false;
+ @Input() highlightPorts: boolean = true;
@Input() deviceLabelToggle: LabelToggle = LabelToggle.NONE;
@Input() hostLabelToggle: HostLabelToggle = HostLabelToggle.NONE;
@Input() regionData: Region = <Region>{devices: [ [], [], [] ], hosts: [ [], [], [] ], links: []};
@@ -85,7 +86,6 @@
constructor(
protected log: LogService,
- protected is: IconService,
private ref: ChangeDetectorRef
) {
this.selectedLink = null;
@@ -141,10 +141,6 @@
});
this.log.debug('ForceSvgComponent initialized - waiting for nodes and links');
- this.is.loadIconDef('m_switch');
- this.is.loadIconDef('m_roadm');
- this.is.loadIconDef('m_router');
- this.is.loadIconDef('m_endstation');
}
/**
@@ -206,6 +202,10 @@
this.showHosts = changes['showHosts'].currentValue;
}
+ if (changes['highlightPorts']) {
+ this.highlightPorts = changes['highlightPorts'].currentValue;
+ }
+
// Pass on the changes to device
if (changes['deviceLabelToggle']) {
this.deviceLabelToggle = changes['deviceLabelToggle'].currentValue;
@@ -258,7 +258,7 @@
* @param selectedNode the newly selected node
*/
updateSelected(selectedNode: UiElement): void {
- this.log.debug('Node or link selected', selectedNode);
+ this.log.debug('Node or link selected', selectedNode ? selectedNode.id : 'none');
this.devices
.filter((d) =>
selectedNode === undefined || d.device.id !== selectedNode.id)
@@ -272,7 +272,7 @@
.filter((l) =>
selectedNode === undefined || l.link.id !== selectedNode.id)
.forEach((l) => l.deselect());
-
+ // Push the changes back up to parent (Topology Component)
this.selectedNodeEvent.emit(selectedNode);
}
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/models/link.ts b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/models/link.ts
index eb6d340..28f0b7c 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/models/link.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/models/link.ts
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-present Open Networking Foundation
+ * Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
@@ -52,6 +52,13 @@
source: Node;
target: Node;
+ public static deviceNameFromEp(ep: string): string {
+ if (ep !== undefined && ep.lastIndexOf('/') > 0) {
+ return ep.substr(0, ep.lastIndexOf('/'));
+ }
+ return ep;
+ }
+
constructor(source, target) {
this.source = source;
this.target = target;
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.html b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.html
index 70d4d5b..08ccaec 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.html
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.html
@@ -1,5 +1,5 @@
<!--
-~ Copyright 2018-present Open Networking Foundation
+~ Copyright 2019-present Open Networking Foundation
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -84,9 +84,6 @@
[@deviceLabelToggleTxt]="labelToggle">
{{ labelToggle == 0 ? '': labelToggle == 1 ? device.id:device.props.name }}
</svg:text>
- <!-- It's not possible to drive the following xref dynamically -->
- <svg:use *ngIf="device.type == 'switch'" xlink:href="#m_switch" width="36" height="36" x="-18" y="-18">
- </svg:use>
- <svg:use *ngIf="device.type == 'roadm'" xlink:href="#m_roadm" width="36" height="36" x="-18" y="-18">
+ <svg:use [attr.xlink:href]="'#m_' + device.type" width="36" height="36" x="-18" y="-18">
</svg:use>
</svg:g>
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/linksvg/linksvg.component.ts b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/linksvg/linksvg.component.ts
index 8202c67..af4d0a9 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/linksvg/linksvg.component.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/linksvg/linksvg.component.ts
@@ -53,6 +53,7 @@
export class LinkSvgComponent extends NodeVisual implements OnChanges {
@Input() link: Link;
@Input() highlighted: string = '';
+ @Input() highlightsEnabled: boolean = true;
@Input() label: string;
isHighlighted: boolean = false;
@Output() selectedEvent = new EventEmitter<UiElement>();
@@ -86,6 +87,9 @@
}
enhance() {
+ if (!this.highlightsEnabled) {
+ return;
+ }
this.enhancedEvent.emit(this.link);
this.enhanced = true;
this.repositionLabels();
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.css b/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.css
deleted file mode 100644
index beb3725..0000000
--- a/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.css
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright 2018-present Open Networking Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.html b/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.html
deleted file mode 100644
index 8fe566b..0000000
--- a/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!--
-~ Copyright 2018-present Open Networking Foundation
-~
-~ Licensed under the Apache License, Version 2.0 (the "License");
-~ you may not use this file except in compliance with the License.
-~ You may obtain a copy of the License at
-~
-~ http://www.apache.org/licenses/LICENSE-2.0
-~
-~ Unless required by applicable law or agreed to in writing, software
-~ distributed under the License is distributed on an "AS IS" BASIS,
-~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-~ See the License for the specific language governing permissions and
-~ limitations under the License.
--->
-<p>
- layout works!
-</p>
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.spec.ts
deleted file mode 100644
index 1691947..0000000
--- a/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.spec.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2018-present Open Networking Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { LayoutComponent } from './layout.component';
-
-describe('LayoutComponent', () => {
- let component: LayoutComponent;
- let fixture: ComponentFixture<LayoutComponent>;
-
- beforeEach(async(() => {
- TestBed.configureTestingModule({
- declarations: [ LayoutComponent ]
- })
- .compileComponents();
- }));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(LayoutComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.ts b/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.ts
deleted file mode 100644
index 122c14b..0000000
--- a/web/gui2/src/main/webapp/app/view/topology/layer/layout/layout.component.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2018-present Open Networking Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import { Component, OnInit } from '@angular/core';
-
-@Component({
- selector: 'onos-layout',
- templateUrl: './layout.component.html',
- styleUrls: ['./layout.component.css']
-})
-export class LayoutComponent implements OnInit {
-
- constructor() { }
-
- ngOnInit() {
- }
-
-}
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.html b/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.html
index 9233713..17fba06 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.html
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.html
@@ -16,6 +16,6 @@
<svg:g xmlns:svg="http://www.w3.org/2000/svg" id="topo-noDevsLayer" transform="translate(500,500)" style="visibility: visible;">
<svg:g id="reposition" #reposition [attr.transform]="centre(reposition.getBBox())">
<svg:use width="100" height="100" class="noDevsBird" href="#bird"></svg:use>
- <svg:text x="120" y="80">No Devices Are Connected</svg:text>
+ <svg:text x="120" y="80">{{lionFn('no_devices_are_connected')}}</svg:text>
</svg:g>
</svg:g>
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.spec.ts
index a467a3d..891a3fb 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.spec.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.spec.ts
@@ -26,7 +26,7 @@
UrlFnService,
TableFilterPipe,
IconComponent,
- WebSocketService
+ WebSocketService, SvgUtilService, PrefsService
} from 'gui2-fw-lib';
import { of } from 'rxjs';
@@ -37,11 +37,6 @@
}
}
-class MockIconService {
- classes = 'active-close';
- loadIconDef() { }
-}
-
class MockWebSocketService {
createWebSocket() { }
isConnected() { return false; }
@@ -49,6 +44,15 @@
bindHandlers() { }
}
+class MockSvgUtilService {
+ translate() {}
+ scale() {}
+}
+
+class MockPrefsService {
+}
+
+
/**
* ONOS GUI -- Topology NoDevicesConnected -- Unit Tests
*/
@@ -73,9 +77,10 @@
declarations: [ NoDeviceConnectedSvgComponent ],
providers: [
{ provide: FnService, useValue: fs },
- { provide: IconService, useClass: MockIconService },
{ provide: LogService, useValue: logSpy },
+ { provide: SvgUtilService, useClass: MockSvgUtilService },
{ provide: WebSocketService, useClass: MockWebSocketService },
+ { provide: PrefsService, useClass: MockPrefsService },
{ provide: 'Window', useValue: windowMock },
]
}).compileComponents();
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.ts b/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.ts
index 2ff9ed1..a245fad 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component.ts
@@ -20,7 +20,7 @@
LogService,
PrefsService,
IconService,
- SvgUtilService
+ SvgUtilService, LionService
} from 'gui2-fw-lib';
/**
@@ -37,16 +37,24 @@
styleUrls: ['./nodeviceconnectedsvg.component.css']
})
export class NoDeviceConnectedSvgComponent extends ViewControllerImpl implements OnInit {
+ lionFn; // Function
constructor(
protected fs: FnService,
protected log: LogService,
protected ps: PrefsService,
- protected is: IconService,
- protected sus: SvgUtilService
+ protected sus: SvgUtilService,
+ private lion: LionService
) {
super(fs, log, ps);
- this.is.loadIconDef('bird');
+
+ if (this.lion.ubercache.length === 0) {
+ this.lionFn = this.dummyLion;
+ this.lion.loadCbs.set('topo-nodevices', () => this.doLion());
+ } else {
+ this.doLion();
+ }
+
this.log.debug('NoDeviceConnectedSvgComponent constructed');
}
@@ -64,4 +72,19 @@
return this.sus.translate([repositionBox.x, repositionBox.y]) + '' + this.sus.scale(scale, scale);
}
+ /**
+ * Read the LION bundle for Details panel and set up the lionFn
+ */
+ doLion() {
+ this.lionFn = this.lion.bundle('core.view.Topo');
+
+ }
+
+ /**
+ * A dummy implementation of the lionFn until the response is received and the LION
+ * bundle is received from the WebSocket
+ */
+ dummyLion(key: string): string {
+ return '%' + key + '%';
+ }
}
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/zoomable.directive.ts b/web/gui2/src/main/webapp/app/view/topology/layer/zoomable.directive.ts
index c956627..bd69db1 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/zoomable.directive.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/zoomable.directive.ts
@@ -28,6 +28,9 @@
private log: LogService,
) {}
+ /**
+ * If the input object is changed then re-establish the zoom
+ */
ngOnChanges() {
let zoomed, zoom;
@@ -44,4 +47,13 @@
this.log.debug('Applying zoomable behaviour on', this.zoomableOf, this._element.nativeElement);
}
+ /**
+ * Reset the zoom when the R key is pressed when in Topology view
+ */
+ resetZoom(): void {
+ const container = d3.select(this._element.nativeElement);
+ container.attr('transform', 'translate(0,0) scale(1.0)');
+ this.log.debug('Pan to 0,0 and zoom to 1.0');
+ }
+
}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.css b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.css
index 9a35cb3..9ddfe17 100644
--- a/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.css
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.css
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-present Open Networking Foundation
+ * Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,18 +19,18 @@
padding: 16px;
top: 370px;
}
-html[data-platform='iPad'] #topo2-p-detail {
+html[data-platform='iPad'] {
top: 386px;
}
-#topo2-p-detail .actionBtns .actionBtn {
+.actionBtns .actionBtn {
display: inline-block;
}
-#topo2-p-detail .actionBtns .actionBtn svg {
+.actionBtns .actionBtn svg {
width: 28px;
height: 28px;
}
-#topo2-p-detail div.actionBtns {
+div.actionBtns {
padding-top: 6px;
}
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.html b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.html
index d79954b..405fdfc 100644
--- a/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.html
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.html
@@ -1,5 +1,5 @@
<!--
-~ Copyright 2018-present Open Networking Foundation
+~ Copyright 2019-present Open Networking Foundation
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,112 +15,52 @@
-->
<div id="topo2-p-detail" class="floatpanel topo2-p"
style="opacity: 1; right: 20px; width: 260px; top: 350px;" [@detailsPanelState]="on">
+ <!-- Template explanation - Create a HTML header which has an SVG icon along
+ side title text. -->
<div class="header">
<div class="icon clickable">
- <svg>
- <use width="26" height="26" class="glyph" xlink:href="#m_switch"></use>
- </svg>
+ <onos-icon
+ [iconSize]="26"
+ [iconId]="showDetails?.glyphId">
+ </onos-icon>
</div>
- <h2 class="clickable">{{ selectedNode?.id }}</h2>
+ <h2 class="clickable">{{ showDetails?.title }}</h2>
</div>
<div class="body">
<table>
<tbody>
- <tr>
- <td class="label">URI :</td>
- <td class="value">{{ selectedNode?.id }}</td>
- </tr>
- <tr>
- <td class="label">Vendor :</td>
- <td class="value">ONF</td>
- </tr>
- <tr>
- <td class="label">H/W Version :</td>
- <td class="value">0.1</td>
- </tr>
- <tr>
- <td class="label">S/W Version :</td>
- <td class="value">0.1</td>
- </tr>
- <tr>
- <td class="label">Serial # :</td>
- <td class="value">1234</td>
- </tr>
- <tr>
- <td class="label">Protocol :</td>
- <td class="value"></td>
- </tr>
- <tr>
- <td colspan="2">
- <hr>
- </td>
- </tr>
- <tr>
- <td class="label">Ports :</td>
- <td class="value">4</td>
- </tr>
- <tr>
- <td class="label">Flows :</td>
- <td class="value">4</td>
- </tr>
- <tr>
- <td class="label">Tunnels :</td>
- <td class="value">0</td>
- </tr>
+ <!-- Template explanation - Inside a HTML table, create a row per
+ item in the propOrder array returned through the WSS showDetails.
+ If the row name contains only '-' then draw a horiz rule otherwise
+ create a cell for the name and another for the value -->
+ <tr *ngFor="let p of showDetails?.propOrder">
+ <td *ngIf="showDetails?.propLabels[p] !== '-'"
+ class="label">{{showDetails?.propLabels[p]}} :</td>
+ <td *ngIf="showDetails?.propLabels[p] !== '-'"
+ class="value">{{ showDetails?.propValues[p]}}</td>
+ <!-- If the label is '-' then insert a horiz line -->
+ <td *ngIf="showDetails?.propLabels[p] === '-'"
+ colspan="2"><hr></td>
+ </tr>
</tbody>
</table>
</div>
<div class="footer">
<hr>
<div class="actionBtns">
- <div class="actionBtn">
- <div class="button" id="topo2-p-detail-core-showDeviceView">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#switch"></use>
- </g>
- </svg>
- </div>
- </div>
- <div class="actionBtn">
- <div class="button" id="topo2-p-detail-core-showFlowView">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#flowTable"></use>
- </g>
- </svg>
- </div>
- </div>
- <div class="actionBtn">
- <div class="button" id="topo2-p-detail-core-showPortView">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#portTable"></use>
- </g>
- </svg>
- </div>
- </div>
- <div class="actionBtn">
- <div class="button" id="topo2-p-detail-core-showGroupView">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#groupTable"></use>
- </g>
- </svg>
- </div>
- </div>
- <div class="actionBtn">
- <div class="button" id="topo2-p-detail-core-showMeterView">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#meterTable"></use>
- </g>
- </svg>
+ <!-- Template explanation - Inside the panel footer, create an SVG icon
+ per entry in the buttons array returned from the WSS showDetails
+ The icons used here are loaded in the ForceSvgComponent
+ -->
+ <div *ngFor="let btn of showDetails?.buttons" class="actionBtn">
+ <div class="button" id="topo2-p-detail-core-{{ btn }}"
+ (click)="navto(buttonAttribs(btn).path, showDetails.navPath, showDetails.id)">
+ <onos-icon
+ [iconSize]="25"
+ [iconId]="buttonAttribs(btn).gid"
+ [toolTip]="lionFn(buttonAttribs(btn).tt)"
+ classes="icon">
+ </onos-icon>
</div>
</div>
</div>
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.spec.ts
index 0c0c269..620d931 100644
--- a/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.spec.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.spec.ts
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-present Open Networking Foundation
+ * Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,9 +20,10 @@
import { DetailsComponent } from './details.component';
import {
- FnService,
- LogService
+ FnService, LionService,
+ LogService, IconComponent
} from 'gui2-fw-lib';
+import {RouterTestingModule} from '@angular/router/testing';
class MockActivatedRoute extends ActivatedRoute {
constructor(params: Params) {
@@ -42,6 +43,15 @@
let component: DetailsComponent;
let fixture: ComponentFixture<DetailsComponent>;
+ const bundleObj = {
+ 'core.view.Flow': {
+ test: 'test1'
+ }
+ };
+ const mockLion = (key) => {
+ return bundleObj[key] || '%' + key + '%';
+ };
+
beforeEach(async(() => {
const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
ar = new MockActivatedRoute({ 'debug': 'txrx' });
@@ -60,11 +70,20 @@
fs = new FnService(ar, logSpy, windowMock);
TestBed.configureTestingModule({
- imports: [ BrowserAnimationsModule ],
- declarations: [ DetailsComponent ],
+ imports: [ BrowserAnimationsModule, RouterTestingModule ],
+ declarations: [ DetailsComponent, IconComponent ],
providers: [
{ provide: FnService, useValue: fs },
{ provide: LogService, useValue: logSpy },
+ {
+ provide: LionService, useFactory: (() => {
+ return {
+ bundle: ((bundleId) => mockLion),
+ ubercache: new Array(),
+ loadCbs: new Map<string, () => void>([])
+ };
+ })
+ },
{ provide: 'Window', useValue: windowMock },
]
})
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.ts b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.ts
index 935b2ce..f63d99a 100644
--- a/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/details/details.component.ts
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-present Open Networking Foundation
+ * Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,20 +13,77 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {Component, Input, OnInit} from '@angular/core';
-import { animate, state, style, transition, trigger } from '@angular/animations';
import {
- LogService,
- LoadingService,
- FnService,
+ Component,
+ Input,
+ OnChanges,
+ OnDestroy,
+ OnInit,
+ SimpleChanges
+} from '@angular/core';
+import {animate, state, style, transition, trigger} from '@angular/animations';
+import {
DetailsPanelBaseImpl,
+ FnService, LionService,
+ LoadingService,
+ LogService,
WebSocketService
} from 'gui2-fw-lib';
-import {Node} from '../../layer/forcesvg/models';
+import {Host, Link, LinkType, UiElement} from '../../layer/forcesvg/models';
+import {Params, Router} from '@angular/router';
-/*
- ONOS GUI -- Topology Details Panel.
- Displays details of selected device.
+
+interface ButtonAttrs {
+ gid: string;
+ tt: string;
+ path: string;
+}
+
+const SHOWDEVICEVIEW: ButtonAttrs = {
+ gid: 'deviceTable',
+ tt: 'tt_ctl_show_device',
+ path: 'device',
+};
+const SHOWFLOWVIEW: ButtonAttrs = {
+ gid: 'flowTable',
+ tt: 'title_flows',
+ path: 'flow',
+};
+const SHOWPORTVIEW: ButtonAttrs = {
+ gid: 'portTable',
+ tt: 'tt_ctl_show_port',
+ path: 'port',
+};
+const SHOWGROUPVIEW: ButtonAttrs = {
+ gid: 'groupTable',
+ tt: 'tt_ctl_show_group',
+ path: 'group',
+};
+const SHOWMETERVIEW: ButtonAttrs = {
+ gid: 'meterTable',
+ tt: 'tt_ctl_show_meter',
+ path: 'meter',
+};
+const SHOWPIPECONFVIEW: ButtonAttrs = {
+ gid: 'pipeconfTable',
+ tt: 'tt_ctl_show_pipeconf',
+ path: 'pipeconf',
+};
+
+interface ShowDetails {
+ buttons: string[];
+ glyphId: string;
+ id: string;
+ navPath: string;
+ propLabels: Object;
+ propOrder: string[];
+ propValues: Object;
+ title: string;
+}
+/**
+ * ONOS GUI -- Topology Details Panel.
+ * Displays details of selected device. When no device is selected the panel slides
+ * off to the side and disappears
*/
@Component({
selector: 'onos-details',
@@ -40,7 +97,7 @@
trigger('detailsPanelState', [
state('true', style({
transform: 'translateX(0%)',
- opacity: '100'
+ opacity: '1.0'
})),
state('false', style({
transform: 'translateX(100%)',
@@ -51,21 +108,169 @@
])
]
})
-export class DetailsComponent extends DetailsPanelBaseImpl implements OnInit {
- @Input() selectedNode: Node = undefined;
+export class DetailsComponent extends DetailsPanelBaseImpl implements OnInit, OnDestroy, OnChanges {
+ @Input() selectedNode: UiElement = undefined; // Populated when user selects node or link
+
+ // deferred localization strings
+ lionFn; // Function
+ showDetails: ShowDetails; // Will be populated on callback. Cleared if nothing is selected
constructor(
protected fs: FnService,
protected log: LogService,
protected ls: LoadingService,
+ protected router: Router,
protected wss: WebSocketService,
+ private lion: LionService
) {
super(fs, ls, log, wss, 'topo');
- this.log.debug('InstanceComponent constructed');
+
+ if (this.lion.ubercache.length === 0) {
+ this.lionFn = this.dummyLion;
+ this.lion.loadCbs.set('flow', () => this.doLion());
+ } else {
+ this.doLion();
+ }
+
+ this.log.debug('Topo DetailsComponent constructed');
}
- ngOnInit() {
+ /**
+ * When the component is initializing set up the handler for callbacks of
+ * ShowDetails from the WSS. Set the variable showDetails when ever a callback
+ * is made
+ */
+ ngOnInit(): void {
this.on = false;
+ this.wss.bindHandlers(new Map<string, (data) => void>([
+ ['showDetails', (data) => {
+ this.showDetails = data;
+ // this.log.debug('showDetails received', data);
+ }
+ ]
+ ]));
+ this.log.debug('Topo DetailsComponent initialized');
+ }
+
+ /**
+ * When the component is being unloaded then unbind the WSS handler.
+ */
+ ngOnDestroy(): void {
+ this.wss.unbindHandlers(['showDetails']);
+ this.log.debug('Topo DetailsComponent destroyed');
+ }
+
+ /**
+ * If changes are detected on the Input param selectedNode, call on WSS sendEvent
+ * Note the difference in call to the WSS with requestDetails between a node
+ * and a link - the handling is done in TopologyViewMessageHandler#RequestDetails.process()
+ *
+ * The WSS will call back asynchronously (see fn in ngOnInit())
+ *
+ * @param changes Simple Changes set of updates
+ */
+ ngOnChanges(changes: SimpleChanges): void {
+ if (changes['selectedNode']) {
+ this.selectedNode = changes['selectedNode'].currentValue;
+ let type: any;
+
+ if (this.selectedNode === undefined) {
+ // Selection has been cleared
+ this.showDetails = <ShowDetails>{};
+ return;
+ }
+
+ if (this.selectedNode.hasOwnProperty('nodeType')) { // For Device, Host, SubRegion
+ type = (<Host>this.selectedNode).nodeType;
+ this.wss.sendEvent('requestDetails', {
+ id: this.selectedNode.id,
+ class: type,
+ });
+ } else if (this.selectedNode.hasOwnProperty('type')) { // Must be link
+ const link: Link = <Link>this.selectedNode;
+ if (<LinkType><unknown>LinkType[link.type] === LinkType.UiEdgeLink) { // Number based enum
+ this.wss.sendEvent('requestDetails', {
+ key: link.id,
+ class: 'link',
+ sourceId: link.epA,
+ targetId: Link.deviceNameFromEp(link.epB),
+ targetPort: link.portB,
+ isEdgeLink: true
+ });
+ } else {
+ this.wss.sendEvent('requestDetails', {
+ key: link.id,
+ class: 'link',
+ sourceId: Link.deviceNameFromEp(link.epA),
+ sourcePort: link.portA,
+ targetId: Link.deviceNameFromEp(link.epB),
+ targetPort: link.portB,
+ isEdgeLink: false
+ });
+ }
+ } else {
+ this.log.warn('Unexpected type for selected element', this.selectedNode);
+ }
+ } else {
+ this.log.warn('Unexpected change in Topo DetailsComponent');
+ }
+ }
+
+ /**
+ * Table of core button attributes to return per button icon
+ * @param btnName The name of the button
+ * @returns A structure with the button attributes
+ */
+ buttonAttribs(btnName: string): ButtonAttrs {
+ switch (btnName) {
+ case 'showDeviceView':
+ return SHOWDEVICEVIEW;
+ case 'showFlowView':
+ return SHOWFLOWVIEW;
+ case 'showPortView':
+ return SHOWPORTVIEW;
+ case 'showGroupView':
+ return SHOWGROUPVIEW;
+ case 'showMeterView':
+ return SHOWMETERVIEW;
+ case 'showPipeConfView':
+ return SHOWPIPECONFVIEW;
+ default:
+ return <ButtonAttrs>{
+ gid: btnName,
+ path: btnName
+ };
+ }
+ }
+
+ /**
+ * Navigate using Angular Routing. Combines the parameters to generate a relative URL
+ * e.g. if params are 'meter', 'device' and 'null:0000000000001' then the
+ * navigation URL will become "http://localhost:4200/#/meter?devId=null:0000000000000002"
+ *
+ * @param path The path to navigate to
+ * @param navPath The parameter name to use
+ * @param selId the parameter value to use
+ */
+ navto(path: string, navPath: string, selId: string): void {
+ this.log.debug('navigate to', path, 'for', navPath, '=', selId);
+ // Special case until it's fixed
+ if (selId) {
+ if (navPath === 'device') {
+ navPath = 'devId';
+ }
+ const queryPar: Params = {};
+ queryPar[navPath] = selId;
+ this.router.navigate([path], { queryParams: queryPar });
+ }
+ }
+
+ /**
+ * Read the LION bundle for Details panel and set up the lionFn
+ */
+ doLion() {
+ this.lionFn = this.lion.bundle('core.view.Flow');
+
}
}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.html b/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.html
index 0cb4a0b..f5a2859 100644
--- a/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.html
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.html
@@ -13,7 +13,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<div id="topo-p-instance" class="floatpanel" [ngStyle]="{'left': '20px', 'top':divTopPx+'px', 'width': (onosInstances.length * 170)+'px', 'height': '85px'}" [@instancePanelState]="!on">
+<div id="topo-p-instance" class="floatpanel" [ngStyle]="{'left': '20px', 'top':divTopPx+'px', 'width': (onosInstances.length * 170)+'px', 'height': '85px'}" [@instancePanelState]="on">
<div *ngFor="let inst of onosInstances | keyvalue ; let i=index"
[ngClass]="['onosInst', inst.value.online?'online':'', inst.value.ready? 'ready': '', mastership?'mastership':'', 'affinity']"
(click)="chooseMastership(inst.value.id)">
@@ -33,7 +33,7 @@
<text class="instLabel ip" x="48" y="55">{{ inst.value.ip }}</text>
<use width="20" height="20" class="glyph badgeIcon bird" xlink:href="#bird" transform="translate(15,10)"></use>
<use *ngIf="inst.value.ready" width="16" height="16" class="glyph overlay badgeIcon readyBadge" xlink:href="#checkMark" transform="translate(18,40)"></use>
- <text class="instLabel ns" x="48" y="73">Devices: {{ inst.value.switches }}</text>
+ <text class="instLabel ns" x="48" y="73">{{lionFn('devices')}} {{ inst.value.switches }}</text>
<use *ngIf="inst.value.uiAttached" width="24" height="24" class="glyph overlay badgeIcon uiBadge" xlink:href="#uiAttached" transform="translate(14,54)"></use>
</svg>
</div>
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.ts b/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.ts
index 05e8768..b30c706 100644
--- a/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/instance/instance.component.ts
@@ -26,7 +26,7 @@
FnService,
PanelBaseImpl,
IconService,
- SvgUtilService
+ SvgUtilService, LionService
} from 'gui2-fw-lib';
/**
@@ -77,18 +77,26 @@
@Output() mastershipEvent = new EventEmitter<string>();
public onosInstances: Array<Instance>;
protected mastership: string;
+ lionFn; // Function
constructor(
protected fs: FnService,
protected log: LogService,
protected ls: LoadingService,
protected is: IconService,
- protected sus: SvgUtilService
+ protected sus: SvgUtilService,
+ private lion: LionService
) {
super(fs, ls, log);
this.onosInstances = <Array<Instance>>[];
- this.is.loadIconDef('active');
- this.is.loadIconDef('uiAttached');
+
+ if (this.lion.ubercache.length === 0) {
+ this.lionFn = this.dummyLion;
+ this.lion.loadCbs.set('topo-inst', () => this.doLion());
+ } else {
+ this.doLion();
+ }
+ this.on = true;
this.log.debug('InstanceComponent constructed');
}
@@ -114,4 +122,12 @@
this.mastershipEvent.emit(this.mastership);
this.log.debug('Instance', this.mastership, 'chosen on GUI');
}
+
+ /**
+ * Read the LION bundle for Details panel and set up the lionFn
+ */
+ doLion() {
+ this.lionFn = this.lion.bundle('core.view.Topo');
+
+ }
}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.ts b/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.ts
index c1c41f8..a520c86 100644
--- a/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.ts
@@ -70,6 +70,7 @@
) {
super(fs, ls, log, 'summary');
this.summaryData = <SummaryResponse>{};
+ this.on = true;
this.log.debug('SummaryComponent constructed');
}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/button.css b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/button.css
new file mode 100644
index 0000000..1effdbc
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/button.css
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- Button Service (layout) -- CSS file
+ */
+
+.button,
+.toggleButton,
+.radioSet {
+ display: inline-block;
+ padding: 0 4px;
+}
+.radioButton {
+ display: inline-block;
+ padding: 0 2px;
+}
+
+.button svg.embeddedIcon,
+.toggleButton svg.embeddedIcon,
+.radioButton svg.embeddedIcon {
+ cursor: pointer;
+}
+.button svg.embeddedIcon .icon rect,
+.toggleButton svg.embeddedIcon .icon rect,
+.radioButton svg.embeddedIcon .icon rect{
+ stroke: none;
+}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.css b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.css
index 9dca44c..449d436 100644
--- a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.css
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.css
@@ -18,6 +18,40 @@
/*
ONOS GUI -- Topology Toolbar Panel -- CSS file
*/
+
+
+
+div.tbar-arrow {
+ position: absolute;
+ top: 53%;
+ left: 96%;
+ margin-right: -4%;
+ transform: translate(-50%, -50%);
+ cursor: pointer;
+}
+.safari div.tbar-arrow {
+ top: 46%;
+}
+.firefox div.tbar-arrow {
+ left: 97%;
+ margin-right: -3%;
+}
+
+.toolbar {
+ line-height: 125%;
+}
+.tbar-row {
+ display: inline-block;
+}
+
+.separator {
+ border: 1px solid;
+ margin: 0 4px 0 4px;
+ display: inline-block;
+ height: 23px;
+ width: 0;
+}
+
#toolbar-topo2-toolbar {
padding: 6px;
}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.html b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.html
index ae25507..693e1b5 100644
--- a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.html
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.html
@@ -15,117 +15,52 @@
-->
<div id="toolbar-topo2-toolbar" class="floatpanel toolbar" [@toolbarState]="on"
style="opacity: 1; left: 0px; width: 261px; top: auto; bottom: 10px;">
- <div class="tbar-arrow">
- <svg class="embeddedIcon" width="10" height="10" viewBox="0 0 50 50">
- <g class="icon" transform="translate(0 50) rotate(-90)">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#triangleUp"></use>
- </g>
- </svg>
+ <div class="tbar-arrow" (click)="on =! on">
+ <onos-icon [iconSize]="10" [iconId]="on?'triangleLeft':'triangleRight'"></onos-icon>
</div>
- <div class="tbar-row">
- <div class="toggleButton selected" id="toolbar-topo2-toolbar-topo2-instance-tog">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#m_uiAttached"></use>
- </g>
- </svg>
+ <div class="tbar-row ctrl-btns">
+ <div class="toggleButton" id="toolbar-topo2-toolbar-topo2-instance-tog" (click)="buttonClicked('instance-tog')">
+ <onos-icon [iconSize]="25" iconId="m_uiAttached" [toolTip]="lionFn('tbtt_tog_instances')" [classes]="['toggleButton', instancesVisible?'selected':'']"></onos-icon>
</div>
- <div class="toggleButton selected" id="toolbar-topo2-toolbar-topo2-summary-tog">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#m_summary"></use>
- </g>
- </svg>
+ <div class="toggleButton" id="toolbar-topo2-toolbar-topo2-summary-tog" (click)="buttonClicked('summary-tog')">
+ <onos-icon [iconSize]="25" iconId="m_summary" [toolTip]="lionFn('tbtt_tog_summary')" [classes]="['toggleButton', summaryVisible?'selected':'']"></onos-icon>
</div>
- <div class="toggleButton selected" id="toolbar-topo2-toolbar-details-tog">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#m_details"></use>
- </g>
- </svg>
+ <div class="toggleButton" id="toolbar-topo2-toolbar-details-tog" (click)="buttonClicked('details-tog')">
+ <onos-icon [iconSize]="25" iconId="m_details" [toolTip]="lionFn('tbtt_tog_use_detail')" [classes]="['toggleButton', detailsVisible?'selected':'']"></onos-icon>
</div>
<div class="separator"></div>
- <div class="toggleButton" id="toolbar-topo2-toolbar-hosts-tog">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#m_endstation"></use>
- </g>
- </svg>
+ <div class="toggleButton" id="toolbar-topo2-toolbar-hosts-tog" (click)="buttonClicked('hosts-tog')">
+ <onos-icon [iconSize]="25" iconId="m_endstation" [toolTip]="lionFn('tbtt_tog_host')" [classes]="['toggleButton', hostsVisible?'selected':'']"></onos-icon>
</div>
- <div class="toggleButton selected" id="toolbar-topo2-toolbar-offline-tog">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#m_switch"></use>
- </g>
- </svg>
+ <div class="toggleButton" id="toolbar-topo2-toolbar-offline-tog" (click)="buttonClicked('offline-tog')">
+ <onos-icon [iconSize]="25" iconId="m_switch" [toolTip]="lionFn('tbtt_tog_offline')" classes="toggleButton selected"></onos-icon>
</div>
- <div class="toggleButton selected" id="toolbar-topo2-toolbar-topo2-ports-tog">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#m_ports"></use>
- </g>
- </svg>
+ <div class="toggleButton" id="toolbar-topo2-toolbar-topo2-ports-tog" (click)="buttonClicked('ports-tog')">
+ <onos-icon [iconSize]="25" iconId="m_ports" [toolTip]="lionFn('tbtt_tog_porthi')" classes="toggleButton selected" [classes]="['toggleButton', portsVisible?'selected':'']"></onos-icon>
</div>
- <div class="toggleButton selected" id="toolbar-topo2-toolbar-topo2-bkgrnd-tog">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#m_map"></use>
- </g>
- </svg>
+ <div class="toggleButton" id="toolbar-topo2-toolbar-topo2-bkgrnd-tog" (click)="buttonClicked('bkgrnd-tog')">
+ <onos-icon [iconSize]="25" iconId="m_map" [toolTip]="lionFn('tbtt_tog_map')" classes="toggleButton selected" [classes]="['toggleButton', backgroundVisible?'selected':'']"></onos-icon>
</div>
</div>
<br>
<div class="tbar-row">
- <div class="button" id="toolbar-topo2-toolbar-topo2-cycleLabels-btn">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#m_cycleLabels"></use>
- </g>
- </svg>
+ <div class="button" id="toolbar-topo2-toolbar-topo2-cycleLabels-btn" (click)="buttonClicked('cycleLabels-btn')">
+ <onos-icon [iconSize]="25" iconId="m_cycleLabels" [toolTip]="lionFn('tbtt_cyc_dev_labs')" classes="button"></onos-icon>
</div>
- <div class="button" id="toolbar-topo2-toolbar-topo2-resetZoom-btn">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#m_resetZoom"></use>
- </g>
- </svg>
+ <div class="button" id="toolbar-topo2-toolbar-topo2-resetZoom-btn" (click)="buttonClicked('resetZoom-btn')">
+ <onos-icon [iconSize]="25" iconId="m_resetZoom" [toolTip]="lionFn('tbtt_reset_zoom')" classes="button"></onos-icon>
</div>
<div class="separator"></div>
- <div class="button" id="toolbar-topo2-toolbar-topo2-eqMaster-btn">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#m_eqMaster"></use>
- </g>
- </svg>
+ <div class="button" id="toolbar-topo2-toolbar-topo2-eqMaster-btn" (click)="buttonClicked('eqMaster-btn')">
+ <onos-icon [iconSize]="25" iconId="m_eqMaster" [toolTip]="lionFn('tbtt_eq_master')" classes="button"></onos-icon>
</div>
<div class="separator"></div>
- <div class="radioSet" id="toolbar-topo2-toolbar-topo-overlays">
- <div class="radioButton selected" id="toolbar-topo2-toolbar-topo-overlays-0">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#m_unknown"></use>
- </g>
- </svg>
+ <div class="radioSet" id="toolbar-topo2-traffic">
+ <div class="radioButton selected" id="toolbar-topo2-cancel-traffic" (click)="buttonClicked('cancel-traffic')">
+ <onos-icon [iconSize]="25" iconId="m_unknown" [toolTip]="lionFn('tr_btn_cancel_monitoring')" classes="radioButton selected"></onos-icon>
</div>
- <div class="radioButton" id="toolbar-topo2-toolbar-topo-overlays-1">
- <svg class="embeddedIcon" width="25" height="25" viewBox="0 0 50 50">
- <g class="icon">
- <rect width="50" height="50" rx="5"></rect>
- <use width="50" height="50" class="glyph" xlink:href="#m_allTraffic"></use>
- </g>
- </svg>
+ <div class="radioButton" id="toolbar-topo2-all-traffic" (click)="buttonClicked('all-traffic')">
+ <onos-icon [iconSize]="25" iconId="m_allTraffic" [toolTip]="lionFn('tr_btn_show_related_traffic')" classes="radioButton selected"></onos-icon>
</div>
</div>
</div>
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.spec.ts
index 90a629e..91c1de4 100644
--- a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.spec.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.spec.ts
@@ -19,8 +19,8 @@
import { ToolbarComponent } from './toolbar.component';
import {
- FnService,
- LogService
+ FnService, LionService,
+ LogService, IconComponent
} from 'gui2-fw-lib';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
@@ -42,6 +42,15 @@
let component: ToolbarComponent;
let fixture: ComponentFixture<ToolbarComponent>;
+ const bundleObj = {
+ 'core.view.Topo': {
+ test: 'test1'
+ }
+ };
+ const mockLion = (key) => {
+ return bundleObj[key] || '%' + key + '%';
+ };
+
beforeEach(async(() => {
const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
ar = new MockActivatedRoute({ 'debug': 'txrx' });
@@ -60,10 +69,19 @@
fs = new FnService(ar, logSpy, windowMock);
TestBed.configureTestingModule({
imports: [ BrowserAnimationsModule ],
- declarations: [ ToolbarComponent ],
+ declarations: [ ToolbarComponent, IconComponent ],
providers: [
{ provide: FnService, useValue: fs },
{ provide: LogService, useValue: logSpy },
+ {
+ provide: LionService, useFactory: (() => {
+ return {
+ bundle: ((bundleId) => mockLion),
+ ubercache: new Array(),
+ loadCbs: new Map<string, () => void>([])
+ };
+ })
+ },
{ provide: 'Window', useValue: windowMock },
]
})
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.ts b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.ts
index 2addffe..1ec3dbb 100644
--- a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.component.ts
@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Component, OnInit } from '@angular/core';
+import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {
LogService,
LoadingService,
FnService,
- PanelBaseImpl
+ PanelBaseImpl, LionService
} from 'gui2-fw-lib';
import {animate, state, style, transition, trigger} from '@angular/animations';
@@ -32,36 +32,96 @@
styleUrls: [
'./toolbar.component.css', './toolbar.theme.css',
'../../topology.common.css',
- '../../../../fw/widget/panel.css', '../../../../fw/widget/panel-theme.css'
+ '../../../../fw/widget/panel.css', '../../../../fw/widget/panel-theme.css',
+ './button.css'
],
animations: [
trigger('toolbarState', [
state('true', style({
transform: 'translateX(0%)',
- opacity: '1.0'
+ // opacity: '1.0'
})),
state('false', style({
- transform: 'translateX(-100%)',
- opacity: '0.0'
+ transform: 'translateX(-93%)',
+ // opacity: '0.0'
})),
- transition('0 => 1', animate('100ms ease-in')),
- transition('1 => 0', animate('100ms ease-out'))
+ transition('0 => 1', animate('500ms ease-in')),
+ transition('1 => 0', animate('500ms ease-out'))
])
]
})
export class ToolbarComponent extends PanelBaseImpl implements OnInit {
+ // deferred localization strings
+ lionFn; // Function
+ // Used to drive the display of the hosts icon - there is also another such variable on the forcesvg
+ @Input() hostsVisible: boolean = false;
+ @Input() instancesVisible: boolean = true;
+ @Input() summaryVisible: boolean = true;
+ @Input() detailsVisible: boolean = true;
+ @Input() backgroundVisible: boolean = false;
+ @Input() portsVisible: boolean = true;
+
+ @Output() buttonEvent = new EventEmitter<string>();
constructor(
protected fs: FnService,
protected log: LogService,
protected ls: LoadingService,
+ private lion: LionService
) {
super(fs, ls, log);
this.on = false;
+
+ if (this.lion.ubercache.length === 0) {
+ this.lionFn = this.dummyLion;
+ this.lion.loadCbs.set('topo-toolbar', () => this.doLion());
+ } else {
+ this.doLion();
+ }
+
this.log.debug('ToolbarComponent constructed');
}
ngOnInit() {
}
+ /**
+ * Read the LION bundle for Toolbar and set up the lionFn
+ */
+ doLion() {
+ this.lionFn = this.lion.bundle('core.view.Topo');
+ }
+
+ /**
+ * As buttons are clicked on the toolbar, emit events up to the parent
+ *
+ * The toggling of the input variables here is in addition to the control
+ * of these input variables from the parent. This is so that this component
+ * may be reused and is not dependent on a particular parent implementation
+ * to work
+ * @param name The name of button clicked.
+ */
+ buttonClicked(name: string): void {
+ switch (name) {
+ case 'hosts-tog':
+ this.hostsVisible = !this.hostsVisible;
+ break;
+ case 'instance-tog':
+ this.instancesVisible = !this.instancesVisible;
+ break;
+ case 'summary-tog':
+ this.summaryVisible = !this.summaryVisible;
+ break;
+ case 'details-tog':
+ this.detailsVisible = !this.detailsVisible;
+ break;
+ case 'bkgrnd-tog':
+ this.backgroundVisible = !this.backgroundVisible;
+ break;
+ default:
+ this.log.warn('Unhandled toolbar click', name);
+ }
+ // Send a message up to let TopologyComponent know of the event
+ this.buttonEvent.emit(name);
+ }
}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.theme.css b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.theme.css
index fcd9157..7933ee6 100644
--- a/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.theme.css
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/toolbar/toolbar.theme.css
@@ -15,9 +15,39 @@
*/
-/*
- ONOS GUI -- Topology Toolbar Panel -- Theme CSS file
+/**
+ * ONOS GUI -- Topology Toolbar Panel -- Theme CSS file
*/
+.tbar-arrow svg.embeddedIcon .icon rect {
+ stroke: none;
+}
+
+.tbar-arrow svg.embeddedIcon .icon .glyph {
+ fill: #838383;
+}
+
+.tbar-arrow svg.embeddedIcon .icon rect {
+ fill: none;
+}
+
+.separator {
+ border-color: #ddd;
+}
+
+/* ========== DARK Theme ========== */
+
+.dark .tbar-arrow svg.embeddedIcon .icon .glyph {
+ fill: #B2B2B2;
+}
+
+.dark .tbar-arrow svg.embeddedIcon .icon rect {
+ fill: none;
+}
+
+.dark .separator {
+ border-color: #454545;
+}
+
.dark #toolbar-topo2-toolbar .tbar-row.right {
color: #666;
}
\ No newline at end of file
diff --git a/web/gui2/src/main/webapp/app/view/topology/topology.module.ts b/web/gui2/src/main/webapp/app/view/topology/topology.module.ts
index 3d9debc..e7fe739 100644
--- a/web/gui2/src/main/webapp/app/view/topology/topology.module.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/topology.module.ts
@@ -18,7 +18,6 @@
import { TopologyRoutingModule } from './topology-routing.module';
import { TopologyComponent } from './topology/topology.component';
import { NoDeviceConnectedSvgComponent } from './layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component';
-import { LayoutComponent } from './layer/layout/layout.component';
import { InstanceComponent } from './panel/instance/instance.component';
import { SummaryComponent } from './panel/summary/summary.component';
import { ToolbarComponent } from './panel/toolbar/toolbar.component';
@@ -39,6 +38,8 @@
/**
* ONOS GUI -- Topology View Module
*
+ * The main entry point is the TopologyComponent
+ *
* Note: This has been updated from onos-gui-1.0.0 where it was called 'topo2'
* whereas here it is now called 'topology'. This also merges in the old 'topo'
*/
@@ -51,7 +52,6 @@
declarations: [
TopologyComponent,
NoDeviceConnectedSvgComponent,
- LayoutComponent,
InstanceComponent,
SummaryComponent,
ToolbarComponent,
diff --git a/web/gui2/src/main/webapp/app/view/topology/topology.service.ts b/web/gui2/src/main/webapp/app/view/topology/topology.service.ts
index 9422a3f..2c5d777 100644
--- a/web/gui2/src/main/webapp/app/view/topology/topology.service.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/topology.service.ts
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-present Open Networking Foundation
+ * Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,12 +49,12 @@
init(instance: InstanceComponent, background: BackgroundSvgComponent, force: ForceSvgComponent) {
this.wss.bindHandlers(new Map<string, (data) => void>([
['topo2AllInstances', (data) => {
- this.log.warn('Add fn for topo2AllInstances callback', data);
+ this.log.debug('Instances updated through WSS as topo2AllInstances', data);
instance.onosInstances = data.members;
}
],
['topo2CurrentLayout', (data) => {
- this.log.warn('Add fn for topo2CurrentLayout callback', data);
+ this.log.debug('Background Data updated from WSS as topo2CurrentLayout', data);
if (background) {
background.layoutData = data;
}
@@ -65,19 +65,20 @@
force.ngOnChanges({
'regionData' : new SimpleChange(<Region>{}, data, true)
});
- this.log.warn('Add fn for topo2CurrentRegion callback', force.regionData);
+ this.log.debug('Region Data replaced from WSS as topo2CurrentRegion', force.regionData);
}
],
['topo2PeerRegions', (data) => { this.log.warn('Add fn for topo2PeerRegions callback', data); } ],
['topo2UiModelEvent', (event) => {
// this.log.debug('Handling', event);
force.handleModelEvent(
- <ModelEventType><unknown>(ModelEventType[event.type]),
- <ModelEventMemo>(event.memo),
+ <ModelEventType><unknown>(ModelEventType[event.type]), // Number based enum
+ <ModelEventMemo>(event.memo), // String based enum
event.subject, event.data);
+ this.log.debug('Region Data updated from WSS as topo2UiModelEvent', force.regionData);
}
],
- // ['topo2Highlights', (data) => { this.log.warn('Add fn for topo2Highlights callback', data); } ],
+ // topo2Highlights is handled by TrafficService
]));
this.handlers.push('topo2AllInstances');
this.handlers.push('topo2CurrentLayout');
diff --git a/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.html b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.html
index 2a654b7..6fe0cb1 100644
--- a/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.html
+++ b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.html
@@ -1,5 +1,5 @@
<!--
-~ Copyright 2018-present Open Networking Foundation
+~ Copyright 2019-present Open Networking Foundation
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -13,17 +13,42 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
+<!-- Template explaination - Add in the flash message component - and link it to
+the local variable - this is used to display messages when keyboard shortcuts are pressed
+-->
<onos-flash id="topoMsgFlash" message="{{ flashMsg }}" (closed)="flashMsg = ''"></onos-flash>
+<!-- Template explanation - Add in the Panel components for the Topology view
+ These are referenced inside the typescript by @ViewChild and their label
+-->
<onos-instance #instance [divTopPx]="80" (mastershipEvent)="force.onosInstMastership = $event"></onos-instance>
<onos-summary #summary></onos-summary>
-<onos-toolbar #toolbar></onos-toolbar>
+<onos-toolbar #toolbar (buttonEvent)="toolbarButtonClicked($event)"></onos-toolbar>
<onos-details #details></onos-details>
<div id="ov-topo2">
+ <!-- Template explanation -
+ Line 0) This is the root of the whole SVG canvas of the Topology View - all
+ components beneath it are SVG components only (no HTML)
+ line 1) the No Devices Connected banner is shown if the force component
+ (from line 4) does not contain any devices
+ line 2) Create an SVG Grouping and apply the onosZoomableOf directive to it,
+ passing in the whole SVG canvas (#svgZoom)
+ line 3) Add in the Background Svg Component (if showBackground is true - toggled
+ by toolbar and by keyboard shortcut 'B'
+ line 4) Add in the layer of the Force Svg Component. If any item is selected on it, pass
+ to the details view and deselect all others. This is node and line graph
+ whose contents are supplied through the Topology Service, and whose positions
+ 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">
- <svg:g *ngIf="force.regionData?.devices.length === 0" onos-nodeviceconnected />
+ <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 +
+ force.regionData?.devices[2].length=== 0"
+ onos-nodeviceconnected />
<svg:g id="topo-zoomlayer" onosZoomableOf [zoomableOf]="svgZoom">
+ <svg:desc>A logical layer that allows the main SVG canvas to be zoomed and panned</svg:desc>
<svg:g *ngIf="showBackground" onos-backgroundsvg/>
<svg:g #force onos-forcesvg (selectedNodeEvent)="nodeSelected($event)"/>
</svg:g>
diff --git a/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.spec.ts
index a9c6194..23fb257 100644
--- a/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.spec.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.spec.ts
@@ -32,9 +32,11 @@
import {
FlashComponent,
FnService,
- LogService
+ LogService,
+ IconService, IconComponent
} from 'gui2-fw-lib';
import {ZoomableDirective} from '../layer/zoomable.directive';
+import {RouterTestingModule} from '@angular/router/testing';
class MockActivatedRoute extends ActivatedRoute {
@@ -72,6 +74,10 @@
destroy() {}
}
+class MockIconService {
+ loadIconDef() { }
+}
+
/**
* ONOS GUI -- Topology View -- Unit Tests
*/
@@ -101,7 +107,7 @@
fs = new FnService(ar, logSpy, windowMock);
TestBed.configureTestingModule({
- imports: [ BrowserAnimationsModule ],
+ imports: [ BrowserAnimationsModule, RouterTestingModule ],
declarations: [
TopologyComponent,
InstanceComponent,
@@ -109,7 +115,8 @@
ToolbarComponent,
DetailsComponent,
FlashComponent,
- ZoomableDirective
+ ZoomableDirective,
+ IconComponent
],
providers: [
{ provide: FnService, useValue: fs },
@@ -117,6 +124,7 @@
{ provide: 'Window', useValue: windowMock },
{ provide: HttpClient, useClass: MockHttpClient },
{ provide: TopologyService, useClass: MockTopologyService },
+ { provide: IconService, useClass: MockIconService },
]
}).compileComponents();
logServiceSpy = TestBed.get(LogService);
diff --git a/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.ts b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.ts
index 7365310..3e1e1a6 100644
--- a/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.ts
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-present Open Networking Foundation
+ * Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
@@ -21,9 +21,9 @@
} from '@angular/core';
import * as d3 from 'd3';
import {
- FnService,
+ FnService, IconService,
KeysService,
- KeysToken,
+ KeysToken, LionService,
LogService,
PrefsService,
SvgUtilService,
@@ -36,9 +36,14 @@
import {BackgroundSvgComponent} from '../layer/backgroundsvg/backgroundsvg.component';
import {ForceSvgComponent} from '../layer/forcesvg/forcesvg.component';
import {TopologyService} from '../topology.service';
-import {HostLabelToggle, LabelToggle, Node} from '../layer/forcesvg/models';
+import {
+ HostLabelToggle,
+ LabelToggle,
+ UiElement
+} from '../layer/forcesvg/models';
import {ToolbarComponent} from '../panel/toolbar/toolbar.component';
import {TrafficService} from '../traffic.service';
+import {ZoomableDirective} from '../layer/zoomable.directive';
/**
* ONOS GUI Topology View
@@ -77,11 +82,13 @@
@ViewChild(ToolbarComponent) toolbar: ToolbarComponent;
@ViewChild(BackgroundSvgComponent) background: BackgroundSvgComponent;
@ViewChild(ForceSvgComponent) force: ForceSvgComponent;
+ @ViewChild(ZoomableDirective) zoomDirective: ZoomableDirective;
flashMsg: string = '';
prefsState = {};
hostLabelIdx: number = 1;
showBackground: boolean = false;
+ lionFn; // Function
constructor(
protected log: LogService,
@@ -92,29 +99,69 @@
protected wss: WebSocketService,
protected zs: ZoomService,
protected ts: TopologyService,
- protected trs: TrafficService
+ protected trs: TrafficService,
+ protected is: IconService,
+ private lion: LionService,
) {
+ if (this.lion.ubercache.length === 0) {
+ this.lionFn = this.dummyLion;
+ this.lion.loadCbs.set('topo-toolbar', () => this.doLion());
+ } else {
+ this.doLion();
+ }
+ this.is.loadIconDef('bird');
+ this.is.loadIconDef('active');
+ this.is.loadIconDef('uiAttached');
+ this.is.loadIconDef('m_switch');
+ this.is.loadIconDef('m_roadm');
+ this.is.loadIconDef('m_router');
+ this.is.loadIconDef('m_uiAttached');
+ this.is.loadIconDef('m_endstation');
+ this.is.loadIconDef('m_ports');
+ this.is.loadIconDef('m_summary');
+ this.is.loadIconDef('m_details');
+ this.is.loadIconDef('m_map');
+ this.is.loadIconDef('m_cycleLabels');
+ this.is.loadIconDef('m_resetZoom');
+ this.is.loadIconDef('m_eqMaster');
+ this.is.loadIconDef('m_unknown');
+ this.is.loadIconDef('m_allTraffic');
+ this.is.loadIconDef('deviceTable');
+ this.is.loadIconDef('flowTable');
+ this.is.loadIconDef('portTable');
+ this.is.loadIconDef('groupTable');
+ this.is.loadIconDef('meterTable');
+ this.is.loadIconDef('triangleUp');
this.log.debug('Topology component constructed');
}
+ /**
+ * Static functions must come before member variables
+ * @param index
+ */
private static deviceLabelFlashMessage(index: number): string {
switch (index) {
- case 0: return 'Hide device labels';
- case 1: return 'Show friendly device labels';
- case 2: return 'Show device ID labels';
+ case 0: return 'fl_device_labels_hide';
+ case 1: return 'fl_device_labels_show_friendly';
+ case 2: return 'fl_device_labels_show_id';
}
}
private static hostLabelFlashMessage(index: number): string {
switch (index) {
- case 0: return 'Hide host labels';
- case 1: return 'Show friendly host labels';
- case 2: return 'Show host IP labels';
- case 3: return 'Show host MAC Address labels';
+ case 0: return 'fl_host_labels_hide';
+ case 1: return 'fl_host_labels_show_friendly';
+ case 2: return 'fl_host_labels_show_ip';
+ case 3: return 'fl_host_labels_show_mac';
}
}
+ /**
+ * Pass the list of Key Commands to the KeyService, and initialize the Topology
+ * Service - which communicates with through the WebSocket to the ONOS server
+ * to get the nodes and links.
+ */
ngOnInit() {
this.bindCommands();
// The components from the template are handed over to TopologyService here
@@ -125,11 +172,72 @@
this.log.debug('Topology component initialized');
}
+ /**
+ * When this component is being stopped, disconnect the TopologyService from
+ * the WebSocket
+ */
ngOnDestroy() {
this.ts.destroy();
this.log.debug('Topology component destroyed');
}
+ /**
+ * When ever a toolbar button is clicked, an event is sent up from toolbar
+ * component which is caught and passed on to here.
+ * @param name The name of the button that was clicked
+ */
+ toolbarButtonClicked(name: string) {
+ switch (name) {
+ case 'instance-tog':
+ this.toggleInstancePanel();
+ break;
+ case 'summary-tog':
+ this.toggleSummary();
+ break;
+ case 'details-tog':
+ this.toggleDetails();
+ break;
+ case 'hosts-tog':
+ this.toggleHosts();
+ break;
+ case 'offline-tog':
+ this.toggleOfflineDevices();
+ break;
+ case 'ports-tog':
+ this.togglePorts();
+ break;
+ case 'bkgrnd-tog':
+ this.toggleBackground();
+ break;
+ case 'cycleLabels-btn':
+ this.cycleDeviceLabels();
+ break;
+ case 'cycleHostLabel-btn':
+ this.cycleHostLabels();
+ break;
+ case 'resetZoom-btn':
+ this.resetZoom();
+ break;
+ case 'eqMaster-btn':
+ this.equalizeMasters();
+ break;
+ case 'cancel-traffic':
+ this.cancelTraffic();
+ break;
+ case 'all-traffic':
+ this.monitorAllTraffic();
+ break;
+ default:
+ this.log.warn('Unhandled Toolbar action', name);
+ }
+ }
+
+ /**
+ * The list of key strokes that will be active in the Topology View.
+ *
+ * This action map is passed to the KeyService through the bindCommands()
+ * when this component is being initialized
+ */
actionMap() {
return {
A: [() => {this.monitorAllTraffic(); }, 'Monitor all traffic'],
@@ -226,7 +334,7 @@
const next = LabelToggle.next(old);
this.force.ngOnChanges({'deviceLabelToggle':
new SimpleChange(old, next, false)});
- this.flashMsg = TopologyComponent.deviceLabelFlashMessage(next);
+ this.flashMsg = this.lionFn(TopologyComponent.deviceLabelFlashMessage(next));
this.log.debug('Cycling device labels', old, next);
}
@@ -235,108 +343,112 @@
const next = HostLabelToggle.next(old);
this.force.ngOnChanges({'hostLabelToggle':
new SimpleChange(old, next, false)});
- this.flashMsg = TopologyComponent.hostLabelFlashMessage(next);
+ this.flashMsg = this.lionFn(TopologyComponent.hostLabelFlashMessage(next));
this.log.debug('Cycling host labels', old, next);
}
- protected toggleBackground(token: KeysToken) {
- this.flashMsg = 'Toggling background';
+ protected toggleBackground(token?: KeysToken) {
this.showBackground = !this.showBackground;
+ this.flashMsg = this.lionFn(this.showBackground ? 'show' : 'hide') +
+ ' ' + this.lionFn('fl_background_map');
+ this.toolbar.backgroundVisible = this.showBackground;
this.log.debug('Toggling background', token);
- // TODO: Reinstate with components
- // t2bgs.toggle(x);
}
- protected toggleDetails(token: KeysToken) {
+ protected toggleDetails(token?: KeysToken) {
if (this.details.selectedNode) {
- this.flashMsg = 'Toggling details';
- this.details.togglePanel(() => {
+ const on: boolean = this.details.togglePanel(() => {
});
+ this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
+ ' ' + this.lionFn('fl_panel_details');
+ this.toolbar.detailsVisible = on;
+
this.log.debug('Toggling details', token);
}
}
- protected toggleInstancePanel(token: KeysToken) {
- this.flashMsg = 'Toggling instances';
- this.instance.togglePanel(() => {});
- this.log.debug('Toggling instances', token);
- // TODO: Reinstate with components
- // this.updatePrefsState('insts', t2is.toggle(x));
+ protected toggleInstancePanel(token?: KeysToken) {
+ const on: boolean = this.instance.togglePanel(() => {});
+ this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
+ ' ' + this.lionFn('fl_panel_instances');
+ this.toolbar.instancesVisible = on;
+ this.log.debug('Toggling instances', token, on);
}
protected toggleSummary() {
- this.flashMsg = 'Toggling summary';
- this.summary.togglePanel(() => {});
+ const on: boolean = this.summary.togglePanel(() => {});
+ this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
+ ' ' + this.lionFn('fl_panel_summary');
+ this.toolbar.summaryVisible = on;
}
protected resetZoom() {
- // this.zoomer.reset();
- this.log.debug('resetting zoom');
- // TODO: Reinstate with components
- // t2bgs.resetZoom();
- // flash.flash('Pan and zoom reset');
+ this.zoomDirective.resetZoom();
+ this.flashMsg = this.lionFn('fl_pan_zoom_reset');
}
- protected togglePorts(token: KeysToken) {
- this.log.debug('Toggling ports');
- // TODO: Reinstate with components
- // this.updatePrefsState('porthl', t2vs.togglePortHighlights(x));
- // t2fs.updateLinks();
+ protected togglePorts(token?: KeysToken) {
+ const old: boolean = this.force.highlightPorts;
+ const current: boolean = !this.force.highlightPorts;
+ this.force.ngOnChanges({'highlightPorts': new SimpleChange(old, current, false)});
+ this.flashMsg = this.lionFn(current ? 'enable' : 'disable') +
+ ' ' + this.lionFn('fl_port_highlighting');
+ this.toolbar.portsVisible = current;
+ this.log.debug(current ? 'Enable' : 'Disable', 'port highlighting');
}
protected equalizeMasters() {
this.wss.sendEvent('equalizeMasters', null);
-
+ this.flashMsg = this.lionFn('fl_eq_masters');
this.log.debug('equalizing masters');
- // TODO: Reinstate with components
- // flash.flash('Equalizing master roles');
}
protected resetNodeLocation() {
+ // TODO: Implement reset locations
+ this.flashMsg = this.lionFn('fl_reset_node_locations');
this.log.debug('resetting node location');
- // TODO: Reinstate with components
- // t2fs.resetNodeLocation();
- // flash.flash('Reset node locations');
}
protected unpinNode() {
+ // TODO: Implement this
this.log.debug('unpinning node');
- // TODO: Reinstate with components
- // t2fs.unpin();
- // flash.flash('Unpin node');
}
protected toggleToolbar() {
this.log.debug('toggling toolbar');
- this.flashMsg = ('Toggle toolbar');
this.toolbar.on = !this.toolbar.on;
}
- protected actionedFlashed(action, message) {
- this.log.debug('action flashed');
- // TODO: Reinstate with components
- // this.flash.flash(action + ' ' + message);
- }
-
protected toggleHosts() {
const old: boolean = this.force.showHosts;
const current = !this.force.showHosts;
this.force.ngOnChanges({'showHosts': new SimpleChange(old, current, false)});
- this.flashMsg = (this.force.showHosts ? 'Show' : 'Hide') + ' Hosts';
+ this.flashMsg = this.lionFn('hosts') + ' ' +
+ this.lionFn(this.force.showHosts ? 'visible' : 'hidden');
+ this.toolbar.hostsVisible = current;
this.log.debug('toggling hosts: ', this.force.showHosts ? 'Show' : 'Hide');
}
protected toggleOfflineDevices() {
+ // TODO: Implement toggle offline visibility
+ const on: boolean = true;
+ this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
+ ' ' + this.lionFn('fl_offline_devices');
this.log.debug('toggling offline devices');
- // TODO: Reinstate with components
- // let on = t2rs.toggleOfflineDevices();
- // this.actionedFlashed(on ? 'Show': 'Hide', 'offline devices');
}
+ /**
+ * Check to see if this is needed anymore
+ * @param what
+ */
protected notValid(what) {
this.log.warn('topo.js getActionEntry(): Not a valid ' + what);
}
+ /**
+ * Check to see if this is needed anymore
+ * @param what
+ */
getActionEntry(key) {
let entry;
@@ -354,15 +466,23 @@
return this.fs.isA(entry) || [entry, ''];
}
- nodeSelected(node: Node) {
- this.details.selectedNode = node;
- this.details.on = Boolean(node);
+ /**
+ * An event handler that updates the details panel as items are
+ * selected in the forcesvg layer
+ * @param nodeOrLink the item to display details of
+ */
+ nodeSelected(nodeOrLink: UiElement) {
+ this.details.ngOnChanges({'selectedNode':
+ new SimpleChange(undefined, nodeOrLink, true)});
+ this.details.on = Boolean(nodeOrLink);
}
/**
* Enable traffic monitoring
*/
monitorAllTraffic() {
+ // TODO: Implement support for toggling between bits, packets and octets
+ this.flashMsg = this.lionFn('tr_fl_pstats_bits');
this.trs.init(this.force);
}
@@ -370,6 +490,22 @@
* Cancel traffic monitoring
*/
cancelTraffic() {
+ this.flashMsg = this.lionFn('fl_monitoring_canceled');
this.trs.destroy();
}
+
+ /**
+ * Read the LION bundle for Toolbar and set up the lionFn
+ */
+ doLion() {
+ this.lionFn = this.lion.bundle('core.view.Topo');
+ }
+
+ /**
+ * A dummy implementation of the lionFn until the response is received and the LION
+ * bundle is received from the WebSocket
+ */
+ dummyLion(key: string): string {
+ return '%' + key + '%';
+ }
}