From 854af18c26835319712aded05fdc3624502314a4 Mon Sep 17 00:00:00 2001 From: Nicolas Hu Date: Mon, 17 Aug 2020 10:11:50 -0400 Subject: [PATCH] Add Xapp Onboarder frontend UI Signed-off-by: Jun (Nicolas) Hu Issue-ID: OAM-108 Change-Id: Ic5f1d997a9c5dbc6786c6d364e92f7e5a30c938c --- .../src/app/catalog/catalog.component.html | 88 ++++++------- .../src/app/catalog/catalog.component.ts | 21 ++++ .../src/app/onboard/onboard.component.html | 60 +++++++++ .../src/app/onboard/onboard.component.scss | 23 ++++ .../src/app/onboard/onboard.component.spec.ts | 45 +++++++ .../src/app/onboard/onboard.component.ts | 137 +++++++++++++++++++++ dashboard/webapp-frontend/src/app/rd.module.ts | 8 +- .../xapp-onboarder/xapp-onboarder.service.spec.ts | 35 ++++++ .../xapp-onboarder/xapp-onboarder.service.ts | 46 +++++++ docs/release-notes.rst | 3 +- 10 files changed, 420 insertions(+), 46 deletions(-) create mode 100644 dashboard/webapp-frontend/src/app/onboard/onboard.component.html create mode 100644 dashboard/webapp-frontend/src/app/onboard/onboard.component.scss create mode 100644 dashboard/webapp-frontend/src/app/onboard/onboard.component.spec.ts create mode 100644 dashboard/webapp-frontend/src/app/onboard/onboard.component.ts create mode 100644 dashboard/webapp-frontend/src/app/services/xapp-onboarder/xapp-onboarder.service.spec.ts create mode 100644 dashboard/webapp-frontend/src/app/services/xapp-onboarder/xapp-onboarder.service.ts diff --git a/dashboard/webapp-frontend/src/app/catalog/catalog.component.html b/dashboard/webapp-frontend/src/app/catalog/catalog.component.html index 78d525ce..b54d5dbf 100644 --- a/dashboard/webapp-frontend/src/app/catalog/catalog.component.html +++ b/dashboard/webapp-frontend/src/app/catalog/catalog.component.html @@ -17,47 +17,49 @@ limitations under the License. ========================LICENSE_END=================================== --> -
-

xApp Catalog

- - - - - App Name - {{element.name}} - - - - Version - {{element.version}} - - - - Action - -
- - -
-
-
- - - No records found. - - - - - - -
- -
- -
+
+

xApp Catalog

+ + + + + + + App Name + {{element.name}} + + + + Version + {{element.version}} + + + + Action + +
+ + +
+
+
- + + No records found. + + + + + + +
+ +
+ +
+ +
diff --git a/dashboard/webapp-frontend/src/app/catalog/catalog.component.ts b/dashboard/webapp-frontend/src/app/catalog/catalog.component.ts index 4ae7b89c..ac8e6ec6 100644 --- a/dashboard/webapp-frontend/src/app/catalog/catalog.component.ts +++ b/dashboard/webapp-frontend/src/app/catalog/catalog.component.ts @@ -31,6 +31,7 @@ import { LoadingDialogService } from '../services/ui/loading-dialog.service'; import { UiService } from '../services/ui/ui.service'; import { AppConfigurationComponent } from './../app-configuration/app-configuration.component'; import { ConfirmDialogService } from '../services/ui/confirm-dialog.service'; +import { OnboardComponent } from './../onboard/onboard.component'; import { NotificationService } from '../services/ui/notification.service'; import { CatalogDataSource } from './catalog.datasource'; @@ -125,4 +126,24 @@ export class CatalogComponent implements OnInit, OnDestroy { ); } + onboard(): void { + if (this.darkMode) { + this.panelClass = 'dark-theme'; + } else { + this.panelClass = ''; + } + const dialogRef = this.dialog.open(OnboardComponent, { + panelClass: this.panelClass, + width: '400px', + maxHeight: '1000px', + position: { + top: '10%' + }, + data: { + instanceKey: this.instanceKey + } + + }); + } + } diff --git a/dashboard/webapp-frontend/src/app/onboard/onboard.component.html b/dashboard/webapp-frontend/src/app/onboard/onboard.component.html new file mode 100644 index 00000000..478cbb2b --- /dev/null +++ b/dashboard/webapp-frontend/src/app/onboard/onboard.component.html @@ -0,0 +1,60 @@ + + + + + + + + + + folder_open + + + + + folder_open + + + + + + +
+ + config file URL + + + + control schema URL + + + +
+
+ +
+ diff --git a/dashboard/webapp-frontend/src/app/onboard/onboard.component.scss b/dashboard/webapp-frontend/src/app/onboard/onboard.component.scss new file mode 100644 index 00000000..4c566884 --- /dev/null +++ b/dashboard/webapp-frontend/src/app/onboard/onboard.component.scss @@ -0,0 +1,23 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2020 AT&T Intellectual Property + * %% + * 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. + * ========================LICENSE_END=================================== + */ + +.mat-raised-button { + margin-right: 5px; +} \ No newline at end of file diff --git a/dashboard/webapp-frontend/src/app/onboard/onboard.component.spec.ts b/dashboard/webapp-frontend/src/app/onboard/onboard.component.spec.ts new file mode 100644 index 00000000..dd62cda9 --- /dev/null +++ b/dashboard/webapp-frontend/src/app/onboard/onboard.component.spec.ts @@ -0,0 +1,45 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2020 AT&T Intellectual Property + * %% + * 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. + * ========================LICENSE_END=================================== + */ + +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OnboardComponent } from './onboard.component'; + +describe('OnboardComponent', () => { + let component: OnboardComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ OnboardComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(OnboardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/dashboard/webapp-frontend/src/app/onboard/onboard.component.ts b/dashboard/webapp-frontend/src/app/onboard/onboard.component.ts new file mode 100644 index 00000000..7f609a62 --- /dev/null +++ b/dashboard/webapp-frontend/src/app/onboard/onboard.component.ts @@ -0,0 +1,137 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2020 AT&T Intellectual Property + * %% + * 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. + * ========================LICENSE_END=================================== + */ + +import { Component, Inject, OnInit } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { BehaviorSubject } from 'rxjs/BehaviorSubject'; +import { finalize } from 'rxjs/operators'; +import { XappOnboarderService } from '../services/xapp-onboarder/xapp-onboarder.service'; +import { ErrorDialogService } from '../services/ui/error-dialog.service'; +import { LoadingDialogService } from '../services/ui/loading-dialog.service'; +import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; +import { NotificationService } from '../services/ui/notification.service'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; + +@Component({ + selector: 'rd-onboard', + templateUrl: './onboard.component.html', + styleUrls: ['./onboard.component.scss'] +}) +export class OnboardComponent implements OnInit { + + private loadingSubject = new BehaviorSubject(false); + public loading$ = this.loadingSubject.asObservable(); + public urlOnboardForm: FormGroup; + + constructor( + private dialogRef: MatDialogRef, + private xappOnboarderService: XappOnboarderService, + private errorDiaglogService: ErrorDialogService, + private loadingDialogService: LoadingDialogService, + private notificationService: NotificationService, + @Inject(MAT_DIALOG_DATA) private data + ) { } + + ngOnInit(): void { + this.urlOnboardForm = new FormGroup({ + configURL: new FormControl('', [Validators.required]), + schemaURL: new FormControl('', [Validators.required]) + }) + } + ; + configFile: File; + controlsSchema: File; + descriptor = { + "config-file.json": {}, + "controls-schema.json": {} + } + descriptor_url = { + "config-file.json_url": "", + "controls-schema.json_url": "" + } + + uploadFromLocal() { + this.loadingDialogService.startLoading('Onboarding xApp'); + this.xappOnboarderService.onboardXappFile(this.descriptor, this.data.instanceKey) + .pipe( + finalize(() => { + this.loadingDialogService.stopLoading(); + this.dialogRef.close(); + }) + ) + .subscribe( + (response: HttpResponse) => { + this.notificationService.success('Onboard succeeded!'); + }, + ((her: HttpErrorResponse) => { + let msg = her.message; + if (her.error && her.error.message) { + msg = her.error.message; + } + this.notificationService.warn('Onboard failed: ' + msg); + }) + ); + } + + uploadFromURL(data) { + this.descriptor_url["config-file.json_url"] = data.configURL; + this.descriptor_url["controls-schema.json_url"] = data.schemaURL; + this.loadingDialogService.startLoading('Onboarding xApp'); + this.xappOnboarderService.onboardXappURL(this.descriptor_url, this.data.instanceKey) + .pipe( + finalize(() => { + this.loadingDialogService.stopLoading(); + this.dialogRef.close(); + }) + ) + .subscribe( + (response: HttpResponse) => { + this.notificationService.success('Onboard succeeded!'); + }, + ((her: HttpErrorResponse) => { + let msg = her.message; + if (her.error && her.error.message) { + msg = her.error.message; + } + this.notificationService.warn('Onboard failed: ' + msg); + }) + ); + } + + + selectConfigFile(event) { + this.configFile = event.target.files[0]; + let fileReader = new FileReader(); + fileReader.onload = (e) => { + this.descriptor["config-file.json"] = JSON.parse(fileReader.result as string); + } + fileReader.readAsText(this.configFile); + } + + selectControlsSchema(event) { + this.controlsSchema = event.target.files[0]; + let fileReader = new FileReader(); + fileReader.onload = (e) => { + this.descriptor["controls-schema.json"] = JSON.parse(fileReader.result as string); + } + fileReader.readAsText(this.controlsSchema); + + } +} diff --git a/dashboard/webapp-frontend/src/app/rd.module.ts b/dashboard/webapp-frontend/src/app/rd.module.ts index c91ce3e9..9de3bad7 100644 --- a/dashboard/webapp-frontend/src/app/rd.module.ts +++ b/dashboard/webapp-frontend/src/app/rd.module.ts @@ -67,6 +67,7 @@ import { EditDashboardUserDialogComponent } from './user/edit-dashboard-user-dia import { ErrorDialogComponent } from './ui/error-dialog/error-dialog.component'; import { FooterComponent } from './footer/footer.component'; import { InstanceSelectorDialogComponent } from './ui/instance-selector-dialog/instance-selector-dialog.component'; +import { OnboardComponent } from './onboard/onboard.component'; import { LoadingDialogComponent } from './ui/loading-dialog/loading-dialog.component'; import { MainComponent } from './main/main.component'; import { PlatformComponent } from './platform/platform.component'; @@ -87,6 +88,7 @@ import { ErrorDialogService } from './services/ui/error-dialog.service'; import { InstanceSelectorService } from './services/instance-selector/instance-selector.service'; import { InstanceSelectorDialogService } from './services/ui/instance-selector-dialog.service'; import { UiService } from './services/ui/ui.service'; +import { XappOnboarderService } from './services/xapp-onboarder/xapp-onboarder.service'; @NgModule({ @@ -113,7 +115,8 @@ import { UiService } from './services/ui/ui.service'; StatsComponent, StatsDialogComponent, UserComponent, - InstanceSelectorDialogComponent + InstanceSelectorDialogComponent, + OnboardComponent ], imports: [ BrowserModule, @@ -186,7 +189,8 @@ import { UiService } from './services/ui/ui.service'; ErrorDialogService, InstanceSelectorService, InstanceSelectorDialogService, - UiService + UiService, + XappOnboarderService ], bootstrap: [RdComponent] }) diff --git a/dashboard/webapp-frontend/src/app/services/xapp-onboarder/xapp-onboarder.service.spec.ts b/dashboard/webapp-frontend/src/app/services/xapp-onboarder/xapp-onboarder.service.spec.ts new file mode 100644 index 00000000..80cec3a3 --- /dev/null +++ b/dashboard/webapp-frontend/src/app/services/xapp-onboarder/xapp-onboarder.service.spec.ts @@ -0,0 +1,35 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2019 AT&T Intellectual Property + * %% + * 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. + * ========================LICENSE_END=================================== + */ +import { TestBed } from '@angular/core/testing'; + +import { XappOnboarderService } from './xapp-onboarder.service'; + +describe('XappOnboarderService', () => { + let service: XappOnboarderService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(XappOnboarderService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/dashboard/webapp-frontend/src/app/services/xapp-onboarder/xapp-onboarder.service.ts b/dashboard/webapp-frontend/src/app/services/xapp-onboarder/xapp-onboarder.service.ts new file mode 100644 index 00000000..03d45710 --- /dev/null +++ b/dashboard/webapp-frontend/src/app/services/xapp-onboarder/xapp-onboarder.service.ts @@ -0,0 +1,46 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2019 AT&T Intellectual Property + * %% + * 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. + * ========================LICENSE_END=================================== + */ + +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { DashboardService } from '../dashboard/dashboard.service'; +@Injectable({ + providedIn: 'root' +}) +export class XappOnboarderService { + + private component = 'xappobrd'; + + constructor( + private dashboardSvc: DashboardService, + private httpClient: HttpClient + ) { } + + onboardXappFile(descriptor: any, instanceKey: string): Observable> { + const path = this.dashboardSvc.buildPath(this.component, instanceKey, 'onboard'); + return this.httpClient.post(path, descriptor, { observe: 'response' }); + } + + onboardXappURL(descriptor_remote: any, instanceKey: string): Observable> { + const path = this.dashboardSvc.buildPath(this.component, instanceKey, 'onboard','download'); + return this.httpClient.post(path, descriptor_remote, { observe: 'response' }); + } +} diff --git a/docs/release-notes.rst b/docs/release-notes.rst index 200ac4d6..cfbae03b 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -5,9 +5,10 @@ RIC Dashboard Release Notes =========================== -Version 2.1.0, 8 Jun 2020 +Version 2.1.0, 17 Aug 2020 -------------------------- * Add Xapp Onboarder client to backend (`OAM-108 `_) +* Add Xapp Onboarder frontend UI (`OAM-108 `_) Version 2.0.3, 3 Jun 2020 -------------------------- -- 2.16.6