Added native Bazel build to GUI2. Reduced a lot of the unused Angular CLI structures
Reviewers should look at the changes in WORKSPACE, BUILD, BUILD.bazel, README.md files
This is only possible now as rules_nodejs went to 1.0.0 on December 20
gui2 has now been made the entry point (rather than gui2-fw-lib)
No tests or linting are functional yet for Typescript
Each NgModule now has its own BUILD.bazel file with ng_module
gui2-fw-lib is all one module and has been refactored to simplify the directory structure
gui2-topo-lib is also all one module - its directory structure has had 3 layers removed
The big bash script in web/gui2/BUILD has been removed - all is done through ng_module rules
in web/gui2/src/main/webapp/BUILD.bazel and web/gui2/src/main/webapp/app/BUILD.bazel
Change-Id: Ifcfcc23a87be39fe6d6c8324046cc8ebadb90551
diff --git a/web/gui2-fw-lib/lib/layer/confirm/confirm.component.css b/web/gui2-fw-lib/lib/layer/confirm/confirm.component.css
new file mode 100644
index 0000000..b097534
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/confirm/confirm.component.css
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- Confirm Component (layout) -- CSS file
+ */
+#app-dialog {
+ top: 140px;
+ padding: 12px;
+}
+
+#app-dialog h3 {
+ display: inline-block;
+ font-weight: bold;
+ font-size: 18pt;
+}
+
+#app-dialog p {
+ font-size: 12pt;
+}
+
+#app-dialog p.strong {
+ font-weight: bold;
+ padding: 8px;
+ text-align: center;
+}
diff --git a/web/gui2-fw-lib/lib/layer/confirm/confirm.component.html b/web/gui2-fw-lib/lib/layer/confirm/confirm.component.html
new file mode 100644
index 0000000..098d83a
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/confirm/confirm.component.html
@@ -0,0 +1,22 @@
+<!--
+~ 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.
+-->
+<div id="app-dialog" class="floatpanel dialog" [@confirmDlgState]="message!==''">
+ <h3> {{ title }} </h3>
+ <p>{{ message }}</p>
+ <p *ngIf="warning" class="warning strong">{{ warning }}</p>
+ <div tabindex="10" class="dialog-button" (click)="choice(true)">OK</div>
+ <div tabindex="11" class="dialog-button" (click)="choice(false)">Cancel</div>
+</div>
diff --git a/web/gui2-fw-lib/lib/layer/confirm/confirm.component.spec.ts b/web/gui2-fw-lib/lib/layer/confirm/confirm.component.spec.ts
new file mode 100644
index 0000000..9692e3a
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/confirm/confirm.component.spec.ts
@@ -0,0 +1,90 @@
+/*
+ * 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 { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { DebugElement } from '@angular/core';
+import { By } from '@angular/platform-browser';
+import { LionService } from '../../util/lion.service';
+
+import { ConsoleLoggerService } from '../../consolelogger.service';
+import { LogService } from '../../log.service';
+import { ConfirmComponent } from './confirm.component';
+
+/**
+ * ONOS GUI -- Layer -- Confirm Component - Unit Tests
+ */
+describe('ConfirmComponent', () => {
+ let log: LogService;
+ let component: ConfirmComponent;
+ let fixture: ComponentFixture<ConfirmComponent>;
+ const bundleObj = {
+ 'core.view.App': {
+ test: 'test1',
+ dlg_confirm_action: 'Confirm'
+ }
+ };
+ const mockLion = (key) => {
+ return bundleObj[key] || '%' + key + '%';
+ };
+
+ beforeEach(async(() => {
+ log = new ConsoleLoggerService();
+ TestBed.configureTestingModule({
+ imports: [ BrowserAnimationsModule ],
+ declarations: [ ConfirmComponent ],
+ providers: [
+ { provide: LogService, useValue: log },
+ {
+ provide: LionService, useFactory: (() => {
+ return {
+ bundle: ((bundleId) => mockLion),
+ ubercache: new Array(),
+ loadCbs: new Map<string, () => void>([])
+ };
+ })
+ },
+ ]
+ });
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ConfirmComponent);
+ component = fixture.debugElement.componentInstance;
+ component.title = 'Confirm';
+ component.message = 'A message';
+ component.warning = 'A warning';
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should have a h3 inside a div#app-dialog', () => {
+ const appDe: DebugElement = fixture.debugElement;
+ const divDe = appDe.query(By.css('div#app-dialog h3'));
+ const div: HTMLElement = divDe.nativeElement;
+ expect(div.textContent).toEqual(' Confirm ');
+ });
+
+ it('should have a div.dialog-button inside a div#app-dialog', () => {
+ const appDe: DebugElement = fixture.debugElement;
+ const divDe = appDe.query(By.css('div#app-dialog div.dialog-button'));
+ const div: HTMLElement = divDe.nativeElement;
+ // It selects the first one
+ expect(div.textContent).toEqual('OK');
+ });
+});
diff --git a/web/gui2-fw-lib/lib/layer/confirm/confirm.component.ts b/web/gui2-fw-lib/lib/layer/confirm/confirm.component.ts
new file mode 100644
index 0000000..7533a7e
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/confirm/confirm.component.ts
@@ -0,0 +1,88 @@
+/*
+ * 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, Input, Output, EventEmitter } from '@angular/core';
+import { trigger, state, style, animate, transition } from '@angular/animations';
+import { LogService } from '../../log.service';
+import { LionService } from '../../util/lion.service';
+
+/**
+ * ONOS GUI -- Layer -- Confirm Component
+ *
+ * Replaces Flash Service in old GUI.
+ * Provides a mechanism to present a confirm dialog to the screen
+ *
+ * To use add an element to the template like
+ * <onos-confirm message="Performing something dangerous. Would you like to proceed"></onos-flash>
+ *
+ * An event is raised with either OK or Cancel
+ */
+@Component({
+ selector: 'onos-confirm',
+ templateUrl: './confirm.component.html',
+ styleUrls: [
+ './confirm.component.css',
+ './confirm.theme.css',
+ '../dialog.css',
+ '../dialog.theme.css',
+ '../../widget/panel.css',
+ '../../widget/panel-theme.css'
+ ],
+ animations: [
+ trigger('confirmDlgState', [
+ state('true', style({
+ transform: 'translateX(-100%)',
+ opacity: '100'
+ })),
+ state('false', style({
+ transform: 'translateX(0%)',
+ opacity: '0'
+ })),
+ transition('0 => 1', animate('100ms ease-in')),
+ transition('1 => 0', animate('100ms ease-out'))
+ ])
+ ]
+})
+export class ConfirmComponent {
+
+ lionFn; // Function
+
+ @Input() message: string;
+ @Input() warning: string;
+ @Input() title: string;
+ @Output() chosen: EventEmitter<boolean> = new EventEmitter();
+
+ constructor(
+ private log: LogService,
+ private lion: LionService,
+ ) {
+ this.log.debug('ConfirmComponent constructed');
+ this.doLion();
+ }
+
+ /**
+ * When OK or Cancel is pressed, send an event to parent with choice
+ */
+ choice(chosen: boolean): void {
+ this.chosen.emit(chosen);
+ }
+
+ /**
+ * Read the LION bundle for App to get confirm dialouge header
+ */
+ doLion() {
+ this.lionFn = this.lion.bundle('core.view.App');
+ }
+}
diff --git a/web/gui2-fw-lib/lib/layer/confirm/confirm.theme.css b/web/gui2-fw-lib/lib/layer/confirm/confirm.theme.css
new file mode 100644
index 0000000..db97648
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/confirm/confirm.theme.css
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- Confirm Component (theme) -- CSS file
+ */
+/* temporarily removed .light */
+#app-dialog p.strong {
+ color: white;
+ background-color: #ce5b58;
+}
+
+#app-dialog.floatpanel.dialog {
+ background-color: #ffffff;
+}
+
+#app-dialog p.strong {
+ color: white;
+ background-color: #ce5b58;
+}
diff --git a/web/gui2-fw-lib/lib/layer/dialog.css b/web/gui2-fw-lib/lib/layer/dialog.css
new file mode 100644
index 0000000..6792a3d
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/dialog.css
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- Dialog Service (layout) -- CSS file
+ */
+
+.dialog h2 {
+ margin: 0;
+ word-wrap: break-word;
+ display: inline-block;
+ width: 210px;
+ vertical-align: middle;
+}
+
+.dialog .dialog-button {
+ display: inline-block;
+ cursor: pointer;
+ height: 20px;
+ padding: 6px 8px 2px 8px;
+ margin: 4px;
+ float: right;
+}
diff --git a/web/gui2-fw-lib/lib/layer/dialog.theme.css b/web/gui2-fw-lib/lib/layer/dialog.theme.css
new file mode 100644
index 0000000..24cd5fa
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/dialog.theme.css
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- Dialog Service (theme) -- CSS file
+ */
+
+/* temporarily removed .light */
+.dialog .dialog-button {
+ background-color: #518ecc;
+ color: white;
+}
+
+
+/* ========== DARK Theme ========== */
+
+.dark .dialog .dialog-button {
+ background-color: #345e85;
+ color: #cccccd;
+}
diff --git a/web/gui2-fw-lib/lib/layer/flash/flash.component.css b/web/gui2-fw-lib/lib/layer/flash/flash.component.css
new file mode 100644
index 0000000..66b8f3b
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/flash/flash.component.css
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- Flash Component (layout) -- CSS file
+ */
+
+#flash {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ z-index: 1400;
+}
+
+#flash.warning div#flashBox {
+ border: 2px solid #222222;
+ border-radius: 10px;
+ background: #FFFFFF;
+ padding: 10px;
+}
+
+#flash div#flashBox {
+ background: #CCCCCC;
+ border-radius: 10px;
+ padding: 1px;
+}
+
+#flash div#flashBox div.dialog-button {
+ transform :translateY(-32px);
+}
+
+#flash.warning p#flashText {
+ stroke: #FF0000;
+ color: #FF0000;
+ text-anchor: middle;
+ alignment-baseline: middle;
+ text-align: center;
+ font-size: 16pt;
+ border-radius: 10px;
+ background: #FFFFFF;
+ padding: 10px;
+}
+
+#flash p#flashText {
+ stroke: none;
+ color: #222222;
+ text-anchor: middle;
+ alignment-baseline: middle;
+ text-align: center;
+ font-size: 16pt;
+ border-radius: 10px;
+ background: #CCCCCC;
+ padding: 5px;
+}
diff --git a/web/gui2-fw-lib/lib/layer/flash/flash.component.html b/web/gui2-fw-lib/lib/layer/flash/flash.component.html
new file mode 100644
index 0000000..46b6de9
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/flash/flash.component.html
@@ -0,0 +1,21 @@
+<!--
+~ 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.
+-->
+<div id="flash" class="dialog" [ngClass]="warning?'warning':''" [@flashState]="visible">
+ <div id="flashBox" *ngIf="visible">
+ <p id="flashText">{{ message }}</p>
+ <div class="dialog-button" *ngIf="dwell>1200" (click)="closeNow()">Dismiss</div>
+ </div>
+</div>
\ No newline at end of file
diff --git a/web/gui2-fw-lib/lib/layer/flash/flash.component.spec.ts b/web/gui2-fw-lib/lib/layer/flash/flash.component.spec.ts
new file mode 100644
index 0000000..661e223
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/flash/flash.component.spec.ts
@@ -0,0 +1,60 @@
+/*
+ * 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 { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { DebugElement } from '@angular/core';
+import { By } from '@angular/platform-browser';
+
+import { ConsoleLoggerService } from '../../consolelogger.service';
+import { LogService } from '../../log.service';
+import { FlashComponent } from './flash.component';
+
+/**
+ * ONOS GUI -- Layer -- Flash Component - Unit Tests
+ */
+describe('FlashComponent', () => {
+ let log: LogService;
+ let component: FlashComponent;
+ let fixture: ComponentFixture<FlashComponent>;
+
+ beforeEach(async(() => {
+ log = new ConsoleLoggerService();
+ TestBed.configureTestingModule({
+ imports: [ BrowserAnimationsModule ],
+ declarations: [ FlashComponent ],
+ providers: [
+ { provide: LogService, useValue: log },
+ ]
+ });
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(FlashComponent);
+ component = fixture.debugElement.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+// it('should have a div#flash', () => {
+// component.enabled = true;
+// const appDe: DebugElement = fixture.debugElement;
+// const divDe = appDe.query(By.css('div#flash'));
+// expect(divDe).toBeTruthy();
+// });
+});
diff --git a/web/gui2-fw-lib/lib/layer/flash/flash.component.ts b/web/gui2-fw-lib/lib/layer/flash/flash.component.ts
new file mode 100644
index 0000000..7dd721d
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/flash/flash.component.ts
@@ -0,0 +1,91 @@
+/*
+ * 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, Input, Output, OnChanges, SimpleChange, EventEmitter } from '@angular/core';
+import { LogService } from '../../log.service';
+import { trigger, state, style, animate, transition } from '@angular/animations';
+
+/**
+ * ONOS GUI -- Layer -- Flash Component
+ *
+ * Replaces Flash Service in old GUI.
+ * Provides a mechanism to flash short informational messages to the screen
+ * to alert the user of something, e.g. "Hosts visible" or "Hosts hidden".
+ *
+ * It can be used in a warning mode, where text will appear in red
+ * The dwell time (milliseconds) can be controlled or the default is 1200ms
+ *
+ * To use add an element to the template like
+ * <onos-flash message="Hosts visible" dwell="2000" warning="true"></onos-flash>
+ * This whole element can be disabled until needed with an ngIf, but if this is done
+ * the animated fade-in and fade-out will not happen
+ * There is also a (closed) event that tells you when the message is closed, or
+ * fades-out
+ */
+@Component({
+ selector: 'onos-flash',
+ templateUrl: './flash.component.html',
+ styleUrls: [
+ './flash.component.css',
+ '../dialog.css',
+ '../dialog.theme.css',
+ ],
+ animations: [
+ trigger('flashState', [
+ state('false', style({
+// transform: 'translateY(-400%)',
+ opacity: '0.0',
+ })),
+ state('true', style({
+// transform: 'translateY(0%)',
+ opacity: '1.0',
+ })),
+ transition('0 => 1', animate('200ms ease-in')),
+ transition('1 => 0', animate('200ms ease-out'))
+ ])
+ ]
+})
+export class FlashComponent implements OnChanges {
+ @Input() message: string;
+ @Input() dwell: number = 1200; // milliseconds
+ @Input() warning: boolean = false;
+ @Output() closed: EventEmitter<boolean> = new EventEmitter();
+
+ public visible: boolean = false;
+
+ /**
+ * Flash a message up for 1200ms then disappear again.
+ * See animation parameter for the ease in and ease out params
+ */
+ ngOnChanges(changes: {[propertyName: string]: SimpleChange}) {
+ if (changes['message'] && this.message && this.message !== '') {
+ this.visible = true;
+
+ setTimeout(() => {
+ this.visible = false;
+ this.closed.emit(false);
+ }, this.dwell);
+ }
+ }
+
+ /**
+ * The message will flash up for 'dwell' milliseconds
+ * If dwell is > 2000ms, then there will be a button that allows it to be dismissed now
+ */
+ closeNow() {
+ this.visible = false;
+ this.closed.emit(false);
+ }
+}
diff --git a/web/gui2-fw-lib/lib/layer/loading/loading.component.css b/web/gui2-fw-lib/lib/layer/loading/loading.component.css
new file mode 100644
index 0000000..9095bd2
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/loading/loading.component.css
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- Loading Service -- CSS file
+ */
+
+#loading-anim {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+ z-index: -5000;
+}
diff --git a/web/gui2-fw-lib/lib/layer/loading/loading.component.html b/web/gui2-fw-lib/lib/layer/loading/loading.component.html
new file mode 100644
index 0000000..8220197
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/loading/loading.component.html
@@ -0,0 +1,16 @@
+<!--
+~ 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.
+-->
+<img id="loading-anim" [src]="img" alt="loading - please wait" [@loadingState]="running"/>
diff --git a/web/gui2-fw-lib/lib/layer/loading/loading.component.spec.ts b/web/gui2-fw-lib/lib/layer/loading/loading.component.spec.ts
new file mode 100644
index 0000000..185c20e
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/loading/loading.component.spec.ts
@@ -0,0 +1,49 @@
+/*
+ * 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 { LoadingComponent } from './loading.component';
+import {LogService} from '../../log.service';
+import {ConsoleLoggerService} from '../../consolelogger.service';
+import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
+
+describe('LoadingComponent', () => {
+ let log: LogService;
+ let component: LoadingComponent;
+ let fixture: ComponentFixture<LoadingComponent>;
+
+ beforeEach(async(() => {
+ log = new ConsoleLoggerService();
+ TestBed.configureTestingModule({
+ imports: [ BrowserAnimationsModule ],
+ declarations: [ LoadingComponent ],
+ providers: [
+ { provide: LogService, useValue: log }
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(LoadingComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/web/gui2-fw-lib/lib/layer/loading/loading.component.ts b/web/gui2-fw-lib/lib/layer/loading/loading.component.ts
new file mode 100644
index 0000000..59ce04b
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/loading/loading.component.ts
@@ -0,0 +1,110 @@
+/*
+ * 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, Input, OnChanges, OnDestroy, OnInit, SimpleChanges} from '@angular/core';
+import {LogService} from '../../log.service';
+import {animate, state, style, transition, trigger} from '@angular/animations';
+
+const LOADING_IMG_DIR = 'data/img/loading/';
+const LOADING_PFX = '/load-';
+const NUM_IMGS = 16;
+
+/**
+ * ONOS GUI - A component that shows the loading icon
+ *
+ * Should be shown if someone has to wait for more than
+ * a certain time for data to be retrieved
+ * Note the animation - there is a pause of 500ms before the images appear
+ * and then it eases in over 200ms
+ */
+@Component({
+ selector: 'onos-loading',
+ templateUrl: './loading.component.html',
+ styleUrls: ['./loading.component.css'],
+ animations: [
+ trigger('loadingState', [
+ state('false', style({
+ opacity: '0.0',
+ 'z-index': -5000
+ })),
+ state('true', style({
+ opacity: '1.0',
+ 'z-index': 5000
+ })),
+ transition('0 => 1', animate('200ms 500ms ease-in')),
+ transition('1 => 0', animate('200ms ease-out'))
+ ])
+ ]
+})
+export class LoadingComponent implements OnChanges {
+ @Input() theme: string = 'light';
+ @Input() running: boolean;
+
+ speed: number = 8; // Frames per second
+ idx = 1;
+ images: HTMLImageElement[] = [];
+ img: string;
+ task: any;
+
+ constructor(
+ private log: LogService,
+ ) {
+ let idx: number;
+
+ for (idx = 1; idx <= NUM_IMGS ; idx++) {
+ this.addImg('light', idx);
+ this.addImg('dark', idx);
+ }
+
+ this.log.debug('LoadingComponent constructed - images preloaded from', this.fname(1, this.theme));
+ }
+
+ /**
+ * Detects changes in in Input variable
+ * Here we want to detect if running has been enabled or disabled
+ * @param changes
+ */
+ ngOnChanges(changes: SimpleChanges): void {
+ if (changes['running']) {
+ const newRunning: boolean = changes['running'].currentValue;
+
+ if (newRunning) {
+ this.task = setInterval(() => this.nextFrame(), 1000 / this.speed);
+ } else {
+ if (this.task) {
+ clearInterval(this.task);
+ this.task = null;
+ }
+ }
+ }
+ }
+
+ private addImg(theme: string, idx: number): void {
+ const img = new Image();
+ img.src = this.fname(idx, theme);
+ this.images.push(img);
+ }
+
+ private fname(i: number, theme: string): string {
+ const z = i > 9 ? '' : '0';
+ return LOADING_IMG_DIR + theme + LOADING_PFX + z + i + '.png';
+ }
+
+ private nextFrame(): void {
+ this.idx = this.idx === 16 ? 1 : this.idx + 1;
+ this.img = this.fname(this.idx, this.theme);
+ }
+
+}
diff --git a/web/gui2-fw-lib/lib/layer/panel.service.ts b/web/gui2-fw-lib/lib/layer/panel.service.ts
new file mode 100644
index 0000000..863d18f
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/panel.service.ts
@@ -0,0 +1,222 @@
+/*
+ * 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 {Injectable} from '@angular/core';
+import {FnService} from '../util/fn.service';
+import {LogService} from '../log.service';
+import {ThemeService} from '../util/theme.service';
+import {WebSocketService} from '../remote/websocket.service';
+import * as d3 from 'd3';
+
+let fs;
+
+const defaultSettings = {
+ edge: 'right',
+ width: 200,
+ margin: 20,
+ hideMargin: 20,
+ xtnTime: 750,
+ fade: true,
+};
+
+let panels,
+ panelLayer;
+
+function init() {
+ panelLayer = d3.select('div#floatpanels');
+ panelLayer.text('');
+ panels = {};
+}
+
+// helpers for panel
+function noop() {
+}
+
+function margin(p: any) {
+ return p.settings.margin;
+}
+
+function hideMargin(p: any) {
+ return p.settings.hideMargin;
+}
+
+function noPx(p: any, what: any) {
+ return Number(p.el.style(what).replace(/px$/, ''));
+}
+
+function widthVal(p: any) {
+ return noPx(p, 'width');
+}
+
+function heightVal(p: any) {
+ return noPx(p, 'height');
+}
+
+function pxShow(p: any) {
+ return margin(p) + 'px';
+}
+
+function pxHide(p: any) {
+ return (-hideMargin(p) - widthVal(p) - (noPx(p, 'padding') * 2)) + 'px';
+}
+
+function makePanel(id: any, settings: any) {
+ const p = {
+ id: id,
+ settings: settings,
+ on: false,
+ el: null,
+ },
+ api = {
+ show: showPanel,
+ hide: hidePanel,
+ toggle: togglePanel,
+ empty: emptyPanel,
+ append: appendPanel,
+ width: panelWidth,
+ height: panelHeight,
+ bbox: panelBBox,
+ isVisible: panelIsVisible,
+ classed: classed,
+ el: panelEl,
+ };
+
+ p.el = panelLayer.append('div')
+ .attr('id', id)
+ .attr('class', 'floatpanel')
+ .style('opacity', 0);
+
+ // has to be called after el is set
+ p.el.style(p.settings.edge, pxHide(p));
+ panelWidth(p.settings.width);
+ if (p.settings.height) {
+ panelHeight(p.settings.height);
+ }
+
+ panels[id] = p;
+
+ function showPanel(cb: any) {
+ const endCb = fs.isF(cb) || noop;
+ p.on = true;
+ p.el.transition().duration(p.settings.xtnTime)
+ .style(p.settings.edge, pxShow(p))
+ .style('opacity', 1);
+ }
+
+ function hidePanel(cb: any) {
+ const endCb = fs.isF(cb) || noop,
+ endOpacity = p.settings.fade ? 0 : 1;
+ p.on = false;
+ p.el.transition().duration(p.settings.xtnTime)
+ .style(p.settings.edge, pxHide(p))
+ .style('opacity', endOpacity);
+ }
+
+ function togglePanel(cb: any) {
+ if (p.on) {
+ hidePanel(cb);
+ } else {
+ showPanel(cb);
+ }
+ return p.on;
+ }
+
+ function emptyPanel() {
+ return p.el.text('');
+ }
+
+ function appendPanel(what: any) {
+ return p.el.append(what);
+ }
+
+ function panelWidth(w: any) {
+ if (w === undefined) {
+ return widthVal(p);
+ }
+ p.el.style('width', w + 'px');
+ }
+
+ function panelHeight(h: any) {
+ if (h === undefined) {
+ return heightVal(p);
+ }
+ p.el.style('height', h + 'px');
+ }
+
+ function panelBBox() {
+ return p.el.node().getBoundingClientRect();
+ }
+
+ function panelIsVisible() {
+ return p.on;
+ }
+
+ function classed(cls: any, bool: any) {
+ return p.el.classed(cls, bool);
+ }
+
+ function panelEl() {
+ return p.el;
+ }
+
+ return api;
+}
+
+function removePanel(id: any) {
+ panelLayer.select('#' + id).remove();
+ delete panels[id];
+}
+
+@Injectable({
+ providedIn: 'root',
+})
+export class PanelService {
+ constructor(private funcs: FnService,
+ private log: LogService,
+ private ts: ThemeService,
+ private wss: WebSocketService) {
+ fs = this.funcs;
+ init();
+ }
+
+ createPanel(id: any, opts: any) {
+ const settings = (<any>Object).assign({}, defaultSettings, opts);
+ if (!id) {
+ this.log.warn('createPanel: no ID given');
+ return null;
+ }
+ if (panels[id]) {
+ this.log.warn('Panel with ID "' + id + '" already exists');
+ return null;
+ }
+ if (fs.debugOn('widget')) {
+ this.log.debug('creating panel:', id, settings);
+ }
+ return makePanel(id, settings);
+ }
+
+ destroyPanel(id: any) {
+ if (panels[id]) {
+ if (fs.debugOn('widget')) {
+ this.log.debug('destroying panel:', id);
+ }
+ removePanel(id);
+ } else {
+ if (fs.debugOn('widget')) {
+ this.log.debug('no panel to destroy:', id);
+ }
+ }
+ }
+}
diff --git a/web/gui2-fw-lib/lib/layer/quickhelp/quickhelp.component.css b/web/gui2-fw-lib/lib/layer/quickhelp/quickhelp.component.css
new file mode 100644
index 0000000..fb0995a
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/quickhelp/quickhelp.component.css
@@ -0,0 +1,56 @@
+/*
+ * 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: absolute;
+ width: 100%;
+}
+
+#quickhelp div.help {
+ background: black;
+ opacity: 0.8;
+}
+
+#quickhelp div.help table {
+ vertical-align: top;
+ width: 100%;
+}
+
+#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/lib/layer/quickhelp/quickhelp.component.html b/web/gui2-fw-lib/lib/layer/quickhelp/quickhelp.component.html
new file mode 100644
index 0000000..7d96ebf
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/quickhelp/quickhelp.component.html
@@ -0,0 +1,72 @@
+<!--
+~ 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">{{lionFn("qh_hint_show_hide_qh")}}</td>
+ </tr>
+ <tr>
+ <td class="key">/</td>
+ <td class="desc">{{lionFn("qh_hint_show_hide_qh")}}</td>
+ </tr>
+ <tr>
+ <td class="key">Esc</td>
+ <td class="desc">{{lionFn("qh_hint_esc")}}</td>
+ </tr>
+ <tr>
+ <td class="key">T</td>
+ <td class="desc">{{lionFn("qh_hint_t")}}</td>
+ </tr>
+ </table>
+ <hr class="qhrowsep">
+ <table class="qhrow">
+ <tr *ngFor="let vk of viewKeys; i as index">
+ <ng-container *ngFor="let vkrow of vk">
+ <td class="key">{{vkrow.keystroke}}</td>
+ <td class="desc">{{vkrow.text}}</td>
+ </ng-container>
+ </tr>
+ </table>
+ <hr class="qhrowsep">
+ <div class="qhrow">
+ <table class="qh-r4-c0">
+ <tr>
+ <td class="key">{{lionFnTopo("click")}}</td>
+ <td class="desc">{{lionFnTopo("qh_gest_click")}}</td>
+ </tr>
+ <tr>
+ <td class="key">{{lionFnTopo("shift_click")}}</td>
+ <td class="desc">{{lionFnTopo("qh_gest_shift_click")}}</td>
+ </tr>
+ <tr>
+ <td class="key">{{lionFnTopo("drag")}}</td>
+ <td class="desc">{{lionFnTopo("qh_gest_drag")}}</td>
+ </tr>
+ <tr>
+ <td class="key">{{lionFnTopo("cmd_scroll")}}</td>
+ <td class="desc">{{lionFnTopo("qh_gest_cmd_scroll")}}</td>
+ </tr>
+ <tr>
+ <td class="key" y="48">{{lionFnTopo("drag")}}</td>
+ <td class="desc" y="48" x="74.84375">{{lionFnTopo("qh_gest_cmd_drag")}}</tr>
+ </table>
+ </div>
+ </div>
+</div>
diff --git a/web/gui2-fw-lib/lib/layer/quickhelp/quickhelp.component.spec.ts b/web/gui2-fw-lib/lib/layer/quickhelp/quickhelp.component.spec.ts
new file mode 100644
index 0000000..5dfb73c
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/quickhelp/quickhelp.component.spec.ts
@@ -0,0 +1,92 @@
+/*
+ * 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 {
+ keyHandler: {
+ viewKeys: any[],
+ globalKeys: any[]
+ };
+
+ mockViewKeys: Object[];
+ constructor() {
+ this.mockViewKeys = [];
+ this.keyHandler = {
+ viewKeys: this.mockViewKeys,
+ globalKeys: this.mockViewKeys
+ };
+ }
+}
+
+/**
+ * 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/lib/layer/quickhelp/quickhelp.component.ts b/web/gui2-fw-lib/lib/layer/quickhelp/quickhelp.component.ts
new file mode 100644
index 0000000..ca2408c
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/quickhelp/quickhelp.component.ts
@@ -0,0 +1,109 @@
+/*
+ * 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, OnInit} 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';
+
+export interface KeyEntry {
+ keystroke: string;
+ text: string;
+}
+
+@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 implements OnInit {
+ lionFn; // Function
+ lionFnTopo; // Function
+
+ dialogKeys: Object;
+ globalKeys: Object[];
+ maskedKeys: Object;
+ viewGestures: Object;
+ viewKeys: KeyEntry[][];
+
+ private static extractKeyEntry(viewKeyObj: Object, log: LogService): KeyEntry {
+ const subParts = (<any>Object).values(viewKeyObj[1]);
+ return <KeyEntry>{
+ keystroke: <string>viewKeyObj[0],
+ text: <string>subParts[1]
+ };
+ }
+
+ constructor(
+ private log: LogService,
+ private fs: FnService,
+ public ks: KeysService,
+ private lion: LionService
+ ) {
+ if (this.lion.ubercache.length === 0) {
+ this.lionFn = this.dummyLion;
+ this.lionFnTopo = this.dummyLion;
+ this.lion.loadCbs.set('quickhelp', () => this.doLion());
+ } else {
+ this.doLion();
+ }
+ this.globalKeys = [];
+ this.viewKeys = [[], [], [], [], [], [], [], [], []];
+
+ this.log.debug('QuickhelpComponent constructed');
+ }
+
+ ngOnInit(): void {
+ (<any>Object).entries(this.ks.keyHandler.viewKeys)
+ .filter((vk) => vk[0] !== '_helpFormat' && vk[0] !== '9' && vk[0] !== 'esc')
+ .forEach((vk, idx) => {
+ const ke = QuickhelpComponent.extractKeyEntry(vk, this.log);
+ this.viewKeys[Math.floor(idx / 3)][idx % 3] = ke;
+ });
+ this.log.debug('QuickhelpComponent initialized');
+ this.log.debug('view keys retrieved', this.ks.keyHandler.globalKeys);
+ }
+
+
+ /**
+ * Read the LION bundle for Toolbar and set up the lionFn
+ */
+ doLion() {
+ this.lionFn = this.lion.bundle('core.fw.QuickHelp');
+ this.lionFnTopo = this.lion.bundle('core.view.Topo');
+ }
+
+ /**
+ * A dummy implementation of the lionFn until the response is received and the LION
+ * bundle is received from the WebSocket
+ */
+ dummyLion(key: string): string {
+ return '%' + key + '%';
+ }
+}
diff --git a/web/gui2-fw-lib/lib/layer/quickhelp/test/uberlion_english_sample.json b/web/gui2-fw-lib/lib/layer/quickhelp/test/uberlion_english_sample.json
new file mode 100644
index 0000000..7ff843e
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/quickhelp/test/uberlion_english_sample.json
@@ -0,0 +1,288 @@
+{
+ "event": "uberlion",
+ "payload": {
+ "lion": {
+ "core.fw.Mast": {
+ "confirm_refresh_title": "Confirm GUI Refresh",
+ "logout": "Logout",
+ "tt_help": "Show help page for current view",
+ "ui_ok_to_update": "Press OK to update the GUI.",
+ "uicomp_added": "New GUI components were added.",
+ "uicomp_removed": "Some GUI components were removed.",
+ "unknown_user": "(no one)"
+ },
+ "core.fw.Nav": {
+ "cat_network": "Network",
+ "cat_other": "Other",
+ "cat_platform": "Platform",
+ "nav_item_app": "Applications",
+ "nav_item_cluster": "Cluster Nodes",
+ "nav_item_device": "Devices",
+ "nav_item_host": "Hosts",
+ "nav_item_intent": "Intents",
+ "nav_item_link": "Links",
+ "nav_item_partition": "Partitions",
+ "nav_item_processor": "Packet Processors",
+ "nav_item_settings": "Settings",
+ "nav_item_topo": "Topology",
+ "nav_item_topo2": "Topology 2",
+ "nav_item_tunnel": "Tunnels"
+ },
+ "core.fw.QuickHelp": {
+ "qh_hint_close_detail": "Close the details panel",
+ "qh_hint_esc": "Dismiss dialog or cancel selections",
+ "qh_hint_show_hide_qh": "Show / hide Quick Help",
+ "qh_hint_t": "Toggle theme",
+ "qh_title": "Quick Help"
+ },
+ "core.view.App": {
+ "activate": "Activate",
+ "app_id": "App ID",
+ "category": "Category",
+ "click_row": "click row",
+ "deactivate": "Deactivate",
+ "dlg_confirm_action": "Confirm Action",
+ "dlg_warn_deactivate": "Deactivating or uninstalling this component can have serious negative consequences!",
+ "dlg_warn_own_risk": "** DO SO AT YOUR OWN RISK **",
+ "dp_features": "Features",
+ "dp_permissions": "Permissions",
+ "dp_required_apps": "Required Apps",
+ "icon": "Icon",
+ "nav_item_app": "Applications",
+ "origin": "Origin",
+ "qh_hint_click_row": "Select / deselect application",
+ "qh_hint_close_detail": "Close the details panel",
+ "qh_hint_esc": "Deselect application",
+ "qh_hint_scroll_down": "See more applications",
+ "role": "Role",
+ "scroll_down": "scroll down",
+ "state": "State",
+ "title": "Title",
+ "title_apps": "Applications",
+ "total": "Total",
+ "tt_ctl_activate": "Activate selected application",
+ "tt_ctl_auto_refresh": "Toggle auto refresh",
+ "tt_ctl_deactivate": "Deactivate selected application",
+ "tt_ctl_download": "Download selected application (.oar file)",
+ "tt_ctl_uninstall": "Uninstall selected application",
+ "tt_ctl_upload": "Upload an application (.oar file)",
+ "uninstall": "Uninstall",
+ "version": "Version"
+ },
+ "core.view.Cluster": {
+ "active": "Active",
+ "chassis_id": "Chassis ID",
+ "click": "click",
+ "devices": "Devices",
+ "hw_version": "H/W Version",
+ "ip_address": "IP Address",
+ "last_updated": "Last Updated",
+ "nav_item_cluster": "Cluster Nodes",
+ "node_id": "Node ID",
+ "protocol": "Protocol",
+ "qh_hint_click": "Select a row to show cluster node details",
+ "qh_hint_close_detail": "Close the details panel",
+ "qh_hint_scroll_down": "See available cluster nodes",
+ "scroll_down": "scroll down",
+ "serial_number": "Serial #",
+ "started": "Started",
+ "sw_version": "S/W Version",
+ "tcp_port": "TCP Port",
+ "title_cluster_nodes": "Cluster Nodes",
+ "total": "Total",
+ "type": "Type",
+ "uri": "URI",
+ "vendor": "Vendor"
+ },
+ "core.view.Topo": {
+ "active": "active",
+ "added": "added",
+ "btn_show_view_device": "Show Device View",
+ "btn_show_view_flow": "Show Flow View for this Device",
+ "btn_show_view_group": "Show Group View for this Device",
+ "btn_show_view_meter": "Show Meter View for this Device",
+ "btn_show_view_port": "Show Port View for this Device",
+ "click": "click",
+ "close": "Close",
+ "cmd_drag": "cmd-drag",
+ "cmd_scroll": "cmd-scroll",
+ "device": "Device",
+ "devices": "Devices",
+ "direct": "direct",
+ "disable": "Disable",
+ "drag": "drag",
+ "edge": "edge",
+ "enable": "Enable",
+ "expected": "expected",
+ "fl_background_map": "background map",
+ "fl_bad_links": "Bad Links",
+ "fl_device_labels_hide": "Hide device labels",
+ "fl_device_labels_show_friendly": "Show friendly device labels",
+ "fl_device_labels_show_id": "Show device ID labels",
+ "fl_eq_masters": "Equalizing master roles",
+ "fl_grid_display_1000": "Show XY grid",
+ "fl_grid_display_both": "Show both grids",
+ "fl_grid_display_geo": "Show Geo grid",
+ "fl_grid_display_hide": "Hide grid",
+ "fl_host_labels_hide": "Hide host labels",
+ "fl_host_labels_show_friendly": "Show friendly host labels",
+ "fl_host_labels_show_ip": "Show host IP addresses",
+ "fl_host_labels_show_mac": "Show host MAC addresses",
+ "fl_layer_all": "All Layers Shown",
+ "fl_layer_opt": "Optical Layer Shown",
+ "fl_layer_pkt": "Packet Layer Shown",
+ "fl_monitoring_canceled": "Monitoring Canceled",
+ "fl_normal_view": "Normal View",
+ "fl_oblique_view": "Oblique View",
+ "fl_offline_devices": "Offline Devices",
+ "fl_pan_zoom_reset": "Pan and zoom reset",
+ "fl_panel_details": "Details Panel",
+ "fl_panel_instances": "Instances Panel",
+ "fl_panel_summary": "Summary Panel",
+ "fl_pinned_floating_nodes": "Pinned floating nodes",
+ "fl_port_highlighting": "Port Highlighting",
+ "fl_reset_node_locations": "Reset Node Locations",
+ "fl_selecting_intent": "Selecting Intent",
+ "fl_sprite_layer": "sprite layer",
+ "fl_unpinned_floating_nodes": "Unpinned floating nodes",
+ "flows": "Flows",
+ "grid_x": "Grid X",
+ "grid_y": "Grid Y",
+ "hidden": "Hidden",
+ "hide": "Hide",
+ "host": "Host",
+ "hosts": "Hosts",
+ "hw_version": "H/W Version",
+ "inactive": "inactive",
+ "indirect": "indirect",
+ "intent": "Intent",
+ "intents": "Intents",
+ "ip": "IP",
+ "latitude": "Latitude",
+ "links": "Links",
+ "longitude": "Longitude",
+ "lp_label_a2b": "A to B",
+ "lp_label_a_friendly": "A name",
+ "lp_label_a_id": "A id",
+ "lp_label_a_port": "A port",
+ "lp_label_a_type": "A type",
+ "lp_label_b2a": "B to A",
+ "lp_label_b_friendly": "B name",
+ "lp_label_b_id": "B id",
+ "lp_label_b_port": "B port",
+ "lp_label_b_type": "B type",
+ "lp_label_friendly": "Friendly",
+ "lp_value_no_link": "[no link]",
+ "mac": "MAC",
+ "nav_item_topo": "Topology",
+ "no_devices_are_connected": "No Devices Are Connected",
+ "not_expected": "not expected",
+ "ok": "OK",
+ "optical": "optical",
+ "ov_tt_none": "No Overlay",
+ "ov_tt_protected_intents": "Protected Intents Overlay",
+ "ov_tt_traffic": "Traffic Overlay",
+ "ports": "Ports",
+ "protocol": "Protocol",
+ "purged": "purged",
+ "qh_gest_click": "Select the item and show details",
+ "qh_gest_cmd_drag": "Pan",
+ "qh_gest_cmd_scroll": "Zoom in / out",
+ "qh_gest_drag": "Reposition (and pin) device / host",
+ "qh_gest_shift_click": "Toggle selection state",
+ "qh_hint_close_detail": "Close the details panel",
+ "resubmitted": "resubmitted",
+ "select": "Select",
+ "serial_number": "Serial #",
+ "shift_click": "shift-click",
+ "show": "Show",
+ "sw_version": "S/W Version",
+ "tbtt_bad_links": "Show bad links",
+ "tbtt_cyc_dev_labs": "Cycle device labels",
+ "tbtt_cyc_grid_display": "Cycle grid display",
+ "tbtt_cyc_host_labs": "Cycle host labels",
+ "tbtt_cyc_layers": "Cycle node layers",
+ "tbtt_eq_master": "Equalize mastership roles",
+ "tbtt_reset_loc": "Reset node locations",
+ "tbtt_reset_zoom": "Reset pan / zoom",
+ "tbtt_sel_map": "Select background geo map",
+ "tbtt_tog_host": "Toggle host visibility",
+ "tbtt_tog_instances": "Toggle ONOS instances panel",
+ "tbtt_tog_map": "Toggle background geo map",
+ "tbtt_tog_oblique": "Toggle oblique view (experimental)",
+ "tbtt_tog_offline": "Toggle offline visibility",
+ "tbtt_tog_porthi": "Toggle port highlighting",
+ "tbtt_tog_sprite": "Toggle sprite layer",
+ "tbtt_tog_summary": "Toggle ONOS summary panel",
+ "tbtt_tog_toolbar": "Toggle Toolbar",
+ "tbtt_tog_use_detail": "Disable / enable details panel",
+ "tbtt_unpin_node": "Unpin node (hover mouse over)",
+ "title_edge_link": "Edge Link",
+ "title_infra_link": "Infrastructure Link",
+ "title_panel_summary": "ONOS Summary",
+ "title_select_map": "Select Map",
+ "title_selected_items": "Selected Items",
+ "topology_sccs": "Topology SCCs",
+ "tr_btn_cancel_monitoring": "Cancel traffic monitoring",
+ "tr_btn_create_h2h_flow": "Create Host-to-Host Flow",
+ "tr_btn_create_msrc_flow": "Create Multi-Source Flow",
+ "tr_btn_monitor_all": "Monitor all traffic",
+ "tr_btn_monitor_sel_intent": "Monitor traffic of selected intent",
+ "tr_btn_show_all_rel_intents": "Show all related intents",
+ "tr_btn_show_dev_link_flows": "Show device link flows",
+ "tr_btn_show_device_flows": "Show Device Flows",
+ "tr_btn_show_next_rel_intent": "Show next related intent",
+ "tr_btn_show_prev_rel_intent": "Show previous related intent",
+ "tr_btn_show_related_traffic": "Show Related Traffic",
+ "tr_fl_dev_flows": "Device Flows",
+ "tr_fl_fstats_bytes": "Flow Stats (bytes)",
+ "tr_fl_h2h_flow_added": "Host-to-Host flow added",
+ "tr_fl_multisrc_flow": "Multi-Source Flow",
+ "tr_fl_next_rel_int": "Next related intent",
+ "tr_fl_prev_rel_int": "Previous related intent",
+ "tr_fl_pstats_bits": "Port Stats (bits / second)",
+ "tr_fl_pstats_pkts": "Port Stats (packets / second)",
+ "tr_fl_rel_paths": "Related Paths",
+ "tr_fl_traf_on_path": "Traffic on Selected Path",
+ "tunnel": "tunnel",
+ "tunnels": "Tunnels",
+ "uri": "URI",
+ "vendor": "Vendor",
+ "version": "Version",
+ "virtual": "virtual",
+ "visible": "Visible",
+ "vlan": "VLAN",
+ "vlan_none": "None",
+ "withdrawn": "withdrawn"
+ },
+ "core.view.Flow": {
+ "appId": "App ID",
+ "appName": "App Name",
+ "bytes": "Bytes",
+ "duration": "Duration ",
+ "flowId": "Flow ID",
+ "groupId": "Group ID",
+ "hardTimeout": "Hard Timeout",
+ "idleTimeout": "Idle Timeout",
+ "nav_item_flow": "Flows",
+ "packets": "Packets",
+ "permanent": "Permanent",
+ "priority": "Flow Priority ",
+ "selector": "Selector",
+ "state": "State",
+ "tableName": "Table Name ",
+ "title_flows": "Flows for Device ",
+ "total": "Total",
+ "treatment": "Treatment",
+ "tt_ctl_show_device": "Show device table",
+ "tt_ctl_show_group": "Show group view for this device",
+ "tt_ctl_show_meter": "Show meter view for selected device",
+ "tt_ctl_show_pipeconf": "Show pipeconf view for selected device",
+ "tt_ctl_show_port": "Show port view for this device",
+ "tt_ctl_switcth_brief": "Switch to brief view",
+ "tt_ctl_switcth_detailed": "Switch to detailed view"
+ }
+ },
+ "locale": "en_IE"
+ }
+}
diff --git a/web/gui2-fw-lib/lib/layer/veil/veil.component.css b/web/gui2-fw-lib/lib/layer/veil/veil.component.css
new file mode 100644
index 0000000..b688ae7
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/veil/veil.component.css
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- Veil Service (layout) -- CSS file
+ */
+
+#veil {
+ z-index: 5000;
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding: 60px;
+}
+
+#veil p {
+ display: block;
+ text-align: left;
+ font-size: 14pt;
+ font-style: italic;
+}
diff --git a/web/gui2-fw-lib/lib/layer/veil/veil.component.html b/web/gui2-fw-lib/lib/layer/veil/veil.component.html
new file mode 100644
index 0000000..69410c5
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/veil/veil.component.html
@@ -0,0 +1,25 @@
+<!--
+~ 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.
+-->
+
+<div id="veil" *ngIf="enabled">
+ <p *ngFor="let msg of messages">{{ msg }}</p>
+ <svg [attr.width]="fs.windowSize().width" [attr.height]="fs.windowSize().height">
+ <use [attr.width]="birdDim" [attr.height]="birdDim" class="glyph"
+ style="opacity: 0.2;"
+ xlink:href = "#bird" [attr.transform]="trans"/>
+
+ </svg>
+</div>
diff --git a/web/gui2-fw-lib/lib/layer/veil/veil.component.spec.ts b/web/gui2-fw-lib/lib/layer/veil/veil.component.spec.ts
new file mode 100644
index 0000000..72123dd
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/veil/veil.component.spec.ts
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- Layer -- Veil Service - Unit Tests
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute, Params } from '@angular/router';
+
+import { VeilComponent } from './veil.component';
+import { ConsoleLoggerService } from '../../consolelogger.service';
+import { FnService } from '../../util/fn.service';
+import { LogService } from '../../log.service';
+import { GlyphService } from '../../svg/glyph.service';
+import { of } from 'rxjs';
+
+class MockActivatedRoute extends ActivatedRoute {
+ constructor(params: Params) {
+ super();
+ this.queryParams = of(params);
+ }
+}
+
+class MockGlyphService {}
+
+describe('VeilComponent', () => {
+ let fs: FnService;
+ let ar: MockActivatedRoute;
+ let windowMock: Window;
+ let logServiceSpy: jasmine.SpyObj<LogService>;
+
+ beforeEach(async(() => {
+ const logSpy = jasmine.createSpyObj('LogService', ['info', 'debug', 'warn', 'error']);
+ ar = new MockActivatedRoute({});
+ windowMock = <any>{
+ location: <any> {
+ hostname: 'foo'
+ }
+ };
+ fs = new FnService(ar, logSpy, windowMock);
+
+ TestBed.configureTestingModule({
+ declarations: [ VeilComponent ],
+ providers: [
+ { provide: FnService, useValue: fs },
+ { provide: LogService, useValue: logSpy },
+ { provide: GlyphService, useClass: MockGlyphService },
+ { provide: 'Window', useValue: windowMock },
+ ]
+ });
+ logServiceSpy = TestBed.get(LogService);
+ }));
+
+ it('should create', () => {
+ const fixture = TestBed.createComponent(VeilComponent);
+ const component = fixture.componentInstance;
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/web/gui2-fw-lib/lib/layer/veil/veil.component.theme.css b/web/gui2-fw-lib/lib/layer/veil/veil.component.theme.css
new file mode 100644
index 0000000..2939b9f
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/veil/veil.component.theme.css
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+/*
+ ONOS GUI -- Veil Service (theme) -- CSS file
+ */
+
+.light, #veil {
+ background-color: rgba(0,0,0,0.75);
+}
+.dark, #veil {
+ background-color: rgba(64,64,64,0.75);
+}
+
+#veil p {
+ color: #ddd;
+}
+
+#veil svg .glyph {
+ fill: #222;
+}
diff --git a/web/gui2-fw-lib/lib/layer/veil/veil.component.ts b/web/gui2-fw-lib/lib/layer/veil/veil.component.ts
new file mode 100644
index 0000000..b93d950
--- /dev/null
+++ b/web/gui2-fw-lib/lib/layer/veil/veil.component.ts
@@ -0,0 +1,84 @@
+/*
+ * 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 } from '../../util/fn.service';
+import { GlyphService } from '../../svg/glyph.service';
+import { LogService } from '../../log.service';
+import { SvgUtilService } from '../../svg/svgutil.service';
+import { WebSocketService } from '../../remote/websocket.service';
+
+const BIRD = 'bird';
+
+/**
+ * ONOS GUI -- Layer -- Veil Component
+ *
+ * Provides a mechanism to display an overlaying div with information.
+ * Used mainly for web socket connection interruption.
+ *
+ * It can be added to an component's template as follows:
+ * <onos-veil #veil></onos-veil>
+ * <p (click)="veil.show(['t1','t2','t3'])">Test Veil</p>
+ */
+@Component({
+ selector: 'onos-veil',
+ templateUrl: './veil.component.html',
+ styleUrls: ['./veil.component.css', './veil.component.theme.css']
+})
+export class VeilComponent implements OnInit {
+ ww: number;
+ wh: number;
+ birdSvg: string;
+ birdDim: number;
+ enabled: boolean = false;
+ trans: string;
+ messages: string[] = [];
+ veilStyle: string;
+
+ constructor(
+ public fs: FnService,
+ private gs: GlyphService,
+ private log: LogService,
+ private sus: SvgUtilService,
+ private wss: WebSocketService
+ ) {
+ const wSize = this.fs.windowSize();
+ this.ww = wSize.width;
+ this.wh = wSize.height;
+ const shrink = this.wh * 0.3;
+ this.birdDim = this.wh - shrink;
+ const birdCenter = (this.ww - this.birdDim) / 2;
+ this.trans = this.sus.translate([birdCenter, shrink / 2]);
+
+ this.log.debug('VeilComponent with ' + BIRD + ' constructed');
+ }
+
+ ngOnInit() {
+ }
+
+ // msg should be an array of strings
+ show(msgs: string[]): void {
+ this.messages = msgs;
+ this.enabled = true;
+// this.ks.enableKeys(false);
+ }
+
+ hide(): void {
+ this.veilStyle = 'display: none';
+// this.ks.enableKeys(true);
+ }
+
+
+}