Added in summary panel of GUI 2 topo view
Change-Id: I5d325ff1dc2940e08ab9e6f970768b5fd0885e10
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/glyph.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/glyph.service.ts
index 56d62ab..c51af7a 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/glyph.service.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/glyph.service.ts
@@ -190,19 +190,22 @@
}
addGlyph(elem: any, glyphId: string, size: number, overlay: any, trans: any) {
- const sz = size || 40,
- ovr = !!overlay,
- xns = this.fs.isA(trans),
- atr = {
- width: sz,
- height: sz,
- 'class': 'glyph',
- 'xlink:href': '#' + glyphId,
- };
+ const sz = size || 40;
+ const ovr = !!overlay;
+ const xns = this.fs.isA(trans);
+
+ const glyphUse = elem
+ .append('use')
+ .attr('width', sz)
+ .attr('height', sz)
+ .attr('class', 'glyph')
+ .attr('xlink:href', '#' + glyphId)
+ .classed('overlay', ovr);
if (xns) {
- atr.class = this.sus.translate(trans);
+ glyphUse.attr('transform', this.sus.translate(trans));
}
- return elem.append('use').attr(atr).classed('overlay', ovr);
+
+ return glyphUse;
}
}
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/svgutil.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/svgutil.service.ts
index 6107d16..7510486 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/svgutil.service.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/svgutil.service.ts
@@ -18,6 +18,34 @@
import { LogService } from '../log.service';
import * as d3 from 'd3';
+
+// --- Ordinal scales for 7 values.
+// TODO: migrate these colors to the theme service.
+
+// Colors per Mojo-Design's color palette.. (version one)
+// blue red dk grey steel lt blue lt red lt grey
+// var lightNorm = ['#5b99d2', '#d05a55', '#716b6b', '#7e9aa8', '#66cef6', '#db7773', '#aeada8' ],
+// lightMute = ['#a8cceb', '#f1a7a7', '#b9b5b5', '#bdcdd5', '#a8e9fd', '#f8c9c9', '#d7d6d4' ],
+
+// Colors per Mojo-Design's color palette.. (version two)
+// blue lt blue red green brown teal lime
+const lightNorm: string[] = ['#5b99d2', '#66cef6', '#d05a55', '#0f9d58', '#ba7941', '#3dc0bf', '#56af00'];
+const lightMute: string[] = ['#9ebedf', '#abdef5', '#d79a96', '#7cbe99', '#cdab8d', '#96d5d5', '#a0c96d'];
+
+const darkNorm: string[] = ['#5b99d2', '#66cef6', '#d05a55', '#0f9d58', '#ba7941', '#3dc0bf', '#56af00'];
+const darkMute: string[] = ['#9ebedf', '#abdef5', '#d79a96', '#7cbe99', '#cdab8d', '#96d5d5', '#a0c96d'];
+
+const colors = {
+ light: {
+ norm: d3.scaleOrdinal().range(lightNorm),
+ mute: d3.scaleOrdinal().range(lightMute),
+ },
+ dark: {
+ norm: d3.scaleOrdinal().range(darkNorm),
+ mute: d3.scaleOrdinal().range(darkMute),
+ },
+};
+
/**
* ONOS GUI -- SVG -- Util Service
*
@@ -27,44 +55,13 @@
providedIn: 'root',
})
export class SvgUtilService {
- lightNorm: string[];
- lightMute: string[];
- darkNorm: string[];
- darkMute: string[];
- colors: any;
constructor(
private fs: FnService,
private log: LogService
) {
- // --- Ordinal scales for 7 values.
- // TODO: migrate these colors to the theme service.
- // Colors per Mojo-Design's color palette.. (version one)
- // blue red dk grey steel lt blue lt red lt grey
- // var lightNorm = ['#5b99d2', '#d05a55', '#716b6b', '#7e9aa8', '#66cef6', '#db7773', '#aeada8' ],
- // lightMute = ['#a8cceb', '#f1a7a7', '#b9b5b5', '#bdcdd5', '#a8e9fd', '#f8c9c9', '#d7d6d4' ],
-
- // Colors per Mojo-Design's color palette.. (version two)
- // blue lt blue red green brown teal lime
- this.lightNorm = ['#5b99d2', '#66cef6', '#d05a55', '#0f9d58', '#ba7941', '#3dc0bf', '#56af00'];
- this.lightMute = ['#9ebedf', '#abdef5', '#d79a96', '#7cbe99', '#cdab8d', '#96d5d5', '#a0c96d'];
-
- this.darkNorm = ['#5b99d2', '#66cef6', '#d05a55', '#0f9d58', '#ba7941', '#3dc0bf', '#56af00'];
- this.darkMute = ['#9ebedf', '#abdef5', '#d79a96', '#7cbe99', '#cdab8d', '#96d5d5', '#a0c96d'];
-
-
- this.colors = {
- light: {
- norm: d3.scaleOrdinal().range(this.lightNorm),
- mute: d3.scaleOrdinal().range(this.lightMute),
- },
- dark: {
- norm: d3.scaleOrdinal().range(this.darkNorm),
- mute: d3.scaleOrdinal().range(this.darkMute),
- },
- };
this.log.debug('SvgUtilService constructed');
}
@@ -95,10 +92,10 @@
// NOTE: since we are lazily assigning domain ids, we need to
// get the color from all 4 scales, to keep the domains
// in sync.
- const ln = this.colors.light.norm(id);
- const lm = this.colors.light.mute(id);
- const dn = this.colors.dark.norm(id);
- const dm = this.colors.dark.mute(id);
+ const ln = colors.light.norm(id);
+ const lm = colors.light.mute(id);
+ const dn = colors.dark.norm(id);
+ const dm = colors.dark.mute(id);
if (theme === 'dark') {
return muted ? dm : dn;
} else {
@@ -126,32 +123,27 @@
muted = k % 2;
what = muted ? ' muted' : ' normal';
theme = k < 2 ? 'light' : 'dark';
- dom.forEach(function (id, i) {
+ dom.forEach((id, i) => {
const x = i * 20;
const y = k * 20;
- const f = getColor(id, muted, theme);
- g.append('circle').attr({
- cx: x,
- cy: y,
- r: 5,
- fill: f,
- });
+ g.append('circle')
+ .attr('cx', x)
+ .attr('cy', y)
+ .attr('r', 5)
+ .attr('fill', getColor(id, muted, theme));
});
- g.append('rect').attr({
- x: 140,
- y: k * 20 - 5,
- width: 32,
- height: 10,
- rx: 2,
- fill: '#888',
- });
+ g.append('rect')
+ .attr('x', 140)
+ .attr('y', k * 20 - 5)
+ .attr('width', 32)
+ .attr('height', 10)
+ .attr('rx', 2)
+ .attr('fill', '#888');
g.append('text').text(theme + what)
- .attr({
- x: 142,
- y: k * 20 + 2,
- fill: 'white',
- })
- .style('font-size', '4pt');
+ .attr('x', 142)
+ .attr('y', k * 20 + 2)
+ .attr('fill', 'white');
+ // .style('font-size', '4pt');
}
}
}
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/zoom.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/zoom.service.ts
index fdf08f9..8cbca5a 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/zoom.service.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/svg/zoom.service.ts
@@ -117,7 +117,7 @@
*/
// Remove zoom on double click (prevents a
// false zoom navigating regions)
- this.settings.svg.on('dblclick.zoom', null);
+ // this.settings.svg.on('dblclick.zoom', null);
return this.zoomer;
}
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/panel.base.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/panel.base.ts
index 0377c47..628f84f 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/panel.base.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/panel.base.ts
@@ -37,10 +37,10 @@
on: boolean;
- constructor(
+ protected constructor(
protected fs: FnService,
protected ls: LoadingService,
- protected log: LogService,
+ protected log: LogService
) {
// this.log.debug('Panel base class constructed');
}
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/table.base.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/table.base.ts
index 41ce239..e011057 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/table.base.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/widget/table.base.ts
@@ -91,13 +91,13 @@
autoRefresh: boolean = true;
autoRefreshTip: string = 'Toggle auto refresh'; // TODO: get LION string
- private root: string;
- private req: string;
- private resp: string;
+ readonly root: string;
+ readonly req: string;
+ readonly resp: string;
private refreshPromise: any = null;
private handlers: string[] = [];
- constructor(
+ protected constructor(
protected fs: FnService,
protected ls: LoadingService,
protected log: LogService,
diff --git a/web/gui2/BUILD b/web/gui2/BUILD
index 28b0624..0702802 100644
--- a/web/gui2/BUILD
+++ b/web/gui2/BUILD
@@ -93,7 +93,7 @@
":src/main/webapp/login.html",
":src/main/webapp/nav.html",
":src/main/webapp/not-ready.html",
- ":src/main/webapp/onos.theme.css",
+ ":src/main/webapp/onos.global.css",
],
)
diff --git a/web/gui2/angular.json b/web/gui2/angular.json
index 3563d9e..579fbf4 100644
--- a/web/gui2/angular.json
+++ b/web/gui2/angular.json
@@ -20,7 +20,7 @@
"src/main/webapp/data",
"src/main/webapp/app/fw/layer/loading.service.css"
],
- "styles": ["src/main/webapp/onos.theme.css"],
+ "styles": ["src/main/webapp/onos.global.css"],
"scripts": []
},
"configurations": {
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.html b/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.html
deleted file mode 100644
index 6f1bb4b..0000000
--- a/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.html
+++ /dev/null
@@ -1,19 +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.
--->
-<svg:g id="topo-zoomlayer">
- <svg:g onos-backgroundsvg/>
- <svg:g onos-forcesvg/>
-</svg:g>
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.spec.ts b/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.spec.ts
deleted file mode 100644
index 60a1997..0000000
--- a/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.spec.ts
+++ /dev/null
@@ -1,86 +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 { ActivatedRoute, Params } from '@angular/router';
-import { of } from 'rxjs';
-
-import { ZoomLayerSvgComponent } from './zoomlayersvg.component';
-import {
- FnService,
- LogService,
- ZoomService
-} from 'gui2-fw-lib';
-
-class MockActivatedRoute extends ActivatedRoute {
- constructor(params: Params) {
- super();
- this.queryParams = of(params);
- }
-}
-
-class MockZoomService {}
-
-/**
- * ONOS GUI -- Topology View Zoom Layer -- Unit Tests
- */
-describe('ZoomLayerSvgComponent', () => {
- let fs: FnService;
- let ar: MockActivatedRoute;
- let windowMock: Window;
- let logServiceSpy: jasmine.SpyObj<LogService>;
- let component: ZoomLayerSvgComponent;
- let fixture: ComponentFixture<ZoomLayerSvgComponent>;
-
- beforeEach(async(() => {
- const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
- ar = new MockActivatedRoute({ 'debug': 'txrx' });
-
- windowMock = <any>{
- location: <any>{
- hostname: 'foo',
- host: 'foo',
- port: '80',
- protocol: 'http',
- search: { debug: 'true' },
- href: 'ws://foo:123/onos/ui/websock/path',
- absUrl: 'ws://foo:123/onos/ui/websock/path'
- }
- };
- fs = new FnService(ar, logSpy, windowMock);
-
- TestBed.configureTestingModule({
- declarations: [ ZoomLayerSvgComponent ],
- providers: [
- { provide: FnService, useValue: fs },
- { provide: LogService, useValue: logSpy },
- { provide: 'Window', useValue: windowMock },
- { provide: ZoomService, useClass: MockZoomService }
- ]
- })
- .compileComponents();
- logServiceSpy = TestBed.get(LogService);
- }));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(ZoomLayerSvgComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.ts b/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.ts
deleted file mode 100644
index e0c85ed..0000000
--- a/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.ts
+++ /dev/null
@@ -1,112 +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';
-import {
- FnService,
- LogService,
- ZoomService, Zoomer, ZoomOpts
-} from 'gui2-fw-lib';
-
-/**
- * ONOS GUI -- Topology Zoom Layer View.
- * View that contains the 'Force graph' message
- *
- * This component is an SVG snippet that expects to be in an SVG element with a view box of 1000x1000
- *
- * It should be added to a template with a tag like <svg:g onos-zoomlayer />
- */
-@Component({
- selector: '[onos-zoomlayer]',
- templateUrl: './zoomlayersvg.component.html',
- styleUrls: ['./zoomlayersvg.component.css']
-})
-export class ZoomLayerSvgComponent implements OnInit {
- zoomer: Zoomer;
- zoomEventListeners: any[];
-
- constructor(
- protected fs: FnService,
- protected log: LogService,
- protected zs: ZoomService
- ) {
- this.log.debug('ZoomLayerSvgComponent constructed');
- }
-
- ngOnInit() {
-
- }
-
- createZoomer(options: ZoomOpts) {
- // need to wrap the original zoom callback to extend its behavior
- const origCallback = this.fs.isF(options.zoomCallback) ? options.zoomCallback : () => {};
-
- options.zoomCallback = () => {
- origCallback([0, 0], 1);
-
- this.zoomEventListeners.forEach((ev) => ev(this.zoomer));
- };
-
- this.zoomer = this.zs.createZoomer(options);
- return this.zoomer;
- }
-
- getZoomer() {
- return this.zoomer;
- }
-
- findZoomEventListener(ev) {
- for (let i = 0, len = this.zoomEventListeners.length; i < len; i++) {
- if (this.zoomEventListeners[i] === ev) {
- return i;
- }
- }
- return -1;
- }
-
- addZoomEventListener(callback) {
- this.zoomEventListeners.push(callback);
- }
-
- removeZoomEventListener(callback) {
- const evIndex = this.findZoomEventListener(callback);
-
- if (evIndex !== -1) {
- this.zoomEventListeners.splice(evIndex);
- }
- }
-
- adjustmentScale(min: number, max: number): number {
- let _scale = 1;
- const size = (min + max) / 2;
-
- if (size * this.scale() < max) {
- _scale = min / (size * this.scale());
- } else if (size * this.scale() > max) {
- _scale = min / (size * this.scale());
- }
-
- return _scale;
- }
-
- scale(): number {
- return this.zoomer.scale();
- }
-
- panAndZoom(translate: number[], scale: number, transition?: number) {
- this.zoomer.panZoom(translate, scale, transition);
- }
-
-}
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 1ff43e6..af8f6a0 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
@@ -14,7 +14,7 @@
~ limitations under the License.
-->
<div id="topo2-p-detail" class="floatpanel topo2-p"
- style="opacity: 1; right: 20px; width: 260px; top: 350px;" [@detailsPanelState]="!on">
+ style="opacity: 1; right: 20px; width: 260px; top: 350px;" [@detailsPanelState]="on">
<div class="header">
<div class="icon clickable">
<svg>
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 c8bf95b..0fcf179 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
@@ -63,6 +63,7 @@
}
ngOnInit() {
+ this.on = false;
}
}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.html b/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.html
index e71b58d..d781418 100644
--- a/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.html
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.html
@@ -14,63 +14,7 @@
~ limitations under the License.
-->
<div id="topo2-p-summary" class="floatpanel topo2-p"
- style="opacity: 1; right: 20px; width: 260px;" [@summaryPanelState]="!on">
- <div class="header">
- <div class="icon">
- <svg>
- <use width="24" height="24" class="glyph" xlink:href="#bird"
- transform="translate(1,1)"></use>
- </svg>
- </div>
- <h2>ONOS Summary</h2>
- </div>
- <div class="body">
- <table>
- <tbody>
- <tr>
- <td class="label">Version :</td>
- <td class="value">1.15.0.a18e6e1</td>
- </tr>
- <tr>
- <td colspan="2">
- <hr>
- </td>
- </tr>
- <tr>
- <td class="label">Devices :</td>
- <td class="value">2</td>
- </tr>
- <tr>
- <td class="label">Links :</td>
- <td class="value">0</td>
- </tr>
- <tr>
- <td class="label">Hosts :</td>
- <td class="value">0</td>
- </tr>
- <tr>
- <td class="label">Topology SCCs :</td>
- <td class="value">2</td>
- </tr>
- <tr>
- <td colspan="2">
- <hr>
- </td>
- </tr>
- <tr>
- <td class="label">Intents :</td>
- <td class="value">0</td>
- </tr>
- <tr>
- <td class="label">Tunnels :</td>
- <td class="value">0</td>
- </tr>
- <tr>
- <td class="label">Flows :</td>
- <td class="value">8</td>
- </tr>
- </tbody>
- </table>
- </div>
- <div class="footer"></div>
+ style="opacity: 1; right: 20px; width: 260px;" [@summaryPanelState]="on">
+ <!-- everything else is filled in dynamically by listProps() and the
+ response showSummary received from the server -->
</div>
\ No newline at end of file
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 d314528..7de5e89 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
@@ -13,15 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Component, OnInit } from '@angular/core';
+import {Component, OnDestroy, OnInit, ViewEncapsulation} from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';
+import * as d3 from 'd3';
+import { TopoPanelBaseImpl } from '../topopanel.base';
import {
LogService,
LoadingService,
FnService,
- PanelBaseImpl
+ WebSocketService,
+ GlyphService
} from 'gui2-fw-lib';
+export interface SummaryResponse {
+ title: string;
+}
/*
ONOS GUI -- Topology Summary Module.
Defines modeling of ONOS Summary Panel.
@@ -31,9 +37,10 @@
templateUrl: './summary.component.html',
styleUrls: [
'./summary.component.css',
- '../../topology.common.css',
+ '../../topology.common.css', '../../topology.theme.css',
'../../../../fw/widget/panel.css', '../../../../fw/widget/panel-theme.css'
],
+ encapsulation: ViewEncapsulation.None,
animations: [
trigger('summaryPanelState', [
state('true', style({
@@ -49,19 +56,62 @@
])
]
})
-export class SummaryComponent extends PanelBaseImpl implements OnInit {
+export class SummaryComponent extends TopoPanelBaseImpl implements OnInit, OnDestroy {
+ private handlers: string[] = [];
+ private resp: string = 'showSummary';
+ private summaryData: SummaryResponse;
constructor(
protected fs: FnService,
protected log: LogService,
protected ls: LoadingService,
+ protected wss: WebSocketService,
+ protected gs: GlyphService
) {
- super(fs, ls, log);
+ super(fs, ls, log, 'summary');
+ this.summaryData = <SummaryResponse>{};
this.log.debug('SummaryComponent constructed');
}
ngOnInit() {
+ this.wss.bindHandlers(new Map<string, (data) => void>([
+ [this.resp, (data) => this.handleSummaryData(data)]
+ ]));
+ this.handlers.push(this.resp);
+
+ this.init(d3.select('#topo2-p-summary'));
+ this.on = true;
+
+ this.wss.sendEvent('requestSummary', {});
}
+ ngOnDestroy() {
+ this.wss.sendEvent('cancelSummary', {});
+ this.wss.unbindHandlers(this.handlers);
+ }
+
+ handleSummaryData(data: SummaryResponse) {
+ this.summaryData = data;
+ this.render();
+ this.log.debug('Summary', data);
+ }
+
+ private render() {
+ let endedWithSeparator;
+
+ this.emptyRegions();
+
+ const svg = this.appendToHeader('div')
+ .classed('icon', true)
+ .append('svg');
+ const title = this.appendToHeader('h2');
+ const table = this.appendToBody('table');
+ const tbody = table.append('tbody');
+
+ title.text(this.summaryData.title);
+ this.gs.addGlyph(svg, 'bird', 24, 0, [1, 1]);
+ endedWithSeparator = this.listProps(tbody, this.summaryData);
+ // TODO : review whether we need to use/store end-with-sep state
+ }
}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/topopanel.base.ts b/web/gui2/src/main/webapp/app/view/topology/panel/topopanel.base.ts
new file mode 100644
index 0000000..48aa2ed
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/topopanel.base.ts
@@ -0,0 +1,109 @@
+/*
+ * 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 {
+ FnService,
+ LoadingService,
+ LogService,
+ PanelBaseImpl
+} from 'gui2-fw-lib';
+
+/**
+ * Base model of panel view - implemented by Topology Panel components
+ */
+export abstract class TopoPanelBaseImpl extends PanelBaseImpl {
+
+ protected header: any;
+ protected body: any;
+ protected footer: any;
+
+ protected constructor(
+ protected fs: FnService,
+ protected ls: LoadingService,
+ protected log: LogService,
+ protected id: string
+ ) {
+ super(fs, ls, log);
+ }
+
+ protected init(el: any) {
+ this.header = el.append('div').classed('header', true);
+ this.body = el.append('div').classed('body', true);
+ this.footer = el.append('div').classed('footer', true);
+ }
+
+ /**
+ * Decode lists of props sent back through Web Socket
+ *
+ * Means that panels do not have to know property names in advance
+ * Driven by PropertyPanel on Server side
+ */
+ listProps(el, data) {
+ let sepLast: boolean = false;
+
+ // note: track whether we end with a separator or not...
+ data.propOrder.forEach((p) => {
+ if (p === '-') {
+ this.addSep(el);
+ sepLast = true;
+ } else {
+ this.addProp(el, data.propLabels[p], data.propValues[p]);
+ sepLast = false;
+ }
+ });
+ return sepLast;
+ }
+
+ addProp(el, label, value) {
+ const tr = el.append('tr');
+ let lab;
+
+ if (typeof label === 'string') {
+ lab = label.replace(/_/g, ' ');
+ } else {
+ lab = label;
+ }
+
+ function addCell(cls, txt) {
+ tr.append('td').attr('class', cls).text(txt);
+ }
+
+ addCell('label', lab + ' :');
+ addCell('value', value);
+ }
+
+ addSep(el) {
+ el.append('tr').append('td').attr('colspan', 2).append('hr');
+ }
+
+ appendToHeader(x) {
+ return this.header.append(x);
+ }
+
+ appendToBody(x) {
+ return this.body.append(x);
+ }
+
+ appendToFooter(x) {
+ return this.footer.append(x);
+ }
+
+ emptyRegions() {
+ this.header.selectAll('*').remove();
+ this.body.selectAll('*').remove();
+ this.footer.selectAll('*').remove();
+ }
+
+}
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 cc03053..a26f3ec 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
@@ -19,7 +19,6 @@
import { TopologyComponent } from './topology/topology.component';
import { NoDeviceConnectedSvgComponent } from './layer/nodeviceconnectedsvg/nodeviceconnectedsvg.component';
import { LayoutComponent } from './layer/layout/layout.component';
-import { ZoomLayerSvgComponent } from './layer/zoomlayersvg/zoomlayersvg.component';
import { InstanceComponent } from './panel/instance/instance.component';
import { SummaryComponent } from './panel/summary/summary.component';
import { ToolbarComponent } from './panel/toolbar/toolbar.component';
@@ -45,7 +44,6 @@
TopologyComponent,
NoDeviceConnectedSvgComponent,
LayoutComponent,
- ZoomLayerSvgComponent,
InstanceComponent,
SummaryComponent,
ToolbarComponent,
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.css b/web/gui2/src/main/webapp/app/view/topology/topology.theme.css
similarity index 61%
rename from web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.css
rename to web/gui2/src/main/webapp/app/view/topology/topology.theme.css
index fca0dc7..caa6199 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/zoomlayersvg/zoomlayersvg.component.css
+++ b/web/gui2/src/main/webapp/app/view/topology/topology.theme.css
@@ -15,5 +15,32 @@
*/
/**
- * ONOS GUI -- Topology Zoom Layer -- CSS file
- */
\ No newline at end of file
+ * ONOS GUI -- Topology Common styles -- CSS file
+ */
+
+.topo2-p h2 {
+ display: inline-block;
+ padding: 6px;
+}
+
+.topo2-p svg {
+ background: #c0242b;
+ width: 28px;
+ height: 28px;
+}
+
+.topo2-p svg .glyph {
+ fill: #ffffff;
+}
+
+.topo2-p hr {
+ background-color: #cccccc;
+}
+
+#topo2-p-detail svg {
+ background: none;
+}
+
+#topo2-p-detail .header svg .glyph {
+ fill: #c0242b;
+}
\ No newline at end of file
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 7347cb5..0db2c82 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
@@ -21,11 +21,12 @@
<onos-details #details></onos-details>
<div id="ov-topo2">
- <svg viewBox="0 0 1000 1000" id="topo2"
- resize offset-height="56" offset-width="12"
- notifier="notifyResize()">
+ <svg viewBox="0 0 1000 1000" id="topo2">
<svg:g onos-nodeviceconnected />
- <svg:g onos-zoomlayer />
+ <svg:g id="topo-zoomlayer">
+ <svg:g onos-backgroundsvg/>
+ <svg:g onos-forcesvg/>
+ </svg:g>
</svg>
</div>
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 5ed744b..bf46637 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
@@ -14,11 +14,12 @@
* limitations under the License.
*/
import { Component, OnInit, ViewChild } from '@angular/core';
+import * as d3 from 'd3';
import {
FnService,
KeysService, KeysToken,
LogService, PrefsService,
- SvgUtilService, WebSocketService
+ SvgUtilService, WebSocketService, Zoomer, ZoomOpts, ZoomService
} from 'gui2-fw-lib';
import {InstanceComponent} from '../panel/instance/instance.component';
import {SummaryComponent} from '../panel/summary/summary.component';
@@ -60,16 +61,19 @@
flashMsg: string = '';
prefsState = {};
- svg: any;
hostLabelIdx: number = 1;
+ zoomer: Zoomer;
+ zoomEventListeners: any[];
+
constructor(
protected log: LogService,
protected fs: FnService,
protected ks: KeysService,
protected sus: SvgUtilService,
protected ps: PrefsService,
- protected wss: WebSocketService
+ protected wss: WebSocketService,
+ protected zs: ZoomService
) {
this.log.debug('Topology component constructed');
@@ -77,6 +81,15 @@
ngOnInit() {
this.bindCommands();
+ this.zoomer = this.createZoomer(<ZoomOpts>{
+ svg: d3.select('svg#topo2'),
+ zoomLayer: d3.select('g#topo-zoomlayer'),
+ zoomEnabled: () => true,
+ zoomMin: 0.25,
+ zoomMax: 10.0,
+ zoomCallback: (() => { return; })
+ });
+ this.zoomEventListeners = [];
this.log.debug('Topology component initialized');
}
@@ -88,6 +101,8 @@
I: [(token) => {this.toggleInstancePanel(token); }, 'Toggle ONOS Instance Panel'],
O: [() => {this.toggleSummary(); }, 'Toggle the Summary Panel'],
R: [() => {this.resetZoom(); }, 'Reset pan / zoom'],
+ 'shift-Z': [() => {this.panAndZoom([0, 0], this.zoomer.scale() * 2); }, 'Zoom x2'],
+ 'alt-Z': [() => {this.panAndZoom([0, 0], this.zoomer.scale() / 2); }, 'Zoom x0.5'],
P: [(token) => {this.togglePorts(token); }, 'Toggle Port Highlighting'],
E: [() => {this.equalizeMasters(); }, 'Equalize mastership roles'],
X: [() => {this.resetNodeLocation(); }, 'Reset Node Location'],
@@ -98,8 +113,8 @@
'shift-L': [() => {this.cycleHostLabels(); }, 'Cycle host labels'],
// -- instance color palette debug
- 9: function () {
- this.sus.cat7().testCard(this.svg);
+ 9: () => {
+ this.sus.cat7().testCard(d3.select('svg#topo2'));
},
esc: this.handleEscape,
@@ -249,6 +264,7 @@
}
protected resetZoom() {
+ this.zoomer.reset();
this.log.debug('resetting zoom');
// TODO: Reinstate with components
// t2bgs.resetZoom();
@@ -332,4 +348,65 @@
return this.fs.isA(entry) || [entry, ''];
}
+
+
+ protected createZoomer(options: ZoomOpts) {
+ // need to wrap the original zoom callback to extend its behavior
+ const origCallback = this.fs.isF(options.zoomCallback) ? options.zoomCallback : () => {};
+
+ options.zoomCallback = () => {
+ origCallback([0, 0], 1);
+
+ this.zoomEventListeners.forEach((ev) => ev(this.zoomer));
+ };
+
+ return this.zs.createZoomer(options);
+ }
+
+ getZoomer() {
+ return this.zoomer;
+ }
+
+ findZoomEventListener(ev) {
+ for (let i = 0, len = this.zoomEventListeners.length; i < len; i++) {
+ if (this.zoomEventListeners[i] === ev) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ addZoomEventListener(callback) {
+ this.zoomEventListeners.push(callback);
+ }
+
+ removeZoomEventListener(callback) {
+ const evIndex = this.findZoomEventListener(callback);
+
+ if (evIndex !== -1) {
+ this.zoomEventListeners.splice(evIndex);
+ }
+ }
+
+ adjustmentScale(min: number, max: number): number {
+ let _scale = 1;
+ const size = (min + max) / 2;
+
+ if (size * this.scale() < max) {
+ _scale = min / (size * this.scale());
+ } else if (size * this.scale() > max) {
+ _scale = min / (size * this.scale());
+ }
+
+ return _scale;
+ }
+
+ scale(): number {
+ return this.zoomer.scale();
+ }
+
+ panAndZoom(translate: number[], scale: number, transition?: number) {
+ this.zoomer.panZoom(translate, scale, transition);
+ }
+
}
diff --git a/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-300.woff b/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-300.woff
new file mode 100644
index 0000000..38328c4
--- /dev/null
+++ b/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-300.woff
Binary files differ
diff --git a/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-300.woff2 b/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-300.woff2
new file mode 100644
index 0000000..4af4545
--- /dev/null
+++ b/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-300.woff2
Binary files differ
diff --git a/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-600.woff b/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-600.woff
new file mode 100644
index 0000000..5a604b3
--- /dev/null
+++ b/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-600.woff
Binary files differ
diff --git a/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-600.woff2 b/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-600.woff2
new file mode 100644
index 0000000..a0965b7
--- /dev/null
+++ b/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-600.woff2
Binary files differ
diff --git a/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-700.woff b/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-700.woff
new file mode 100644
index 0000000..2523e95
--- /dev/null
+++ b/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-700.woff
Binary files differ
diff --git a/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-700.woff2 b/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-700.woff2
new file mode 100644
index 0000000..2b04b15
--- /dev/null
+++ b/web/gui2/src/main/webapp/fonts/open-sans-v15-latin-700.woff2
Binary files differ
diff --git a/web/gui2/src/main/webapp/index.html b/web/gui2/src/main/webapp/index.html
index 780634c..f50331b 100644
--- a/web/gui2/src/main/webapp/index.html
+++ b/web/gui2/src/main/webapp/index.html
@@ -24,10 +24,6 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
- <!-- Needs investigation - should not have any external dependencies -->
- <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,700'
- rel='stylesheet' type='text/css'>
- <link href="onos.theme.css" type='text/css'>
<link href="app/fw/layer/loading.service.css" rel='stylesheet' type='text/css'>
<base href="/">
<title>ONOS</title>
diff --git a/web/gui2/src/main/webapp/onos.theme.css b/web/gui2/src/main/webapp/onos.global.css
similarity index 69%
rename from web/gui2/src/main/webapp/onos.theme.css
rename to web/gui2/src/main/webapp/onos.global.css
index 8a09e16..36f107e 100644
--- a/web/gui2/src/main/webapp/onos.theme.css
+++ b/web/gui2/src/main/webapp/onos.global.css
@@ -18,12 +18,48 @@
ONOS GUI -- core (theme) -- CSS file
*/
+/**
+ * Offline cache - see
+ * https://google-webfonts-helper.herokuapp.com/fonts/open-sans?subsets=latin
+ */
+/* open-sans-300 - latin */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: normal;
+ font-weight: 300;
+ src: local('Open Sans Light'), local('OpenSans-Light'),
+ url('./fonts/open-sans-v15-latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+ url('./fonts/open-sans-v15-latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+}
+
+/* open-sans-600 - latin */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: normal;
+ font-weight: 600;
+ src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'),
+ url('./fonts/open-sans-v15-latin-600.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+ url('./fonts/open-sans-v15-latin-600.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+}
+
+/* open-sans-700 - latin */
+@font-face {
+ font-family: 'Open Sans';
+ font-style: normal;
+ font-weight: 700;
+ src: local('Open Sans Bold'), local('OpenSans-Bold'),
+ url('./fonts/open-sans-v15-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+ url('./fonts/open-sans-v15-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+}
+
+
+
body {
background-color: white;
}
html {
- font-family: 'Open Sans', sans-serif;
+ font-family: 'Open Sans', normal;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
height: 100%;
@@ -41,7 +77,7 @@
#view h2 {
color: #3c3a3a;
- margin: 32px 0 4px 16px;
+ /*margin: 32px 0 4px 16px;*/
padding: 0;
font-size: 18pt;
font-weight: lighter;