GUI2 add in support for Preferences Service
Change-Id: Icdf2165d9f638aeff1b110a64777b93295935ed2
diff --git a/web/gui/BUILD b/web/gui/BUILD
index 77fa7f7..f8b70c8 100644
--- a/web/gui/BUILD
+++ b/web/gui/BUILD
@@ -210,14 +210,24 @@
genrule(
name = "onos-gui-java-for-gui2",
srcs = glob([
- "src/main/java/org/onosproject/ui/impl/Main*Resource.java",
- "src/main/java/org/onosproject/ui/impl/ApplicationResource.java",
+ "src/main/java/org/onosproject/ui/impl/**/*.java",
]),
outs = ["onos-gui-java-for-gui2.srcjar"],
cmd = "jar cf $@ $(SRCS)",
visibility = ["//visibility:public"],
)
+genrule(
+ name = "onos-gui-lion-for-gui2",
+ srcs = glob([
+ "src/main/resources/org/onosproject/ui/lion/**/*",
+ "src/main/resources/core/**/*",
+ ]),
+ outs = ["onos-gui-lion-for-gui2.srcjar"],
+ cmd = "jar cf $@ $(SRCS)",
+ visibility = ["//visibility:public"],
+)
+
"""
Builds the tar ball for the ONOS GUI
"""
diff --git a/web/gui2-fw-lib/BUILD b/web/gui2-fw-lib/BUILD
index 667814f..b47749b 100644
--- a/web/gui2-fw-lib/BUILD
+++ b/web/gui2-fw-lib/BUILD
@@ -281,8 +281,14 @@
" export PATH=$$ROOT/$$(dirname $${NODE}):$$ROOT/web/gui2-fw-lib/node_modules/@angular/cli/bin:$$PATH &&" +
" node -v > ../../$(location onos-gui2-fw-ng-ver.log) &&" +
" npm -v >> ../../$(location onos-gui2-fw-ng-ver.log) &&" +
- " ng version >> ../../$(location onos-gui2-fw-ng-ver.log) &&" +
- " ng lint gui2-fw-lib > ../../$(location onos-gui2-fw-ng-lint.log);" +
+ " ng version >> ../../$(location onos-gui2-fw-ng-ver.log);" +
+ " ng lint gui2-fw-lib > ../../$(location onos-gui2-fw-ng-lint.log) 2>&1 ||" +
+ " if [ $$? -eq 0 ]; then echo 'Successfully ran lint';" +
+ " else " +
+ " echo 'Error running \'ng lint\' on \'//web/gui2-fw-lib:_onos-gui2-fw-ng-test\'. \\\n" +
+ " See bazel-genfiles/web/gui2-fw-lib/onos-gui2-fw-ng-lint.log for more details' >&2;" +
+ " exit 1;" +
+ " fi;" +
" if [ -f /usr/bin/chromium-browser ]; then " + # Add to this for Mac and Chrome
" export CHROME_BIN=/usr/bin/chromium-browser; " +
" elif [ -f /opt/google/chrome/chrome ]; then " +
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/gui2-fw-lib.module.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/gui2-fw-lib.module.ts
index 6004bce..f213ca1 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/gui2-fw-lib.module.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/gui2-fw-lib.module.ts
@@ -23,6 +23,7 @@
import { MastComponent } from './mast/mast/mast.component';
import { TableFilterPipe } from './widget/tablefilter.pipe';
import { TableResizeDirective } from './widget/tableresize.directive';
+import { QuickhelpComponent } from './layer/quickhelp/quickhelp.component';
@NgModule({
imports: [
@@ -35,6 +36,7 @@
VeilComponent,
FlashComponent,
ConfirmComponent,
+ QuickhelpComponent,
MastComponent,
TableFilterPipe
],
@@ -45,6 +47,7 @@
VeilComponent,
FlashComponent,
ConfirmComponent,
+ QuickhelpComponent,
MastComponent,
TableFilterPipe
]
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/quickhelp/quickhelp.component.css b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/quickhelp/quickhelp.component.css
new file mode 100644
index 0000000..26c1643
--- /dev/null
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/quickhelp/quickhelp.component.css
@@ -0,0 +1,54 @@
+/*
+ * 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 -- Quickhelp Panel -- CSS file
+ */
+
+/*
+ ONOS GUI -- Quick Help Service (layout) -- CSS file
+ */
+
+#quickhelp {
+ top: 100px;
+ z-index: 5000;
+ position: relative;
+}
+
+#quickhelp div.help {
+ background: black;
+ opacity: 0.8;
+}
+
+#quickhelp div.help table {
+ vertical-align: top;
+}
+
+#quickhelp div.help p {
+ text-align: center;
+ color: white;
+ font-weight: bold;
+}
+
+#quickhelp td.key {
+ color: #add;
+ padding-left: 8px;
+ padding-right: 4px;
+}
+
+#quickhelp td.desc {
+ color: white;
+}
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/quickhelp/quickhelp.component.html b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/quickhelp/quickhelp.component.html
new file mode 100644
index 0000000..d387284
--- /dev/null
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/quickhelp/quickhelp.component.html
@@ -0,0 +1,160 @@
+<!--
+~ 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.
+~ 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.
+-->
+<div id="quickhelp" [@quickHelpState]="ks.quickHelpShown">
+ <div class="help" *ngIf="ks.quickHelpShown">
+ <p class="title">{{lionFn("qh_title")}}</p>
+ <!-- TODO: drive this through the keys service keyHandler -->
+ <table class="qhrow">
+ <tr>
+ <td class="key">\</td>
+ <td class="desc">Afficher/cacher l'aide rapide</td>
+ </tr>
+ <tr>
+ <td class="key">/</td>
+ <td class="desc">Afficher/cacher l'aide rapide</td>
+ </tr>
+ <tr>
+ <td class="key">Esc</td>
+ <td class="desc">ignorer la boîte de dialogue ou annuler les
+ sélections
+ </td>
+ </tr>
+ <tr>
+ <td class="key">T</td>
+ <td class="desc">basculer de thème</td>
+ </tr>
+ </table>
+ <hr class="qhrowsep">
+ <table class="qhrow">
+ <tr>
+ <td class="key">I</td>
+ <td class="desc">Basculer au panneau de instance
+ ONOS
+ </td>
+ <td class="key">O</td>
+ <td class="desc">Baculer au panneau récapitulatif
+ ONOS
+ </td>
+ <td class="key">D</td>
+ <td class="desc">Basculer le panneau de détails</td>
+ </tr>
+ <tr>
+ <td class="key">H</td>
+ <td class="desc">Basculer la visibilité de l'hôte
+ </td>
+ <td class="key">M</td>
+ <td class="desc">Basculer la visibilité hors-ligne
+ </td>
+ <td class="key">P</td>
+ <td class="desc">Basculer le port mis en évidence
+ </td>
+ </tr>
+ <tr>
+ <td class="key">Dash</td>
+ <td class="desc">Montrer les mauvais liens</td>
+ <td class="key">B</td>
+ <td class="desc">Basculer la carte géo de fond</td>
+ <td class="key">G</td>
+ <td class="desc">Sélectionner la carte géo de fond
+ </td>
+ </tr>
+ <tr>
+ <td class="key">S</td>
+ <td class="desc">Toggle sprite layer</td>
+ <td class="key" y="0">X</td>
+ <td class="desc" y="0" x="33.53125">réinitialiser la
+ carte des noeuds
+ </td>
+ <td class="key">Z</td>
+ <td class="desc">Basculer la vue oblique
+ (expérimental)
+ </td>
+ </tr>
+ <tr>
+ <td class="key">N</td>
+ <td class="desc">cycle couche de noeuds</td>
+ <td class="key">L</td>
+ <td class="desc">Parcourir étiquettes appareils</td>
+ <td class="key">Shift-l</td>
+ <td class="desc">Parcourir étiquettes hôte</td>
+ </tr>
+ <tr>
+ <td class="key">U</td>
+ <td class="desc">survoler avec la souris</td>
+ <td class="key">R</td>
+ <td class="desc">réinitialiser le zoom et le
+ panoramique
+ </td>
+ <td class="key">E</td>
+ <td class="desc">Egaliser les rôles de maîtrises
+ </td>
+ </tr>
+ <tr>
+ <td class="key">Dot</td>
+ <td class="desc">Basculer a la barre d'outils</td>
+ <td class="key">0</td>
+ <td class="desc">Annuler la surveillance du trafic
+ </td>
+ <td class="key">A</td>
+ <td class="desc">Surveiller tout le trafic</td>
+ </tr>
+ <tr>
+ <td class="key">F</td>
+ <td class="desc">Afficher les flux de liaison de périphérique
+ </td>
+ <td class="key">V</td>
+ <td class="desc">Show all related intents</td>
+ <td class="key">L-arrow</td>
+ <td class="desc">Show previous related intent</td>
+ </tr>
+ <tr>
+ <td class="key">R-arrow</td>
+ <td class="desc">Show next related intent</td>
+ <td class="key">W</td>
+ <td class="desc">Monitor traffic of selected intent</td>
+ </tr>
+ </table>
+ <hr>
+ <div class="qhrow">
+ <table class="qh-r4-c0">
+ <tr>
+ <td class="key">cliquer</td>
+ <td class="desc">Sélectionner l'article et montrer les
+ détails
+ </td>
+ </tr>
+ <tr>
+ <td class="key">Cliquer sur MAJ</td>
+ <td class="desc">Basculer l'état de sélection</td>
+ </tr>
+ <tr>
+ <td class="key">Glisser</td>
+ <td class="desc">Repositionner (et épingler) le périphérique
+ / l'hôte
+ </td>
+ </tr>
+ <tr>
+ <td class="key">cmd défiler</td>
+ <td class="desc">Zoom avant/arrière</td>
+ </tr>
+ <tr>
+ <td class="key" y="48">cmd-glisser</td>
+ <td class="desc" y="48" x="74.84375">Pan
+ </tr>
+ </table>
+ </div>
+ </div>
+</div>
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/quickhelp/quickhelp.component.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/quickhelp/quickhelp.component.spec.ts
new file mode 100644
index 0000000..da60a1b
--- /dev/null
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/quickhelp/quickhelp.component.spec.ts
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ * 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 { QuickhelpComponent } from './quickhelp.component';
+import {LogService} from '../../log.service';
+import {ConsoleLoggerService} from '../../consolelogger.service';
+import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
+import {FnService} from '../../util/fn.service';
+import {LionService} from '../../util/lion.service';
+import {KeysService} from '../../util/keys.service';
+
+class MockFnService {}
+
+class MockKeysService {
+
+}
+
+/**
+ * ONOS GUI -- Layer -- Quickhelp Component - Unit Tests
+ */
+describe('QuickhelpComponent', () => {
+ let log: LogService;
+ let component: QuickhelpComponent;
+ let fixture: ComponentFixture<QuickhelpComponent>;
+ const bundleObj = {
+ 'core.fw.QuickHelp': {
+ test: 'test1',
+ tt_help: 'Help!'
+ }
+ };
+ const mockLion = (key) => {
+ return bundleObj[key] || '%' + key + '%';
+ };
+
+ beforeEach(async(() => {
+ log = new ConsoleLoggerService();
+ TestBed.configureTestingModule({
+ imports: [ BrowserAnimationsModule ],
+ declarations: [ QuickhelpComponent ],
+ providers: [
+ { provide: LogService, useValue: log },
+ { provide: FnService, useClass: MockFnService },
+ { provide: LionService, useFactory: (() => {
+ return {
+ bundle: ((bundleId) => mockLion),
+ ubercache: new Array(),
+ loadCbs: new Map<string, () => void>([])
+ };
+ })
+ },
+ { provide: KeysService, useClass: MockKeysService }
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(QuickhelpComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/quickhelp/quickhelp.component.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/quickhelp/quickhelp.component.ts
new file mode 100644
index 0000000..6789e14
--- /dev/null
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/layer/quickhelp/quickhelp.component.ts
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ * 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} from '@angular/core';
+import {animate, state, style, transition, trigger} from '@angular/animations';
+import {LogService} from '../../log.service';
+import {FnService} from '../../util/fn.service';
+import {KeysService} from '../../util/keys.service';
+import {LionService} from '../../util/lion.service';
+
+
+@Component({
+ selector: 'onos-quickhelp',
+ templateUrl: './quickhelp.component.html',
+ styleUrls: ['./quickhelp.component.css'],
+ animations: [
+ trigger('quickHelpState', [
+ state('true', style({
+ opacity: '1.0',
+ })),
+ state('false', style({
+ opacity: '0.0',
+ })),
+ transition('0 => 1', animate('500ms ease-in')),
+ transition('1 => 0', animate('500ms ease-out'))
+ ])
+ ]
+})
+export class QuickhelpComponent {
+ lionFn; // Function
+
+ constructor(
+ private log: LogService,
+ private fs: FnService,
+ public ks: KeysService,
+ private lion: LionService
+ ) {
+ if (this.lion.ubercache.length === 0) {
+ this.lionFn = this.dummyLion;
+ this.lion.loadCbs.set('quickhelp', () => this.doLion());
+ } else {
+ this.doLion();
+ }
+
+ this.log.debug('Quickhelp component constructed');
+ }
+
+ /**
+ * Read the LION bundle for Toolbar and set up the lionFn
+ */
+ doLion() {
+ this.lionFn = this.lion.bundle('core.fw.QuickHelp');
+ }
+
+ /**
+ * 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-fw-lib/projects/gui2-fw-lib/src/lib/nav/nav.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/nav/nav.service.ts
index 337b104..98de228 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/nav/nav.service.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/nav/nav.service.ts
@@ -48,10 +48,8 @@
}
hideNav() {
- this.showNav = !this.showNav;
- if (!this.showNav) {
- this.log.debug('Hiding Nav menu');
- }
+ this.showNav = false;
+ this.log.debug('Hiding Nav menu');
}
toggleNav() {
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/urlfn.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/urlfn.service.spec.ts
index 2c31610..37a0cbd 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/urlfn.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/urlfn.service.spec.ts
@@ -71,7 +71,7 @@
windowMock.location.port = p;
windowMock.location.protocol = prot;
windowMock.location.href = prot + '://' + h + ':' + p +
- ctx + '/onos/ui/';
+ ctx + '/onos/ui2/';
}
it('should define UrlFnService', () => {
@@ -87,37 +87,37 @@
it('should return the correct (http) RS url', () => {
setLoc('http', 'foo', '123');
- expect(ufs.rsUrl('path')).toEqual('http://foo:123/onos/ui/rs/path');
+ expect(ufs.rsUrl('path')).toEqual('http://foo:123/onos/ui2/rs/path');
});
it('should return the correct (https) RS url', () => {
setLoc('https', 'foo', '123');
- expect(ufs.rsUrl('path')).toEqual('https://foo:123/onos/ui/rs/path');
+ expect(ufs.rsUrl('path')).toEqual('https://foo:123/onos/ui2/rs/path');
});
it('should return the correct (ws) WS url', () => {
setLoc('http', 'foo', '123');
- expect(ufs.wsUrl('path')).toEqual('ws://foo:123/onos/ui/websock/path');
+ expect(ufs.wsUrl('path')).toEqual('ws://foo:123/onos/ui2/websock/path');
});
it('should return the correct (wss) WS url', () => {
setLoc('https', 'foo', '123');
- expect(ufs.wsUrl('path')).toEqual('wss://foo:123/onos/ui/websock/path');
+ expect(ufs.wsUrl('path')).toEqual('wss://foo:123/onos/ui2/websock/path');
});
it('should allow us to define an alternate WS port', () => {
setLoc('http', 'foo', '123');
- expect(ufs.wsUrl('xyyzy', '456')).toEqual('ws://foo:456/onos/ui/websock/xyyzy');
+ expect(ufs.wsUrl('xyyzy', '456')).toEqual('ws://foo:456/onos/ui2/websock/xyyzy');
});
it('should allow us to define an alternate host', () => {
setLoc('http', 'foo', '123');
- expect(ufs.wsUrl('core', '456', 'bar')).toEqual('ws://bar:456/onos/ui/websock/core');
+ expect(ufs.wsUrl('core', '456', 'bar')).toEqual('ws://bar:456/onos/ui2/websock/core');
});
it('should allow us to inject an app context', () => {
setLoc('http', 'foo', '123', '/my/app');
- expect(ufs.wsUrl('path')).toEqual('ws://foo:123/my/app/onos/ui/websock/path');
+ expect(ufs.wsUrl('path')).toEqual('ws://foo:123/my/app/onos/ui2/websock/path');
});
});
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/urlfn.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/urlfn.service.ts
index a7576c0..12ca11c 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/urlfn.service.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/urlfn.service.ts
@@ -16,7 +16,7 @@
import { Injectable, Inject } from '@angular/core';
import { LogService } from '../log.service';
-const UICONTEXT = '/onos/ui/';
+const UICONTEXT = '/onos/ui2/';
const RSSUFFIX = UICONTEXT + 'rs/';
const WSSUFFIX = UICONTEXT + 'websock/';
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/websocket.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/websocket.service.spec.ts
index 7695e13..6c6ade8 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/websocket.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/websocket.service.spec.ts
@@ -64,8 +64,8 @@
port: '80',
protocol: 'http',
search: { debug: 'true'},
- href: 'ws://foo:123/onos/ui/websock/path',
- absUrl: 'ws://foo:123/onos/ui/websock/path'
+ href: 'ws://foo:123/onos/ui2/websock/path',
+ absUrl: 'ws://foo:123/onos/ui2/websock/path'
}
};
fs = new FnService(ar, logSpy, windowMock);
@@ -108,13 +108,13 @@
it('should use the appropriate URL, createWebsocket', () => {
const url = wss.createWebSocket();
- expect(url).toEqual('ws://foo:80/onos/ui/websock/core');
+ expect(url).toEqual('ws://foo:80/onos/ui2/websock/core');
});
it('should use the appropriate URL with modified port, createWebsocket',
() => {
const url = wss.createWebSocket(<WsOptions>{ wsport: 1243 });
- expect(url).toEqual('ws://foo:1243/onos/ui/websock/core');
+ expect(url).toEqual('ws://foo:1243/onos/ui2/websock/core');
});
it('should verify websocket event handlers, createWebsocket', () => {
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/websocket.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/websocket.service.ts
index c4d5227..2a254b4 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/websocket.service.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/remote/websocket.service.ts
@@ -91,6 +91,7 @@
*/
private bootstrap(data: Bootstrap) {
this.loggedInUser = data.user;
+ this.log.info('Websocket connection bootstraped', data);
this.clusterNodes = data.clusterNodes;
this.clusterNodes.forEach((d, i) => {
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/keys.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/keys.service.spec.ts
index 5f4b349..47299e7 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/keys.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/keys.service.spec.ts
@@ -89,7 +89,6 @@
});
ks = TestBed.get(KeysService);
ks.installOn(d3Elem);
- ks.bindQhs(qhs);
logServiceSpy = TestBed.get(LogService);
});
@@ -103,7 +102,7 @@
it('should define api functions', () => {
expect(fs.areFunctions(ks, [
- 'bindQhs', 'installOn', 'keyBindings', 'unbindKeys', 'dialogKeys',
+ 'installOn', 'keyBindings', 'unbindKeys', 'dialogKeys',
'addSeq', 'remSeq', 'gestureNotes', 'enableKeys', 'enableGlobalKeys',
'checkNotGlobal', 'getKeyBindings',
'matchSeq', 'whatKey', 'textFieldInput', 'keyIn', 'qhlion', 'qhlionShowHide',
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/keys.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/keys.service.ts
index decb87b..035037e 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/keys.service.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/keys.service.ts
@@ -59,7 +59,7 @@
enter: 1,
esc: 1,
};
- qhs: any; // Quick Help Service ??
+ quickHelpShown: boolean = false;
constructor(
protected log: LogService,
@@ -70,10 +70,6 @@
this.log.debug('KeyService constructed');
}
- bindQhs(_qhs_) {
- this.qhs = _qhs_;
- }
-
installOn(elem) {
this.log.debug('Installing keys handler');
elem.on('keydown', () => { this.keyIn(); });
@@ -314,14 +310,14 @@
if (!this.globalEnabled) {
return false;
}
- this.qhs.showQuickHelp(this.keyHandler);
+ this.quickHelpShown = !this.quickHelpShown;
return true;
}
// returns true if we 'consumed' the ESC keypress, false otherwise
protected escapeKey(view, key, code, ev) {
+ this.quickHelpShown = false;
return this.ns.hideNav();
- // TODO - also hide this.qhs.hideQuickHelp();
}
protected toggleTheme(view, key, code, ev) {
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/prefs.service.spec.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/prefs.service.spec.ts
index d925ecf..13892af 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/prefs.service.spec.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/prefs.service.spec.ts
@@ -35,6 +35,19 @@
*/
describe('PrefsService', () => {
let log: LogService;
+ let windowMock: Window;
+
+ 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'
+ }
+ };
beforeEach(() => {
log = new ConsoleLoggerService();
@@ -43,6 +56,7 @@
providers: [PrefsService,
{ provide: LogService, useValue: log },
{ provide: FnService, useClass: MockFnService },
+ { provide: 'Window', useFactory: (() => windowMock ) },
{ provide: WebSocketService, useClass: MockWebSocketService },
]
});
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/prefs.service.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/prefs.service.ts
index 8145921..b68b4dd 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/prefs.service.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/lib/util/prefs.service.ts
@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Injectable } from '@angular/core';
+import {Inject, Injectable} from '@angular/core';
import { FnService } from './fn.service';
import { LogService } from '../log.service';
import { WebSocketService } from '../remote/websocket.service';
+const UPDATE_PREFS: string = 'updatePrefs';
+const UPDATE_PREFS_REQ: string = 'updatePrefReq';
/**
* ONOS GUI -- Util -- User Preference Service
*/
@@ -25,32 +27,36 @@
providedIn: 'root',
})
export class PrefsService {
- protected Prefs;
protected handlers: string[] = [];
- cache: any;
- listeners: any;
+ cache: Object;
+ listeners: ((data) => void)[] = [];
constructor(
protected fs: FnService,
protected log: LogService,
- protected wss: WebSocketService
+ protected wss: WebSocketService,
+ @Inject('Window') private window: any
) {
- this.cache = {};
this.wss.bindHandlers(new Map<string, (data) => void>([
- [this.Prefs, (data) => this.updatePrefs(data)]
+ [UPDATE_PREFS, (data) => this.updatePrefs(data)]
]));
- this.handlers.push(this.Prefs);
+ this.handlers.push(UPDATE_PREFS);
+
+ // When index.html is fetched it is served up by MainIndexResource.java
+ // which fetches userPrefs in to the global scope.
+ // After that updates are done through WebSocket
+ this.cache = Object.assign({}, this.window['userPrefs']);
this.log.debug('PrefsService constructed');
}
- setPrefs(name: string, obj: any) {
+ setPrefs(name: string, obj: Object) {
// keep a cached copy of the object and send an update to server
this.cache[name] = obj;
- this.wss.sendEvent('updatePrefReq', { key: name, value: obj });
+ this.wss.sendEvent(UPDATE_PREFS_REQ, { key: name, value: obj });
}
updatePrefs(data: any) {
this.cache = data;
- this.listeners.forEach(function (lsnr) { lsnr(); });
+ this.listeners.forEach((lsnr) => lsnr(data) );
}
asNumbers(obj: any, keys?: any, not?: any) {
@@ -101,17 +107,22 @@
// defined keys should overwrite the corresponding values, but any
// existing keys that are NOT explicitly defined here should be left
// alone (not deleted).
- mergePrefs(name: string, obj: any) {
+ mergePrefs(name: string, obj: any): void {
const merged = this.cache[name] || {};
this.setPrefs(name, Object.assign(merged, obj));
}
- addListener(listener: any) {
+ /**
+ * Add a listener function
+ * This will get called back when an 'updatePrefs' message is received on WSS
+ * @param listener a function that can accept one param - data
+ */
+ addListener(listener: (data) => void): void {
this.listeners.push(listener);
}
- removeListener(listener: any) {
- this.listeners = this.listeners.filter(function (obj) { return obj === listener; });
+ removeListener(listener: (data) => void) {
+ this.listeners = this.listeners.filter((obj) => obj !== listener);
}
}
diff --git a/web/gui2-fw-lib/projects/gui2-fw-lib/src/public_api.ts b/web/gui2-fw-lib/projects/gui2-fw-lib/src/public_api.ts
index 5f162d5..3c6d141 100644
--- a/web/gui2-fw-lib/projects/gui2-fw-lib/src/public_api.ts
+++ b/web/gui2-fw-lib/projects/gui2-fw-lib/src/public_api.ts
@@ -49,6 +49,7 @@
export * from './lib/layer/veil/veil.component';
export * from './lib/layer/flash/flash.component';
export * from './lib/layer/confirm/confirm.component';
+export * from './lib/layer/quickhelp/quickhelp.component';
export * from './lib/svg/icon/icon.component';
export * from './lib/widget/tableresize.directive';
diff --git a/web/gui2-fw-lib/src/app/app.component.html b/web/gui2-fw-lib/src/app/app.component.html
index 26f2562..f8d881f 100644
--- a/web/gui2-fw-lib/src/app/app.component.html
+++ b/web/gui2-fw-lib/src/app/app.component.html
@@ -44,3 +44,4 @@
If you change anything in the library, you will have to build it again before
it is picked up in this app.
</p>
+<onos-quickhelp></onos-quickhelp>
diff --git a/web/gui2-fw-lib/src/app/app.module.ts b/web/gui2-fw-lib/src/app/app.module.ts
index d2d4a5d..1d243f5 100644
--- a/web/gui2-fw-lib/src/app/app.module.ts
+++ b/web/gui2-fw-lib/src/app/app.module.ts
@@ -19,6 +19,8 @@
import { RouterModule, Routes } from '@angular/router';
import { AppComponent } from './app.component';
import { Gui2FwLibModule, ConsoleLoggerService, LogService } from 'gui2-fw-lib';
+import {HttpClientModule} from "@angular/common/http";
+import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
const appRoutes: Routes = [
{ path: '**', component: AppComponent }
@@ -31,6 +33,8 @@
imports: [
RouterModule.forRoot(appRoutes),
BrowserModule,
+ BrowserAnimationsModule,
+ HttpClientModule,
Gui2FwLibModule
],
providers: [
diff --git a/web/gui2/BUILD b/web/gui2/BUILD
index 54ac6e8..607f955 100644
--- a/web/gui2/BUILD
+++ b/web/gui2/BUILD
@@ -37,10 +37,11 @@
the build is still hermetic since those files are referred to as dependencies in the genrule.
"""
-COMPILE_DEPS = CORE_DEPS + JACKSON + KRYO + [
+COMPILE_DEPS = CORE_DEPS + JACKSON + KRYO + CLI + [
"@javax_ws_rs_api//jar",
"@servlet_api//jar",
"@jetty_websocket//jar",
+ "@jetty_websocket_api//jar",
"@jetty_util//jar",
"@jersey_media_multipart//jar",
"@jersey_server//jar",
@@ -318,6 +319,14 @@
]) + [
"//web/gui:onos-gui-java-for-gui2",
],
+ exclude_tests = [
+ "org.onosproject.ui.impl.AbstractUiImplTest",
+ "org.onosproject.ui.impl.topo.model.AbstractTopoModelTest",
+ ],
+ karaf_command_packages = [
+ "org.onosproject.ui.impl.cli",
+ "org.onosproject.ui.impl.topo",
+ ],
suppress_checkstyle = True,
test_deps = TEST_DEPS,
web_context = "/onos/ui2",
@@ -334,6 +343,7 @@
":_onos-gui2-ng-build",
":_onos-gui2-base-jar",
":_web_inf_classes_files",
+ "//web/gui:onos-gui-lion-for-gui2",
"src/main/webapp/WEB-INF/web.xml",
],
outs = ["onos-gui2.jar"],
@@ -344,8 +354,11 @@
" for i in $(locations :_web_inf_classes_files); do cp $$ROOT/$$i ./WEB-INF/classes/; done &&" +
" (cd WEB-INF/classes && jar xf $$ROOT/$${BUILD_FILES[1]}) &&" +
" jar xf $$ROOT/$(location :_onos-gui2-base-jar) &&" +
- " find . -type f -exec touch -t 201808280000 {} \; &&" +
- " jar cmf META-INF/MANIFEST.MF $$ROOT/$@ WEB-INF/web.xml WEB-INF/classes",
+ " unzip -q $$ROOT/$(location //web/gui:onos-gui-lion-for-gui2) web/gui/src/main/resources/**/* &&" +
+ " mv web/gui/src/main/resources/org/onosproject/ui/lion* WEB-INF/classes/org/onosproject/ui/ &&" +
+ " mv web/gui/src/main/resources/core WEB-INF/classes/ &&" +
+ " find . -type f -exec touch -t 201901200000 {} \; &&" +
+ " jar cmf META-INF/MANIFEST.MF $$ROOT/$@ WEB-INF/web.xml WEB-INF/classes OSGI-INF/*.xml",
output_to_bindir = 1,
visibility = ["//visibility:public"],
)
diff --git a/web/gui2/README.md b/web/gui2/README.md
index 50f5077..3996c95 100644
--- a/web/gui2/README.md
+++ b/web/gui2/README.md
@@ -16,7 +16,7 @@
As usual with ONOS if you want to run it in a different language set the __ONOS_LOCALE__ environment variable
to the locale you want before starting onos. e.g.
```
-ONOS_LOCALE=fr_FR SHLVL=1 bazel run onos-local
+ONOS_LOCALE=fr_FR SHLVL=1 bazel run onos-local -- clean debug
```
# Development
diff --git a/web/gui2/package-lock.json b/web/gui2/package-lock.json
index 81356c1..2645a24 100644
--- a/web/gui2/package-lock.json
+++ b/web/gui2/package-lock.json
@@ -364,7 +364,7 @@
"requires": {
"anymatch": "1.3.2",
"async-each": "1.0.1",
- "fsevents": "1.2.4",
+ "fsevents": "1.2.7",
"glob-parent": "2.0.0",
"inherits": "2.0.3",
"is-binary-path": "1.0.1",
@@ -2567,7 +2567,7 @@
"anymatch": "2.0.0",
"async-each": "1.0.1",
"braces": "2.3.2",
- "fsevents": "1.2.4",
+ "fsevents": "1.2.7",
"glob-parent": "3.1.0",
"inherits": "2.0.3",
"is-binary-path": "1.0.1",
@@ -4838,14 +4838,14 @@
"dev": true
},
"fsevents": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz",
- "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==",
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz",
+ "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==",
"dev": true,
"optional": true,
"requires": {
"nan": "2.11.1",
- "node-pre-gyp": "0.10.0"
+ "node-pre-gyp": "0.10.3"
},
"dependencies": {
"abbrev": {
@@ -4866,7 +4866,7 @@
"optional": true
},
"are-we-there-yet": {
- "version": "1.1.4",
+ "version": "1.1.5",
"bundled": true,
"dev": true,
"optional": true,
@@ -4890,7 +4890,7 @@
}
},
"chownr": {
- "version": "1.0.1",
+ "version": "1.1.1",
"bundled": true,
"dev": true,
"optional": true
@@ -4926,7 +4926,7 @@
}
},
"deep-extend": {
- "version": "0.5.1",
+ "version": "0.6.0",
"bundled": true,
"dev": true,
"optional": true
@@ -4949,7 +4949,7 @@
"dev": true,
"optional": true,
"requires": {
- "minipass": "2.2.4"
+ "minipass": "2.3.5"
}
},
"fs.realpath": {
@@ -4971,11 +4971,11 @@
"signal-exit": "3.0.2",
"string-width": "1.0.2",
"strip-ansi": "3.0.1",
- "wide-align": "1.1.2"
+ "wide-align": "1.1.3"
}
},
"glob": {
- "version": "7.1.2",
+ "version": "7.1.3",
"bundled": true,
"dev": true,
"optional": true,
@@ -4995,7 +4995,7 @@
"optional": true
},
"iconv-lite": {
- "version": "0.4.21",
+ "version": "0.4.24",
"bundled": true,
"dev": true,
"optional": true,
@@ -5061,21 +5061,21 @@
"dev": true
},
"minipass": {
- "version": "2.2.4",
+ "version": "2.3.5",
"bundled": true,
"dev": true,
"requires": {
- "safe-buffer": "5.1.1",
- "yallist": "3.0.2"
+ "safe-buffer": "5.1.2",
+ "yallist": "3.0.3"
}
},
"minizlib": {
- "version": "1.1.0",
+ "version": "1.2.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
- "minipass": "2.2.4"
+ "minipass": "2.3.5"
}
},
"mkdirp": {
@@ -5093,32 +5093,32 @@
"optional": true
},
"needle": {
- "version": "2.2.0",
+ "version": "2.2.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"debug": "2.6.9",
- "iconv-lite": "0.4.21",
+ "iconv-lite": "0.4.24",
"sax": "1.2.4"
}
},
"node-pre-gyp": {
- "version": "0.10.0",
+ "version": "0.10.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"detect-libc": "1.0.3",
"mkdirp": "0.5.1",
- "needle": "2.2.0",
+ "needle": "2.2.4",
"nopt": "4.0.1",
- "npm-packlist": "1.1.10",
+ "npm-packlist": "1.2.0",
"npmlog": "4.1.2",
- "rc": "1.2.7",
- "rimraf": "2.6.2",
- "semver": "5.5.0",
- "tar": "4.4.1"
+ "rc": "1.2.8",
+ "rimraf": "2.6.3",
+ "semver": "5.6.0",
+ "tar": "4.4.8"
}
},
"nopt": {
@@ -5132,19 +5132,19 @@
}
},
"npm-bundled": {
- "version": "1.0.3",
+ "version": "1.0.5",
"bundled": true,
"dev": true,
"optional": true
},
"npm-packlist": {
- "version": "1.1.10",
+ "version": "1.2.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ignore-walk": "3.0.1",
- "npm-bundled": "1.0.3"
+ "npm-bundled": "1.0.5"
}
},
"npmlog": {
@@ -5153,7 +5153,7 @@
"dev": true,
"optional": true,
"requires": {
- "are-we-there-yet": "1.1.4",
+ "are-we-there-yet": "1.1.5",
"console-control-strings": "1.1.0",
"gauge": "2.7.4",
"set-blocking": "2.0.0"
@@ -5213,12 +5213,12 @@
"optional": true
},
"rc": {
- "version": "1.2.7",
+ "version": "1.2.8",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
- "deep-extend": "0.5.1",
+ "deep-extend": "0.6.0",
"ini": "1.3.5",
"minimist": "1.2.0",
"strip-json-comments": "2.0.1"
@@ -5242,22 +5242,22 @@
"inherits": "2.0.3",
"isarray": "1.0.0",
"process-nextick-args": "2.0.0",
- "safe-buffer": "5.1.1",
+ "safe-buffer": "5.1.2",
"string_decoder": "1.1.1",
"util-deprecate": "1.0.2"
}
},
"rimraf": {
- "version": "2.6.2",
+ "version": "2.6.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
- "glob": "7.1.2"
+ "glob": "7.1.3"
}
},
"safe-buffer": {
- "version": "5.1.1",
+ "version": "5.1.2",
"bundled": true,
"dev": true
},
@@ -5274,7 +5274,7 @@
"optional": true
},
"semver": {
- "version": "5.5.0",
+ "version": "5.6.0",
"bundled": true,
"dev": true,
"optional": true
@@ -5307,7 +5307,7 @@
"dev": true,
"optional": true,
"requires": {
- "safe-buffer": "5.1.1"
+ "safe-buffer": "5.1.2"
}
},
"strip-ansi": {
@@ -5325,18 +5325,18 @@
"optional": true
},
"tar": {
- "version": "4.4.1",
+ "version": "4.4.8",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
- "chownr": "1.0.1",
+ "chownr": "1.1.1",
"fs-minipass": "1.2.5",
- "minipass": "2.2.4",
- "minizlib": "1.1.0",
+ "minipass": "2.3.5",
+ "minizlib": "1.2.1",
"mkdirp": "0.5.1",
- "safe-buffer": "5.1.1",
- "yallist": "3.0.2"
+ "safe-buffer": "5.1.2",
+ "yallist": "3.0.3"
}
},
"util-deprecate": {
@@ -5346,7 +5346,7 @@
"optional": true
},
"wide-align": {
- "version": "1.1.2",
+ "version": "1.1.3",
"bundled": true,
"dev": true,
"optional": true,
@@ -5360,7 +5360,7 @@
"dev": true
},
"yallist": {
- "version": "3.0.2",
+ "version": "3.0.3",
"bundled": true,
"dev": true
}
@@ -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-DRtcy4kDWJxMllozKJpiS4H820mxXmP01bU91qb5sYa/0HjiuihlOiJhvF4Kyg4hUfISNF+bhDeFwr3UgI5xtA==",
+ "integrity": "sha512-vHBnAneVQg76r7k3oY0oW2iLatWXLVmr2ei4I00qM73V7Z8hqkeIyRtOtW2PCbpjtiuPT6q8ObXvkDr23bjZVA==",
"requires": {
"tslib": "1.9.3"
}
@@ -7119,7 +7119,7 @@
"requires": {
"anymatch": "1.3.2",
"async-each": "1.0.1",
- "fsevents": "1.2.4",
+ "fsevents": "1.2.7",
"glob-parent": "2.0.0",
"inherits": "2.0.3",
"is-binary-path": "1.0.1",
@@ -7464,7 +7464,7 @@
"requires": {
"anymatch": "1.3.2",
"async-each": "1.0.1",
- "fsevents": "1.2.4",
+ "fsevents": "1.2.7",
"glob-parent": "2.0.0",
"inherits": "2.0.3",
"is-binary-path": "1.0.1",
diff --git a/web/gui2/src/main/webapp/WEB-INF/web.xml b/web/gui2/src/main/webapp/WEB-INF/web.xml
index 3eda814..5ac6e2f 100644
--- a/web/gui2/src/main/webapp/WEB-INF/web.xml
+++ b/web/gui2/src/main/webapp/WEB-INF/web.xml
@@ -147,7 +147,7 @@
<param-value>
org.glassfish.jersey.media.multipart.MultiPartFeature,
org.onosproject.ui.impl.gui2.LogoutResource,
- <!--org.onosproject.ui.impl.TopologyResource,-->
+ org.onosproject.ui.impl.TopologyResource,
org.onosproject.ui.impl.ApplicationResource,
org.onosproject.ui.impl.gui2.NavResource
</param-value>
@@ -160,16 +160,15 @@
<url-pattern>/rs/*</url-pattern>
</servlet-mapping>
- <!--<servlet>-->
- <!--<servlet-name>Web Socket Service</servlet-name>-->
- <!--<servlet-class>org.onosproject.ui.impl.UiWebSocketServlet-->
- <!--</servlet-class>-->
- <!--<load-on-startup>2</load-on-startup>-->
- <!--</servlet>-->
+ <servlet>
+ <servlet-name>Web Socket Service</servlet-name>
+ <servlet-class>org.onosproject.ui.impl.UiWebSocketServlet</servlet-class>
+ <load-on-startup>2</load-on-startup>
+ </servlet>
- <!--<servlet-mapping>-->
- <!--<servlet-name>Web Socket Service</servlet-name>-->
- <!--<url-pattern>/websock/*</url-pattern>-->
- <!--</servlet-mapping>-->
+ <servlet-mapping>
+ <servlet-name>Web Socket Service</servlet-name>
+ <url-pattern>/websock/*</url-pattern>
+ </servlet-mapping>
</web-app>
diff --git a/web/gui2/src/main/webapp/app/onos.component.html b/web/gui2/src/main/webapp/app/onos.component.html
index 0fedcca..029d524 100644
--- a/web/gui2/src/main/webapp/app/onos.component.html
+++ b/web/gui2/src/main/webapp/app/onos.component.html
@@ -14,7 +14,7 @@
~ limitations under the License.
-->
<div id="view" onosDetectBrowser>
- <onos-mast username="onos"></onos-mast>
+ <onos-mast [username]="onos.username"></onos-mast>
<onos-nav></onos-nav>
<onos-veil #veil></onos-veil>
<div>{{ wss.setVeilDelegate(veil) }}</div>
diff --git a/web/gui2/src/main/webapp/app/onos.component.ts b/web/gui2/src/main/webapp/app/onos.component.ts
index 0fe1346..909b74b 100644
--- a/web/gui2/src/main/webapp/app/onos.component.ts
+++ b/web/gui2/src/main/webapp/app/onos.component.ts
@@ -84,7 +84,7 @@
private ks: KeysService,
public wss: WebSocketService,
private log: LogService,
- private onos: OnosService
+ public onos: OnosService
) {
// This is not like onos.js of AngularJS 1.x In this new structure modules are
diff --git a/web/gui2/src/main/webapp/app/onos.service.spec.ts b/web/gui2/src/main/webapp/app/onos.service.spec.ts
index 073dfa7..c9dfdb3 100644
--- a/web/gui2/src/main/webapp/app/onos.service.spec.ts
+++ b/web/gui2/src/main/webapp/app/onos.service.spec.ts
@@ -23,13 +23,26 @@
*/
describe('OnosService', () => {
let log: LogService;
+ let windowMock: Window;
beforeEach(() => {
log = new ConsoleLoggerService();
+ windowMock = <any>{
+ location: <any> {
+ hostname: 'foo',
+ host: 'foo',
+ port: '80',
+ protocol: 'http',
+ search: { debug: 'true'},
+ href: 'ws://foo:123/onos/ui2/websock/path',
+ absUrl: 'ws://foo:123/onos/ui2/websock/path'
+ }
+ };
TestBed.configureTestingModule({
providers: [OnosService,
{ provide: LogService, useValue: log },
+ { provide: 'Window', useFactory: (() => windowMock ) },
]
});
});
diff --git a/web/gui2/src/main/webapp/app/onos.service.ts b/web/gui2/src/main/webapp/app/onos.service.ts
index b13129b..2cfe008 100644
--- a/web/gui2/src/main/webapp/app/onos.service.ts
+++ b/web/gui2/src/main/webapp/app/onos.service.ts
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Injectable } from '@angular/core';
+import {Inject, Injectable} from '@angular/core';
import { LogService } from 'gui2-fw-lib';
/**
@@ -35,10 +35,14 @@
public browser: string;
public mobile: boolean;
public viewMap: View[];
+ public username: string;
constructor (
- private log: LogService
+ private log: LogService,
+ @Inject('Window') private window: any
) {
+ // The onosUser is added to the index.html by MainIndexResource
+ this.username = this.window['onosUser'];
this.log.debug('OnosService constructed');
}
}
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 c4930c1..517c3e7 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
@@ -47,7 +47,8 @@
<svg:g onos-devicenodesvg [device]="device"
*ngFor="let device of regionData.devices[visibleLayerIdx()]"
onosDraggableNode [draggableNode]="device" [draggableInGraph]="graph"
- (selectedEvent)="updateSelected($event)">
+ (selectedEvent)="updateSelected($event)"
+ [labelToggle]="deviceLabelToggle">
<svg:desc>Device nodes</svg:desc>
</svg:g>
<!-- Template explanation - only display the hosts if 'showHosts' is set true -->
@@ -67,7 +68,8 @@
<svg:g onos-hostnodesvg [host]="host"
*ngFor="let host of regionData.hosts[visibleLayerIdx()]"
onosDraggableNode [draggableNode]="host" [draggableInGraph]="graph"
- (selectedEvent)="updateSelected($event)">
+ (selectedEvent)="updateSelected($event)"
+ [labelToggle]="hostLabelToggle">
<svg:desc>Host nodes</svg:desc>
</svg:g>
</svg:g>
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 b0b4a0c..d2a0b18 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
@@ -51,7 +51,6 @@
LinkSvgComponent
} from './visuals';
-
/**
* ONOS GUI -- Topology Forces Graph Layer View.
*
@@ -65,16 +64,16 @@
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ForceSvgComponent implements OnInit, OnChanges {
- @Input() onosInstMastership: string = '';
- @Input() visibleLayer: LayerType = LayerType.LAYER_DEFAULT;
- @Output() linkSelected = new EventEmitter<RegionLink>();
- @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() showHosts: boolean = false;
+ @Input() highlightPorts: boolean = true;
+ @Input() onosInstMastership: string = '';
+ @Input() visibleLayer: LayerType = LayerType.LAYER_DEFAULT;
+ @Input() selectedLink: RegionLink = null;
@Input() regionData: Region = <Region>{devices: [ [], [], [] ], hosts: [ [], [], [] ], links: []};
+ @Output() linkSelected = new EventEmitter<RegionLink>();
+ @Output() selectedNodeEvent = new EventEmitter<UiElement>();
private graph: ForceDirectedGraph;
private _options: { width, height } = { width: 800, height: 600 };
@@ -198,30 +197,6 @@
this.graph.nodes.length, 'nodes,', this.graph.links.length, 'links');
}
- if (changes['showHosts']) {
- 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;
- this.devices.forEach((d) => {
- d.ngOnChanges({'labelToggle': changes['deviceLabelToggle']});
- });
- }
-
- // Pass on the changes to host
- if (changes['hostLabelToggle']) {
- this.hostLabelToggle = changes['hostLabelToggle'].currentValue;
- this.hosts.forEach((h) => {
- h.ngOnChanges({'labelToggle': changes['hostLabelToggle']});
- });
- }
-
this.ref.markForCheck();
}
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 08ccaec..884d9ce 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
@@ -21,8 +21,8 @@
line 3) Merge this blurred and shifted layer and overlay it with the
original target object
-->
- <svg:filter id="drop-shadow">
- <svg:feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur" />
+ <svg:filter id="drop-shadow" x="-25%" y="-25%" width="200%" height="200%">
+ <svg:feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur" />
<svg:feOffset in="blur" dx="4" dy="4" result="offsetBlur"/>
<svg:feMerge >
<svg:feMergeNode in="offsetBlur" />
@@ -30,8 +30,8 @@
</svg:feMerge>
</svg:filter>
<svg:linearGradient id="diagonal_blue" x1="0%" y1="0%" x2="100%" y2="100%">
- <svg:stop offset= "0%" style="stop-color: #5b99d2;" />
- <svg:stop offset= "100%" style="stop-color: #3b79b2;" />
+ <svg:stop offset= "0%" style="stop-color: #7fabdb;" />
+ <svg:stop offset= "100%" style="stop-color: #5b99d2;" />
</svg:linearGradient>
</svg:defs>
<!-- Template explanation: Creates an SVG Group and in
@@ -57,7 +57,7 @@
<svg:rect
class="node-container" x="-18" y="-18"
width="36" height="36"
- [@deviceLabelToggle]="{ value: labelToggle, params: {txtWidth: (36 + labelTextLen() * 1.05)+'px' }}"
+ [@deviceLabelToggle]="{ value: labelToggle, params: {txtWidth: (36 + labelTextLen() * 1.1)+'px' }}"
filter= "url(#drop-shadow)">
</svg:rect>
<!-- Template explanation: Creates an SVG Rectangle slightly smaller and
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.ts b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.ts
index 756769d..9a8afc5 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/devicenodesvg/devicenodesvg.component.ts
@@ -90,9 +90,6 @@
this.device.y = 0;
}
}
- if (changes['labelToggle']) {
- this.labelToggle = changes['labelToggle'].currentValue;
- }
this.ref.markForCheck();
}
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/hostnodesvg/hostnodesvg.component.html b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/hostnodesvg/hostnodesvg.component.html
index 728a8ce..5bab75d 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/hostnodesvg/hostnodesvg.component.html
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/hostnodesvg/hostnodesvg.component.html
@@ -21,9 +21,9 @@
line 3) Merge this blurred and shifted layer and overlay it with the
original target object
-->
- <svg:filter id="drop-shadow-host">
- <svg:feGaussianBlur in="SourceAlpha" stdDeviation="1" result="blur" />
- <svg:feOffset in="blur" dx="2" dy="2" result="offsetBlur"/>
+ <svg:filter id="drop-shadow-host" x="-25%" y="-25%" width="200%" height="200%">
+ <svg:feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur" />
+ <svg:feOffset in="blur" dx="4" dy="4" result="offsetBlur"/>
<svg:feMerge >
<svg:feMergeNode in="offsetBlur" />
<svg:feMergeNode in="SourceGraphic" />
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/hostnodesvg/hostnodesvg.component.ts b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/hostnodesvg/hostnodesvg.component.ts
index 0720d0e..fc55271 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/hostnodesvg/hostnodesvg.component.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/visuals/hostnodesvg/hostnodesvg.component.ts
@@ -53,11 +53,6 @@
this.host.x = 0;
this.host.y = 0;
}
-
- if (changes['labelToggle']) {
- this.labelToggle = changes['labelToggle'].currentValue;
- }
- // this.ref.markForCheck();
}
hostName(): string {
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 9ddfe17..05402c8 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
@@ -17,8 +17,16 @@
#topo2-p-detail {
padding: 16px;
- top: 370px;
+ opacity: 1;
+ right: 20px;
+ width: 260px;
+ top: 390px;
}
+
+#topo2-p-detail div.actionBtns {
+ padding-top: 6px;
+}
+
html[data-platform='iPad'] {
top: 386px;
}
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 405fdfc..ca23ca1 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">
+ [@detailsPanelState]="on && selectedNode !== undefined">
<!-- Template explanation - Create a HTML header which has an SVG icon along
side title text. -->
<div class="header">
@@ -53,15 +53,13 @@
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>
+ <onos-icon id="topo2-p-detail-core-{{ btn }}"
+ (click)="navto(buttonAttribs(btn).path, showDetails.navPath, showDetails.id)"
+ [iconSize]="25"
+ [iconId]="buttonAttribs(btn).gid"
+ [toolTip]="lionFn(buttonAttribs(btn).tt)"
+ classes="button icon selected">
+ </onos-icon>
</div>
</div>
</div>
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 f63d99a..ea1462c 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
@@ -110,6 +110,7 @@
})
export class DetailsComponent extends DetailsPanelBaseImpl implements OnInit, OnDestroy, OnChanges {
@Input() selectedNode: UiElement = undefined; // Populated when user selects node or link
+ @Input() on: boolean = false; // Override the parent class attribute
// deferred localization strings
lionFn; // Function
@@ -141,7 +142,6 @@
* is made
*/
ngOnInit(): void {
- this.on = false;
this.wss.bindHandlers(new Map<string, (data) => void>([
['showDetails', (data) => {
this.showDetails = data;
@@ -211,8 +211,6 @@
} else {
this.log.warn('Unexpected type for selected element', this.selectedNode);
}
- } else {
- this.log.warn('Unexpected change in Topo DetailsComponent');
}
}
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 b30c706..ac47cce 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
@@ -74,6 +74,7 @@
})
export class InstanceComponent extends PanelBaseImpl {
@Input() divTopPx: number = 100;
+ @Input() on: boolean = false; // Override the parent class attribute
@Output() mastershipEvent = new EventEmitter<string>();
public onosInstances: Array<Instance>;
protected mastership: string;
@@ -96,7 +97,6 @@
} else {
this.doLion();
}
- this.on = true;
this.log.debug('InstanceComponent constructed');
}
diff --git a/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.css b/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.css
index 894b815..b4bd37b 100644
--- a/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.css
+++ b/web/gui2/src/main/webapp/app/view/topology/panel/summary/summary.component.css
@@ -25,4 +25,12 @@
#topo2-p-summary td.label {
width: 50%;
+}
+
+#topo2-p div.header div.icon {
+ padding: 10px
+}
+
+#topo2-p-summary div.header h2 {
+ padding: 10px;
}
\ 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 a520c86..3a42a0b 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,7 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {Component, OnDestroy, OnInit, ViewEncapsulation} from '@angular/core';
+import {
+ Component,
+ Input,
+ 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';
@@ -28,9 +34,12 @@
export interface SummaryResponse {
title: string;
}
-/*
- ONOS GUI -- Topology Summary Module.
- Defines modeling of ONOS Summary Panel.
+/**
+ * ONOS GUI -- Topology Summary Module.
+ * Defines modeling of ONOS Summary Panel.
+ * Note: This component uses the d3 DOM building technique from the old GUI - this
+ * is not the Angular way of building components and should be avoided generally
+ * See DetailsPanelComponent for a better way of doing this kind of thing
*/
@Component({
selector: 'onos-summary',
@@ -57,6 +66,7 @@
]
})
export class SummaryComponent extends TopoPanelBaseImpl implements OnInit, OnDestroy {
+ @Input() on: boolean = false; // Override the parent class attribute
private handlers: string[] = [];
private resp: string = 'showSummary';
private summaryData: SummaryResponse;
@@ -70,7 +80,6 @@
) {
super(fs, ls, log, 'summary');
this.summaryData = <SummaryResponse>{};
- this.on = true;
this.log.debug('SummaryComponent constructed');
}
@@ -82,7 +91,6 @@
this.handlers.push(this.resp);
this.init(d3.select('#topo2-p-summary'));
- this.on = true;
this.wss.sendEvent('requestSummary', {});
}
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 693e1b5..18f9687 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
@@ -63,5 +63,9 @@
<onos-icon [iconSize]="25" iconId="m_allTraffic" [toolTip]="lionFn('tr_btn_show_related_traffic')" classes="radioButton selected"></onos-icon>
</div>
</div>
+ <div class="separator"></div>
+ <div class="button" id="toolbar-topo2-toolbar-topo2-quickhelp" (click)="buttonClicked('quickhelp-btn')">
+ <onos-icon [iconSize]="25" iconId="query" [toolTip]="lionFn('qh_title')" classes="button"></onos-icon>
+ </div>
</div>
</div>
\ No newline at end of file
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 1ec3dbb..f781364 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
@@ -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,8 +20,25 @@
FnService,
PanelBaseImpl, LionService
} from 'gui2-fw-lib';
+
import {animate, state, style, transition, trigger} from '@angular/animations';
+export const INSTANCE_TOGGLE = 'instance-tog';
+export const SUMMARY_TOGGLE = 'summary-tog';
+export const DETAILS_TOGGLE = 'details-tog';
+export const HOSTS_TOGGLE = 'hosts-tog';
+export const OFFLINE_TOGGLE = 'offline-tog';
+export const PORTS_TOGGLE = 'ports-tog';
+export const BKGRND_TOGGLE = 'bkgrnd-tog';
+export const CYCLELABELS_BTN = 'cycleLabels-btn';
+export const CYCLEHOSTLABEL_BTN = 'cycleHostLabel-btn';
+export const RESETZOOM_BTN = 'resetZoom-btn';
+export const EQMASTER_BTN = 'eqMaster-btn';
+export const CANCEL_TRAFFIC = 'cancel-traffic';
+export const ALL_TRAFFIC = 'all-traffic';
+export const QUICKHELP_BTN = 'quickhelp-btn';
+
+
/*
ONOS GUI -- Topology Toolbar Module.
Defines modeling of ONOS toolbar.
@@ -50,7 +67,8 @@
])
]
})
-export class ToolbarComponent extends PanelBaseImpl implements OnInit {
+export class ToolbarComponent extends PanelBaseImpl {
+ @Input() on: boolean = false; // Override the parent class attribute
// deferred localization strings
lionFn; // Function
// Used to drive the display of the hosts icon - there is also another such variable on the forcesvg
@@ -70,7 +88,6 @@
private lion: LionService
) {
super(fs, ls, log);
- this.on = false;
if (this.lion.ubercache.length === 0) {
this.lionFn = this.dummyLion;
@@ -82,9 +99,6 @@
this.log.debug('ToolbarComponent constructed');
}
- ngOnInit() {
- }
-
/**
* Read the LION bundle for Toolbar and set up the lionFn
*/
@@ -103,23 +117,22 @@
*/
buttonClicked(name: string): void {
switch (name) {
- case 'hosts-tog':
+ case HOSTS_TOGGLE:
this.hostsVisible = !this.hostsVisible;
break;
- case 'instance-tog':
+ case INSTANCE_TOGGLE:
this.instancesVisible = !this.instancesVisible;
break;
- case 'summary-tog':
+ case SUMMARY_TOGGLE:
this.summaryVisible = !this.summaryVisible;
break;
- case 'details-tog':
+ case DETAILS_TOGGLE:
this.detailsVisible = !this.detailsVisible;
break;
- case 'bkgrnd-tog':
+ case BKGRND_TOGGLE:
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/topology.common.css b/web/gui2/src/main/webapp/app/view/topology/topology.common.css
index 41b7851..1ad9fbe 100644
--- a/web/gui2/src/main/webapp/app/view/topology/topology.common.css
+++ b/web/gui2/src/main/webapp/app/view/topology/topology.common.css
@@ -79,10 +79,6 @@
width: 50%;
}
-#topo2-p-detail div.actionBtns {
- padding-top: 6px;
-}
-
.topo2-p hr {
height: 1px;
border: 0;
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 6fe0cb1..4b66bd6 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
@@ -18,13 +18,26 @@
-->
<onos-flash id="topoMsgFlash" message="{{ flashMsg }}" (closed)="flashMsg = ''"></onos-flash>
+<onos-quickhelp id="topoQuickHelp"></onos-quickhelp>
<!-- 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 (buttonEvent)="toolbarButtonClicked($event)"></onos-toolbar>
-<onos-details #details></onos-details>
+<onos-instance #instance [divTopPx]="80"
+ (mastershipEvent)="force.onosInstMastership = $event"
+ [on]="prefsState.insts">
+</onos-instance>
+<onos-summary #summary [on]="prefsState.summary"></onos-summary>
+<onos-toolbar #toolbar
+ (buttonEvent)="toolbarButtonClicked($event)"
+ [on]="prefsState.toolbar"
+ [backgroundVisible]="prefsState.bg"
+ [detailsVisible]="prefsState.detail"
+ [hostsVisible]="prefsState.hosts"
+ [instancesVisible]="prefsState.insts"
+ [portsVisible]="prefsState.porthl"
+ [summaryVisible]="prefsState.summary">
+</onos-toolbar>
+<onos-details #details [on]="prefsState.detail"></onos-details>
<div id="ov-topo2">
<!-- Template explanation -
@@ -49,8 +62,17 @@
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 *ngIf="prefsState.bg" onos-backgroundsvg>
+ <svg:desc>The Background SVG component - contains maps</svg:desc>
+ </svg:g>
+ <svg:g #force onos-forcesvg
+ [deviceLabelToggle]="prefsState.dlbls"
+ [hostLabelToggle]="prefsState.hlbls"
+ [showHosts]="prefsState.hosts"
+ [highlightPorts]="prefsState.porthl"
+ (selectedNodeEvent)="nodeSelected($event)">
+ <svg:desc>The Force SVG component - contains all the devices, hosts and links</svg:desc>
+ </svg:g>
</svg:g>
</svg:svg>
</div>
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 23fb257..446d41c 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
@@ -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.
@@ -31,12 +31,20 @@
import {
FlashComponent,
+ QuickhelpComponent,
FnService,
LogService,
- IconService, IconComponent
+ IconService, IconComponent, PrefsService, KeysService, LionService
} from 'gui2-fw-lib';
import {ZoomableDirective} from '../layer/zoomable.directive';
import {RouterTestingModule} from '@angular/router/testing';
+import {TrafficService} from '../traffic.service';
+import {ForceSvgComponent} from '../layer/forcesvg/forcesvg.component';
+import {
+ DeviceNodeSvgComponent, HostNodeSvgComponent,
+ LinkSvgComponent, SubRegionNodeSvgComponent
+} from '../layer/forcesvg/visuals';
+import {DraggableDirective} from '../layer/forcesvg/draggable/draggable.directive';
class MockActivatedRoute extends ActivatedRoute {
@@ -78,6 +86,37 @@
loadIconDef() { }
}
+class MockKeysService {
+ quickHelpShown: boolean = true;
+
+ keyBindings(x) {
+ return {};
+ }
+
+ gestureNotes() {
+ return {};
+ }
+}
+
+class MockTrafficService {}
+
+class MockPrefsService {
+ listeners: ((data) => void)[] = [];
+
+ getPrefs() {
+ return { 'topo2_prefs': ''};
+ }
+
+ addListener(listener: (data) => void): void {
+ this.listeners.push(listener);
+ }
+
+ removeListener(listener: (data) => void) {
+ this.listeners = this.listeners.filter((obj) => obj !== listener);
+ }
+
+}
+
/**
* ONOS GUI -- Topology View -- Unit Tests
*/
@@ -89,6 +128,16 @@
let component: TopologyComponent;
let fixture: ComponentFixture<TopologyComponent>;
+ const bundleObj = {
+ 'core.fw.QuickHelp': {
+ test: 'test1',
+ tt_help: 'Help!'
+ }
+ };
+ const mockLion = (key) => {
+ return bundleObj[key] || '%' + key + '%';
+ };
+
beforeEach(async(() => {
const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
ar = new MockActivatedRoute({ 'debug': 'txrx' });
@@ -116,7 +165,15 @@
DetailsComponent,
FlashComponent,
ZoomableDirective,
- IconComponent
+ IconComponent,
+ QuickhelpComponent,
+ ForceSvgComponent,
+ LinkSvgComponent,
+ DeviceNodeSvgComponent,
+ HostNodeSvgComponent,
+ DraggableDirective,
+ ZoomableDirective,
+ SubRegionNodeSvgComponent
],
providers: [
{ provide: FnService, useValue: fs },
@@ -124,7 +181,18 @@
{ provide: 'Window', useValue: windowMock },
{ provide: HttpClient, useClass: MockHttpClient },
{ provide: TopologyService, useClass: MockTopologyService },
+ { provide: TrafficService, useClass: MockTrafficService },
{ provide: IconService, useClass: MockIconService },
+ { provide: PrefsService, useClass: MockPrefsService },
+ { provide: KeysService, useClass: MockKeysService },
+ { provide: LionService, useFactory: (() => {
+ return {
+ bundle: ((bundleId) => mockLion),
+ ubercache: new Array(),
+ loadCbs: new Map<string, () => void>([])
+ };
+ })
+ },
]
}).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 3e1e1a6..ff8a050 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
@@ -31,7 +31,6 @@
ZoomService
} from 'gui2-fw-lib';
import {InstanceComponent} from '../panel/instance/instance.component';
-import {SummaryComponent} from '../panel/summary/summary.component';
import {DetailsComponent} from '../panel/details/details.component';
import {BackgroundSvgComponent} from '../layer/backgroundsvg/backgroundsvg.component';
import {ForceSvgComponent} from '../layer/forcesvg/forcesvg.component';
@@ -41,10 +40,47 @@
LabelToggle,
UiElement
} from '../layer/forcesvg/models';
-import {ToolbarComponent} from '../panel/toolbar/toolbar.component';
+import {
+ INSTANCE_TOGGLE, SUMMARY_TOGGLE, DETAILS_TOGGLE,
+ HOSTS_TOGGLE, OFFLINE_TOGGLE, PORTS_TOGGLE,
+ BKGRND_TOGGLE, CYCLELABELS_BTN, CYCLEHOSTLABEL_BTN,
+ RESETZOOM_BTN, EQMASTER_BTN,
+ CANCEL_TRAFFIC, ALL_TRAFFIC, QUICKHELP_BTN
+} from '../panel/toolbar/toolbar.component';
import {TrafficService} from '../traffic.service';
import {ZoomableDirective} from '../layer/zoomable.directive';
+const TOPO2_PREFS = 'topo2_prefs';
+const PREF_BG = 'bg';
+const PREF_DETAIL = 'detail';
+const PREF_DLBLS = 'dlbls';
+const PREF_HLBLS = 'hlbls';
+const PREF_HOSTS = 'hosts';
+const PREF_INSTS = 'insts';
+const PREF_OFFDEV = 'offdev';
+const PREF_PORTHL = 'porthl';
+const PREF_SUMMARY = 'summary';
+const PREF_TOOLBAR = 'toolbar';
+
+/**
+ * model of the topo2_prefs object - this is a subset of the overall Prefs returned
+ * by the server
+ */
+export interface Topo2Prefs {
+ bg: number;
+ detail: number;
+ dlbls: number;
+ hlbls: number;
+ hosts: number;
+ insts: number;
+ offdev: number;
+ porthl: number;
+ spr: number;
+ ovid: string;
+ summary: number;
+ toolbar: number;
+}
+
/**
* ONOS GUI Topology View
*
@@ -77,17 +113,27 @@
export class TopologyComponent implements OnInit, OnDestroy {
// These are references to the components inserted in the template
@ViewChild(InstanceComponent) instance: InstanceComponent;
- @ViewChild(SummaryComponent) summary: SummaryComponent;
@ViewChild(DetailsComponent) details: DetailsComponent;
- @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;
+ // These are used as defaults if nothing is set on the server
+ prefsState: Topo2Prefs = <Topo2Prefs>{
+ bg: 0,
+ detail: 1,
+ dlbls: 0,
+ hlbls: 2,
+ hosts: 0,
+ insts: 1,
+ offdev: 1,
+ ovid: 'traffic', // default to traffic overlay
+ porthl: 1,
+ spr: 0,
+ summary: 1,
+ toolbar: 0,
+ };
lionFn; // Function
constructor(
@@ -97,7 +143,6 @@
protected sus: SvgUtilService,
protected ps: PrefsService,
protected wss: WebSocketService,
- protected zs: ZoomService,
protected ts: TopologyService,
protected trs: TrafficService,
protected is: IconService,
@@ -169,15 +214,31 @@
// The handling of the WebSocket call is delegated out to the Topology
// Service just to compartmentalize things a bit
this.ts.init(this.instance, this.background, this.force);
+
+ this.ps.addListener((data) => this.prefsUpdateHandler(data));
+ this.prefsState = this.ps.getPrefs(TOPO2_PREFS, this.prefsState);
this.log.debug('Topology component initialized');
}
/**
+ * Callback function that's called whenever new Prefs are received from WebSocket
+ *
+ * Note: At present the backend server does not filter updated by logged in user,
+ * so you might get updates pertaining to a different user
+ */
+ prefsUpdateHandler(data: any): void {
+ // Extract the TOPO2 prefs from it
+ this.prefsState = data[TOPO2_PREFS];
+ this.log.debug('Updated topo2 prefs', this.prefsState);
+ }
+
+ /**
* When this component is being stopped, disconnect the TopologyService from
* the WebSocket
*/
ngOnDestroy() {
this.ts.destroy();
+ this.ps.removeListener((data) => this.prefsUpdateHandler(data));
this.log.debug('Topology component destroyed');
}
@@ -188,45 +249,48 @@
*/
toolbarButtonClicked(name: string) {
switch (name) {
- case 'instance-tog':
+ case INSTANCE_TOGGLE:
this.toggleInstancePanel();
break;
- case 'summary-tog':
+ case SUMMARY_TOGGLE:
this.toggleSummary();
break;
- case 'details-tog':
+ case DETAILS_TOGGLE:
this.toggleDetails();
break;
- case 'hosts-tog':
+ case HOSTS_TOGGLE:
this.toggleHosts();
break;
- case 'offline-tog':
+ case OFFLINE_TOGGLE:
this.toggleOfflineDevices();
break;
- case 'ports-tog':
+ case PORTS_TOGGLE:
this.togglePorts();
break;
- case 'bkgrnd-tog':
+ case BKGRND_TOGGLE:
this.toggleBackground();
break;
- case 'cycleLabels-btn':
+ case CYCLELABELS_BTN:
this.cycleDeviceLabels();
break;
- case 'cycleHostLabel-btn':
+ case CYCLEHOSTLABEL_BTN:
this.cycleHostLabels();
break;
- case 'resetZoom-btn':
+ case RESETZOOM_BTN:
this.resetZoom();
break;
- case 'eqMaster-btn':
+ case EQMASTER_BTN:
this.equalizeMasters();
break;
- case 'cancel-traffic':
+ case CANCEL_TRAFFIC:
this.cancelTraffic();
break;
- case 'all-traffic':
+ case ALL_TRAFFIC:
this.monitorAllTraffic();
break;
+ case QUICKHELP_BTN:
+ this.ks.quickHelpShown = true;
+ break;
default:
this.log.warn('Unhandled Toolbar action', name);
}
@@ -262,7 +326,7 @@
this.sus.cat7().testCard(d3.select('svg#topo2'));
},
- esc: this.handleEscape,
+ esc: [() => {this.handleEscape(); }, 'Cancel commands'],
// TODO update after adding in Background Service
// topology overlay selections
@@ -306,6 +370,7 @@
// TODO: Cancel Active overlay
// TODO: Reinstate with components
} else {
+ this.nodeSelected(undefined);
this.log.debug('Handling escape');
// } else if (t2rs.deselectAllNodes()) {
// // else if we have node selections, deselect them all
@@ -322,64 +387,111 @@
}
}
-
-
- updatePrefsState(what, b) {
- this.prefsState[what] = b ? 1 : 0;
- this.ps.setPrefs('topo2_prefs', this.prefsState);
+ /**
+ * Updates the cache of preferences locally and onwards to the PrefsService
+ * @param what The attribute of the local topo2-prefs cache to update
+ * @param b the value to update it with
+ */
+ updatePrefsState(what: string, b: number) {
+ this.prefsState[what] = b;
+ this.ps.setPrefs(TOPO2_PREFS, this.prefsState);
}
+ /**
+ * When the button is clicked on the toolbar or the L key is pressed
+ * 1) cycle through options
+ * 2) flash up a message
+ * 3a) Update the local prefs cache
+ * 3b) And passes on to the global prefs service which sends back to the server
+ * 3c) It also has a knock on effect of passing it on to ForceSvgComponent
+ * because prefsState.dlbls is given as an input to it
+ * 3d) This will in turn pass it down to the DeviceSvgComponent which
+ * displays the label
+ */
protected cycleDeviceLabels() {
- const old: LabelToggle = this.force.deviceLabelToggle;
+ const old: LabelToggle = this.prefsState.dlbls;
const next = LabelToggle.next(old);
- this.force.ngOnChanges({'deviceLabelToggle':
- new SimpleChange(old, next, false)});
this.flashMsg = this.lionFn(TopologyComponent.deviceLabelFlashMessage(next));
+ this.updatePrefsState(PREF_DLBLS, next);
this.log.debug('Cycling device labels', old, next);
}
protected cycleHostLabels() {
- const old: HostLabelToggle = this.force.hostLabelToggle;
+ const old: HostLabelToggle = this.prefsState.hlbls;
const next = HostLabelToggle.next(old);
- this.force.ngOnChanges({'hostLabelToggle':
- new SimpleChange(old, next, false)});
this.flashMsg = this.lionFn(TopologyComponent.hostLabelFlashMessage(next));
+ this.updatePrefsState(PREF_HLBLS, next);
this.log.debug('Cycling host labels', old, next);
}
+ /**
+ * When the button is clicked on the toolbar or the B key is pressed
+ * 1) Find the inverse of the current state (held as 1 or 0)
+ * 2) Flash up a message on screen
+ * 3b) And passes on to the global prefs service which sends back to the server
+ * 3c) It also has a knock on effect of passing it on to ToolbarComponent
+ * because prefsState.bg is given as an input to it
+ * @param token
+ */
protected toggleBackground(token?: KeysToken) {
- this.showBackground = !this.showBackground;
- this.flashMsg = this.lionFn(this.showBackground ? 'show' : 'hide') +
+ const bg: boolean = !Boolean(this.prefsState.bg);
+ this.flashMsg = this.lionFn(bg ? 'show' : 'hide') +
' ' + this.lionFn('fl_background_map');
- this.toolbar.backgroundVisible = this.showBackground;
- this.log.debug('Toggling background', token);
+ this.updatePrefsState(PREF_BG, bg ? 1 : 0);
+ this.log.debug('Toggling background', token, bg ? 'shown' : 'hidden');
}
protected toggleDetails(token?: KeysToken) {
- if (this.details.selectedNode) {
- 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);
- }
+ const on: boolean = !Boolean(this.prefsState.detail);
+ this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
+ ' ' + this.lionFn('fl_panel_details');
+ this.updatePrefsState(PREF_DETAIL, on ? 1 : 0);
+ this.log.debug('Toggling details', token);
}
protected toggleInstancePanel(token?: KeysToken) {
- const on: boolean = this.instance.togglePanel(() => {});
+ const on: boolean = !Boolean(this.prefsState.insts);
this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
' ' + this.lionFn('fl_panel_instances');
- this.toolbar.instancesVisible = on;
+ this.updatePrefsState(PREF_INSTS, on ? 1 : 0);
this.log.debug('Toggling instances', token, on);
}
protected toggleSummary() {
- const on: boolean = this.summary.togglePanel(() => {});
+ const on: boolean = !Boolean(this.prefsState.summary);
this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
' ' + this.lionFn('fl_panel_summary');
- this.toolbar.summaryVisible = on;
+ this.updatePrefsState(PREF_SUMMARY, on ? 1 : 0);
+ }
+
+ protected togglePorts(token?: KeysToken) {
+ const current: boolean = !Boolean(this.prefsState.porthl);
+ this.flashMsg = this.lionFn(current ? 'enable' : 'disable') +
+ ' ' + this.lionFn('fl_port_highlighting');
+ this.updatePrefsState(PREF_PORTHL, current ? 1 : 0);
+ this.log.debug(current ? 'Enable' : 'Disable', 'port highlighting');
+ }
+
+ protected toggleToolbar() {
+ const on: boolean = !Boolean(this.prefsState.toolbar);
+ this.updatePrefsState(PREF_TOOLBAR, on ? 1 : 0);
+ this.log.debug('toggling toolbar', on ? 'shown' : 'hidden');
+ }
+
+ protected toggleHosts() {
+ const current: boolean = !Boolean(this.prefsState.hosts);
+ this.flashMsg = this.lionFn('hosts') + ' ' +
+ this.lionFn(this.force.showHosts ? 'visible' : 'hidden');
+ this.updatePrefsState(PREF_HOSTS, current ? 1 : 0);
+ this.log.debug('toggling hosts: ', this.prefsState.hosts ? 'Show' : 'Hide');
+ }
+
+ protected toggleOfflineDevices() {
+ const on: boolean = !Boolean(this.prefsState.offdev);
+ this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
+ ' ' + this.lionFn('fl_offline_devices');
+ this.updatePrefsState(PREF_OFFDEV, on ? 1 : 0);
+ this.log.debug('toggling offline devices', this.prefsState.offdev);
}
protected resetZoom() {
@@ -387,16 +499,6 @@
this.flashMsg = this.lionFn('fl_pan_zoom_reset');
}
- 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');
@@ -414,29 +516,6 @@
this.log.debug('unpinning node');
}
- protected toggleToolbar() {
- this.log.debug('toggling toolbar');
- this.toolbar.on = !this.toolbar.on;
- }
-
- 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.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');
- }
-
/**
* Check to see if this is needed anymore
* @param what
@@ -474,7 +553,6 @@
nodeSelected(nodeOrLink: UiElement) {
this.details.ngOnChanges({'selectedNode':
new SimpleChange(undefined, nodeOrLink, true)});
- this.details.on = Boolean(nodeOrLink);
}
/**