From fa50e55b6e8977ad0a6a28096fe58fb54924ca2b Mon Sep 17 00:00:00 2001 From: "Lott, Christopher (cl778h)" Date: Fri, 12 Jul 2019 14:22:30 -0400 Subject: [PATCH] Add configurable delay to mock endpoints Extend all mocked methods with a configurable call to Thread.sleep() to simulate the delays seen when testing real implementations. Clean up some minor front-end type definitions. Change-Id: Ibd224696649641df27e82888181d89149f47c385 Signed-off-by: Lott, Christopher (cl778h) --- docs/release-notes.rst | 3 +- .../config/A1MediatorMockConfiguration.java | 14 +++- .../dashboard/config/AnrXappMockConfiguration.java | 60 +++++++++++---- .../config/AppManagerMockConfiguration.java | 72 +++++++++++++---- .../config/E2ManagerMockConfiguration.java | 32 ++++++-- .../src/app/anr-xapp/anr-xapp.component.ts | 3 +- .../src/app/app-control/app-control.component.html | 4 +- .../src/app/app-control/app-control.component.ts | 14 ++-- .../src/app/catalog/catalog.component.html | 6 +- .../src/app/catalog/catalog.component.scss | 4 + .../src/app/catalog/catalog.component.ts | 11 +-- webapp-frontend/src/app/interfaces/e2-mgr.types.ts | 9 ++- .../ran-connection-dialog.component.html | 3 +- .../ran-control/ran-connection-dialog.component.ts | 67 ++++++++-------- .../src/app/ran-control/ran-control.component.html | 2 +- .../src/app/ran-control/ran-control.component.ts | 22 +++--- .../src/app/services/anr-xapp/anr-xapp.service.ts | 10 +-- .../src/app/services/app-mgr/app-mgr.service.ts | 6 +- .../src/app/services/ui/confirm-dialog.service.ts | 2 +- webapp-frontend/src/app/user/user.component.html | 89 ++++++++++++---------- webapp-frontend/src/app/user/user.component.scss | 4 + 21 files changed, 285 insertions(+), 152 deletions(-) diff --git a/docs/release-notes.rst b/docs/release-notes.rst index bb84273e..5a3198d1 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -20,13 +20,14 @@ RIC Dashboard Release Notes =========================== -Version 1.2.0, 11 July 2019 +Version 1.2.0, 12 July 2019 --------------------------- * Split URL properties into prefix/suffix parts * Add jacoco plugin to back-end for code coverage * Compile with Java version 11, run with image openjdk:11 * Clean code of issues reported by Sonar * Drop mock RAN names feature that supported R1 testing +* Extend mock endpoints to simulate delay seen in tests Version 1.0.5, 5 July 2019 -------------------------- diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/A1MediatorMockConfiguration.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/A1MediatorMockConfiguration.java index 4b394e5e..351f1143 100644 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/A1MediatorMockConfiguration.java +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/A1MediatorMockConfiguration.java @@ -43,6 +43,8 @@ import org.springframework.http.HttpStatus; public class A1MediatorMockConfiguration { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + // Simulate remote method delay for UI testing + private final int delayMs = 500; public A1MediatorMockConfiguration() { logger.info("Configuring mock A1 Mediator"); @@ -60,8 +62,16 @@ public class A1MediatorMockConfiguration { ApiClient apiClient = apiClient(); A1MediatorApi mockApi = mock(A1MediatorApi.class); when(mockApi.getApiClient()).thenReturn(apiClient); - doAnswer(i -> null).when(mockApi).a1ControllerGetHandler(any(String.class)); - doAnswer(i -> null).when(mockApi).a1ControllerPutHandler(any(String.class), any(Object.class)); + doAnswer(inv -> { + logger.debug("a1ControllerGetHandler sleeping {}", delayMs); + Thread.sleep(delayMs); + return null; + }).when(mockApi).a1ControllerGetHandler(any(String.class)); + doAnswer(inv -> { + logger.debug("a1ControllerPutHandler sleeping {}", delayMs); + Thread.sleep(delayMs); + return null; + }).when(mockApi).a1ControllerPutHandler(any(String.class), any(Object.class)); return mockApi; } diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AnrXappMockConfiguration.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AnrXappMockConfiguration.java index a1e276d5..65960b91 100644 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AnrXappMockConfiguration.java +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AnrXappMockConfiguration.java @@ -51,20 +51,19 @@ public class AnrXappMockConfiguration { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private static final String GNODEB1 = "001EF5:0045FE50"; + private static final String GNODEB2 = "001EF6:0045FE51"; + private static final String GNODEB3 = "001EF7:0045FE52"; // Sonar wants separate declarations private final NeighborCellRelationTable ncrt; private final NeighborCellRelationTable ncrtNodeB1; private final NeighborCellRelationTable ncrtNodeB2; private final NeighborCellRelationTable ncrtNodeB3; - private final GgNodeBTable gNodebTable; - - private static final String GNODEB1 = "001EF5:0045FE50"; - private static final String GNODEB2 = "001EF6:0045FE51"; - private static final String GNODEB3 = "001EF7:0045FE52"; + // Simulate remote method delay for UI testing + private final int delayMs = 500; public AnrXappMockConfiguration() { - logger.info("Configuring mock ANR xApp client"); gNodebTable = new GgNodeBTable(); gNodebTable.addGNodeBIdsItem(GNODEB1).addGNodeBIdsItem(GNODEB2).addGNodeBIdsItem(GNODEB3); @@ -118,16 +117,47 @@ public class AnrXappMockConfiguration { ApiClient apiClient = apiClient(); NcrtApi mockApi = mock(NcrtApi.class); when(mockApi.getApiClient()).thenReturn(apiClient); - when(mockApi.getgNodeB()).thenReturn(gNodebTable); + doAnswer(inv -> { + logger.debug("getgNodeB sleeping {}", delayMs); + Thread.sleep(delayMs); + return gNodebTable; + }).when(mockApi).getgNodeB(); // Swagger sends nulls; front end sends empty strings - when(mockApi.getNcrt((String) isNull(), (String) isNull(), (String) isNull())).thenReturn(ncrt); - when(mockApi.getNcrt(eq(""), any(String.class), any(String.class))).thenReturn(ncrt); - when(mockApi.getNcrt(eq(GNODEB1), any(String.class), any(String.class))).thenReturn(ncrtNodeB1); - when(mockApi.getNcrt(eq(GNODEB2), any(String.class), any(String.class))).thenReturn(ncrtNodeB2); - when(mockApi.getNcrt(eq(GNODEB3), any(String.class), any(String.class))).thenReturn(ncrtNodeB3); - doAnswer(i -> null).when(mockApi).deleteNcrt(any(String.class), any(String.class)); - doAnswer(i -> null).when(mockApi).modifyNcrt(any(String.class), any(String.class), - any(NeighborCellRelationMod.class)); + doAnswer(inv -> { + logger.debug("getNcrt (1) sleeping {}", delayMs); + Thread.sleep(delayMs); + return ncrt; + }).when(mockApi).getNcrt((String) isNull(), (String) isNull(), (String) isNull()); + doAnswer(inv -> { + logger.debug("getNcrt (2) sleeping {}", delayMs); + Thread.sleep(delayMs); + return ncrt; + }).when(mockApi).getNcrt(eq(""), any(String.class), any(String.class)); + doAnswer(inv -> { + logger.debug("getNcrt (3) sleeping {}", delayMs); + Thread.sleep(delayMs); + return ncrtNodeB1; + }).when(mockApi).getNcrt(eq(GNODEB1), any(String.class), any(String.class)); + doAnswer(inv -> { + logger.debug("getNcrt (4) sleeping {}", delayMs); + Thread.sleep(delayMs); + return ncrtNodeB2; + }).when(mockApi).getNcrt(eq(GNODEB2), any(String.class), any(String.class)); + doAnswer(inv -> { + logger.debug("getNcrt (5) sleeping {}", delayMs); + Thread.sleep(delayMs); + return ncrtNodeB3; + }).when(mockApi).getNcrt(eq(GNODEB3), any(String.class), any(String.class)); + doAnswer(inv -> { + logger.debug("deleteNcrt sleeping {}", delayMs); + Thread.sleep(delayMs); + return null; + }).when(mockApi).deleteNcrt(any(String.class), any(String.class)); + doAnswer(inv -> { + logger.debug("modifyNcrt sleeping {}", delayMs); + Thread.sleep(delayMs); + return null; + }).when(mockApi).modifyNcrt(any(String.class), any(String.class), any(NeighborCellRelationMod.class)); return mockApi; } diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AppManagerMockConfiguration.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AppManagerMockConfiguration.java index d97884d7..ef1e9d5d 100644 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AppManagerMockConfiguration.java +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AppManagerMockConfiguration.java @@ -60,6 +60,9 @@ public class AppManagerMockConfiguration { private final AllDeployableXapps availXapps; private final AllDeployedXapps deployedXapps; private final AllXappConfig allXappConfigs; + private final SubscriptionResponse subRes; + // Simulate remote method delay for UI testing + private final int delayMs = 500; public AppManagerMockConfiguration() { logger.info("Configuring mock xApp Manager"); @@ -79,6 +82,7 @@ public class AppManagerMockConfiguration { .status(XappInstance.StatusEnum.RUNNING)); deployedXapps.add(xapp); } + subRes = new SubscriptionResponse().eventType(SubscriptionResponse.EventTypeEnum.ALL).id("subid").version(1); } @Bean @@ -100,19 +104,61 @@ public class AppManagerMockConfiguration { when(mockClient.getStatusCode()).thenReturn(HttpStatus.OK); XappApi mockApi = mock(XappApi.class); when(mockApi.getApiClient()).thenReturn(mockClient); - when(mockApi.getAllXappConfig()).thenReturn(allXappConfigs); - when(mockApi.createXappConfig(any(XAppConfig.class))).thenReturn(allXappConfigs.get(0)); - when(mockApi.modifyXappConfig(any(XAppConfig.class))).thenReturn(allXappConfigs.get(0)); - doAnswer(i -> null).when(mockApi).deleteXappConfig(any(ConfigMetadata.class)); - when(mockApi.deployXapp(any(XAppInfo.class))).thenReturn(deployedXapps.get(0)); - when(mockApi.listAllXapps()).thenReturn(availXapps); - when(mockApi.getAllXapps()).thenReturn(deployedXapps); - when(mockApi.getXappByName(any(String.class))).thenReturn(deployedXapps.get(0)); - doAnswer(i -> null).when(mockApi).undeployXapp(any(String.class)); - SubscriptionResponse subRes = new SubscriptionResponse().eventType(SubscriptionResponse.EventTypeEnum.ALL) - .id("subid").version(1); - when(mockApi.addSubscription(any(SubscriptionRequest.class))).thenReturn(subRes); - doAnswer(i -> null).when(mockApi).deleteSubscription(any(String.class)); + doAnswer(inv -> { + logger.debug("getAllXappConfig sleeping {}", delayMs); + Thread.sleep(delayMs); + return allXappConfigs; + }).when(mockApi).getAllXappConfig(); + doAnswer(inv -> { + logger.debug("createXappConfig sleeping {}", delayMs); + Thread.sleep(delayMs); + return allXappConfigs.get(0); + }).when(mockApi).createXappConfig(any(XAppConfig.class)); + doAnswer(inv -> { + logger.debug("modifyXappConfig sleeping {}", delayMs); + Thread.sleep(delayMs); + return allXappConfigs.get(0); + }).when(mockApi).modifyXappConfig(any(XAppConfig.class)); + doAnswer(inv -> { + logger.debug("deleteXappConfig sleeping {}", delayMs); + Thread.sleep(delayMs); + return null; + }).when(mockApi).deleteXappConfig(any(ConfigMetadata.class)); + doAnswer(inv -> { + logger.debug("deployXapp of {} sleeping {}", inv.getArgument(0), delayMs); + Thread.sleep(delayMs); + return deployedXapps.get(0); + }).when(mockApi).deployXapp(any(XAppInfo.class)); + doAnswer(inv -> { + logger.debug("listAllXapps sleeping {}", delayMs); + Thread.sleep(delayMs); + return availXapps; + }).when(mockApi).listAllXapps(); + doAnswer(inv -> { + logger.debug("getAllXapps sleeping {}", delayMs); + Thread.sleep(delayMs); + return deployedXapps; + }).when(mockApi).getAllXapps(); + doAnswer(inv -> { + logger.debug("getXappByName of {} sleeping {}", inv.getArgument(0), delayMs); + Thread.sleep(delayMs); + return deployedXapps.get(0); + }).when(mockApi).getXappByName(any(String.class)); + doAnswer(inv -> { + logger.debug("undeployXapp of {} sleeping {}", inv.getArgument(0), delayMs); + Thread.sleep(delayMs); + return null; + }).when(mockApi).undeployXapp(any(String.class)); + doAnswer(inv -> { + logger.debug("addSubscription sleeping {}", delayMs); + Thread.sleep(delayMs); + return subRes; + }).when(mockApi).addSubscription(any(SubscriptionRequest.class)); + doAnswer(inv -> { + logger.debug("deleteSubscription sleeping {}", delayMs); + Thread.sleep(delayMs); + return null; + }).when(mockApi).deleteSubscription(any(String.class)); return mockApi; } diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java index 875d01b5..4561dd7e 100644 --- a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java +++ b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java @@ -53,6 +53,8 @@ public class E2ManagerMockConfiguration { private final List nodebIdList; private final GetNodebResponse nodebResponse; + // Simulate remote method delay for UI testing + private final int delayMs = 500; public E2ManagerMockConfiguration() { logger.info("Configuring mock E2 Manager"); @@ -86,11 +88,31 @@ public class E2ManagerMockConfiguration { ApiClient apiClient = apiClient(); NodebApi mockApi = mock(NodebApi.class); when(mockApi.getApiClient()).thenReturn(apiClient); - doAnswer(i -> null).when(mockApi).nodebDelete(); - doAnswer(i -> nodebResponse).when(mockApi).getNb(any(String.class)); - doAnswer(i -> nodebIdList).when(mockApi).getNodebIdList(); - doAnswer(i -> null).when(mockApi).endcSetup(any(SetupRequest.class)); - doAnswer(i -> null).when(mockApi).x2Setup(any(SetupRequest.class)); + doAnswer(inv -> { + logger.debug("nodebDelete sleeping {}", delayMs); + Thread.sleep(delayMs); + return null; + }).when(mockApi).nodebDelete(); + doAnswer(inv -> { + logger.debug("getNb sleeping {}", delayMs); + Thread.sleep(delayMs); + return nodebResponse; + }).when(mockApi).getNb(any(String.class)); + doAnswer(inv -> { + logger.debug("getNodebIdList sleeping {}", delayMs); + Thread.sleep(delayMs); + return nodebIdList; + }).when(mockApi).getNodebIdList(); + doAnswer(inv -> { + logger.debug("endcSetup sleeping {}", delayMs); + Thread.sleep(delayMs); + return null; + }).when(mockApi).endcSetup(any(SetupRequest.class)); + doAnswer(inv -> { + logger.debug("x2Setup sleeping {}", delayMs); + Thread.sleep(delayMs); + return null; + }).when(mockApi).x2Setup(any(SetupRequest.class)); return mockApi; } diff --git a/webapp-frontend/src/app/anr-xapp/anr-xapp.component.ts b/webapp-frontend/src/app/anr-xapp/anr-xapp.component.ts index ba240714..652c955e 100644 --- a/webapp-frontend/src/app/anr-xapp/anr-xapp.component.ts +++ b/webapp-frontend/src/app/anr-xapp/anr-xapp.component.ts @@ -19,6 +19,7 @@ */ import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; +import { HttpResponse } from '@angular/common/http'; import { MatSort } from '@angular/material'; import { MatDialog } from '@angular/material/dialog'; import { fromEvent } from 'rxjs/observable/fromEvent'; @@ -108,7 +109,7 @@ export class AnrXappComponent implements AfterViewInit, OnInit { if (res) { this.anrXappService.deleteNcr(ncr.servingCellNrcgi, ncr.neighborCellNrpci) .subscribe( - response => { + (response: HttpResponse) => { switch (response.status) { case 200: this.notificationService.success('Delete succeeded!'); diff --git a/webapp-frontend/src/app/app-control/app-control.component.html b/webapp-frontend/src/app/app-control/app-control.component.html index 6c8a453d..5c69c2fb 100644 --- a/webapp-frontend/src/app/app-control/app-control.component.html +++ b/webapp-frontend/src/app/app-control/app-control.component.html @@ -55,7 +55,7 @@ - @@ -94,7 +94,7 @@
- +
diff --git a/webapp-frontend/src/app/app-control/app-control.component.ts b/webapp-frontend/src/app/app-control/app-control.component.ts index b172152f..341754b0 100644 --- a/webapp-frontend/src/app/app-control/app-control.component.ts +++ b/webapp-frontend/src/app/app-control/app-control.component.ts @@ -18,6 +18,7 @@ * ========================LICENSE_END=================================== */ import { Component, OnInit, ViewChild } from '@angular/core'; +import { HttpResponse, HttpErrorResponse } from '@angular/common/http'; import { MatSort } from '@angular/material/sort'; import { Router } from '@angular/router'; import { XappControlRow } from '../interfaces/app-mgr.types'; @@ -67,21 +68,24 @@ export class AppControlComponent implements OnInit { } } - undeployApp(app: XappControlRow): void { + onUndeployApp(app: XappControlRow): void { this.confirmDialogService.openConfirmDialog('Are you sure you want to undeploy xApp ' + app.xapp + '?') - .afterClosed().subscribe(res => { + .afterClosed().subscribe( (res: boolean) => { if (res) { this.appMgrSvc.undeployXapp(app.xapp).subscribe( - response => { + ( httpResponse: HttpResponse) => { this.dataSource.loadTable(); - switch (response.status) { + switch (httpResponse.status) { case 200: this.notificationService.success('xApp undeployed successfully!'); break; default: this.notificationService.warn('xApp undeploy failed.'); } - } + }, + ( (error: HttpErrorResponse) => { + this.notificationService.warn(error.message); + }) ); } }); diff --git a/webapp-frontend/src/app/catalog/catalog.component.html b/webapp-frontend/src/app/catalog/catalog.component.html index 2a9b72dd..30896552 100644 --- a/webapp-frontend/src/app/catalog/catalog.component.html +++ b/webapp-frontend/src/app/catalog/catalog.component.html @@ -36,10 +36,10 @@ Action
- -
@@ -57,7 +57,7 @@
- +
diff --git a/webapp-frontend/src/app/catalog/catalog.component.scss b/webapp-frontend/src/app/catalog/catalog.component.scss index 0f9d8889..23184dae 100644 --- a/webapp-frontend/src/app/catalog/catalog.component.scss +++ b/webapp-frontend/src/app/catalog/catalog.component.scss @@ -45,6 +45,10 @@ background-color: transparent; } +.mat-column-action { + max-width: 200px; +} + .catalog-button-row button{ margin-right: 5px; } diff --git a/webapp-frontend/src/app/catalog/catalog.component.ts b/webapp-frontend/src/app/catalog/catalog.component.ts index 97dfd7ca..4eab4083 100644 --- a/webapp-frontend/src/app/catalog/catalog.component.ts +++ b/webapp-frontend/src/app/catalog/catalog.component.ts @@ -25,6 +25,7 @@ import { AppMgrService } from '../services/app-mgr/app-mgr.service'; import { ConfirmDialogService } from './../services/ui/confirm-dialog.service'; import { NotificationService } from './../services/ui/notification.service'; import { CatalogDataSource } from './catalog.datasource'; +import { XMDeployableApp } from '../interfaces/app-mgr.types'; @Component({ selector: 'rd-app-catalog', @@ -53,12 +54,12 @@ export class CatalogComponent implements OnInit { this.errorDiaglogService.displayError(aboutError); } - onDeployApp(name: string): void { - this.confirmDialogService.openConfirmDialog('Deploy application ' + name + '?') - .afterClosed().subscribe( (res: any) => { + onDeployApp(app: XMDeployableApp): void { + this.confirmDialogService.openConfirmDialog('Deploy application ' + app.name + '?') + .afterClosed().subscribe( (res: boolean) => { if (res) { - this.appMgrService.deployXapp(name).subscribe( - (response: HttpResponse) => { + this.appMgrService.deployXapp(app.name).subscribe( + (response: HttpResponse) => { this.notificationService.success('Deploy succeeded!'); }, (error: HttpErrorResponse) => { diff --git a/webapp-frontend/src/app/interfaces/e2-mgr.types.ts b/webapp-frontend/src/app/interfaces/e2-mgr.types.ts index bc29cfe9..4f2cb4a5 100644 --- a/webapp-frontend/src/app/interfaces/e2-mgr.types.ts +++ b/webapp-frontend/src/app/interfaces/e2-mgr.types.ts @@ -23,7 +23,7 @@ export interface E2SetupRequest { ranName: string; ranIp: string; - ranPort: number; + ranPort: string; } export interface E2ErrorResponse { @@ -57,3 +57,10 @@ export interface E2RanDetails { nodebIdentity: E2NodebIdentity; nodebStatus: E2GetNodebResponse; } + +export interface RanDialogFormData { + ranIp: string; + ranName: string; + ranPort: string; + ranType: string; +} diff --git a/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.html b/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.html index 1dac6470..2347a821 100644 --- a/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.html +++ b/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.html @@ -21,7 +21,6 @@
Setup RAN Connection
-
@@ -50,6 +49,6 @@
diff --git a/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.ts b/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.ts index 7f0c368e..25442f77 100644 --- a/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.ts +++ b/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.ts @@ -18,13 +18,14 @@ * ========================LICENSE_END=================================== */ import { Component, OnInit, Inject } from '@angular/core'; +import { HttpResponse, HttpErrorResponse } from '@angular/common/http'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { Observable } from 'rxjs'; import { E2ManagerService } from '../services/e2-mgr/e2-mgr.service'; import { NotificationService } from '../services/ui/notification.service'; import { ErrorDialogService } from '../services/ui/error-dialog.service'; -import { E2SetupRequest } from '../interfaces/e2-mgr.types'; -import { HttpErrorResponse } from '@angular/common/http'; +import { E2SetupRequest, RanDialogFormData } from '../interfaces/e2-mgr.types'; @Component({ selector: 'rd-ran-control-connect-dialog', @@ -35,13 +36,14 @@ import { HttpErrorResponse } from '@angular/common/http'; export class RanControlConnectDialogComponent implements OnInit { public ranDialogForm: FormGroup; + public processing = false; constructor( private dialogRef: MatDialogRef, private service: E2ManagerService, private errorService: ErrorDialogService, - private notifService: NotificationService, - @Inject(MAT_DIALOG_DATA) public data: E2SetupRequest) { + private notifService: NotificationService) { + // opens with empty fields; accepts no data to display } ngOnInit() { @@ -55,64 +57,55 @@ export class RanControlConnectDialogComponent implements OnInit { ranIp: new FormControl('', [Validators.required, Validators.pattern(ipPattern)]), ranPort: new FormControl('', [Validators.required, Validators.pattern(portPattern)]) }); - } onCancel() { - this.dialogRef.close(); + this.dialogRef.close(false); } - public setupConnection = (ranFormValue) => { - if (this.ranDialogForm.valid) { - this.executeSetupConnection(ranFormValue); + setupConnection = (ranFormValue: RanDialogFormData) => { + if (!this.ranDialogForm.valid) { + // should never happen + return; } - } - - private executeSetupConnection = (ranFormValue) => { - let httpErrRes: HttpErrorResponse; - const aboutError = 'RAN Connection Failed: '; + this.processing = true; const setupRequest: E2SetupRequest = { ranName: ranFormValue.ranName, ranIp: ranFormValue.ranIp, ranPort: ranFormValue.ranPort }; + let observable: Observable>; if (ranFormValue.ranType === 'endc') { - this.service.endcSetup(setupRequest).subscribe( - (response: any) => { - this.notifService.success('Endc connect succeeded!'); - this.dialogRef.close(); - }, - (error => { - httpErrRes = error; - this.errorService.displayError(aboutError + httpErrRes.message); - }) - ); + observable = this.service.endcSetup(setupRequest); } else { - this.service.x2Setup(setupRequest).subscribe( - (response: any) => { - this.notifService.success('X2 connect succeeded!'); - this.dialogRef.close(); - }, - (error => { - httpErrRes = error; - this.errorService.displayError(aboutError + httpErrRes.message); - }) - ); + observable = this.service.x2Setup(setupRequest); } + observable.subscribe( + (response: any) => { + this.processing = false; + this.notifService.success('Connect succeeded!'); + this.dialogRef.close(true); + }, + ( (error: HttpErrorResponse) => { + this.processing = false; + this.errorService.displayError('RAN Connection Failed: ' + error.message); + // keep the dialog open + }) + ); } - public hasError(controlName: string, errorName: string) { + hasError(controlName: string, errorName: string) { if (this.ranDialogForm.controls[controlName].hasError(errorName)) { return true; } return false; } - public validateControl(controlName: string) { + validateControl(controlName: string) { if (this.ranDialogForm.controls[controlName].invalid && this.ranDialogForm.controls[controlName].touched) { return true; } return false; } -} // class AppRANConnectDialog +} diff --git a/webapp-frontend/src/app/ran-control/ran-control.component.html b/webapp-frontend/src/app/ran-control/ran-control.component.html index 474542aa..d249d44c 100644 --- a/webapp-frontend/src/app/ran-control/ran-control.component.html +++ b/webapp-frontend/src/app/ran-control/ran-control.component.html @@ -68,7 +68,7 @@
- +
diff --git a/webapp-frontend/src/app/ran-control/ran-control.component.ts b/webapp-frontend/src/app/ran-control/ran-control.component.ts index e911d18d..26665ca6 100644 --- a/webapp-frontend/src/app/ran-control/ran-control.component.ts +++ b/webapp-frontend/src/app/ran-control/ran-control.component.ts @@ -18,6 +18,7 @@ * ========================LICENSE_END=================================== */ import { Component, OnInit } from '@angular/core'; +import { HttpResponse, HttpErrorResponse } from '@angular/common/http'; import { MatDialog } from '@angular/material/dialog'; import { RanControlConnectDialogComponent } from './ran-connection-dialog.component'; import { E2ManagerService } from '../services/e2-mgr/e2-mgr.service'; @@ -25,7 +26,6 @@ import { ErrorDialogService } from '../services/ui/error-dialog.service'; import { ConfirmDialogService } from '../services/ui/confirm-dialog.service'; import { NotificationService } from '../services/ui/notification.service'; import { RANControlDataSource } from './ran-control.datasource'; -import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'rd-ran-control', @@ -49,33 +49,33 @@ export class RanControlComponent implements OnInit { setupRANConnection() { const dialogRef = this.dialog.open(RanControlConnectDialogComponent, { - width: '450px', - data: {} + width: '450px' }); - dialogRef.afterClosed().subscribe(result => { - this.dataSource.loadTable(); + dialogRef.afterClosed().subscribe( (result: boolean) => { + if (result) { + this.dataSource.loadTable(); + } }); } disconnectAllRANConnections() { - let httpErrRes: HttpErrorResponse; const aboutError = 'Disconnect all RAN Connections Failed: '; this.confirmDialogService.openConfirmDialog('Are you sure you want to disconnect all RAN connections?') - .afterClosed().subscribe(res => { + .afterClosed().subscribe( (res: boolean) => { if (res) { this.e2MgrSvc.nodebDelete().subscribe( - response => { + ( response: HttpResponse) => { if (response.status === 200) { this.notificationService.success('Disconnect all RAN Connections Succeeded!'); this.dataSource.loadTable(); } }, - (error => { - httpErrRes = error; - this.errorDialogService.displayError(aboutError + httpErrRes.message); + ( (error: HttpErrorResponse) => { + this.errorDialogService.displayError(aboutError + error.message); }) ); } }); } + } diff --git a/webapp-frontend/src/app/services/anr-xapp/anr-xapp.service.ts b/webapp-frontend/src/app/services/anr-xapp/anr-xapp.service.ts index 759ad7e7..c789261e 100644 --- a/webapp-frontend/src/app/services/anr-xapp/anr-xapp.service.ts +++ b/webapp-frontend/src/app/services/anr-xapp/anr-xapp.service.ts @@ -95,7 +95,7 @@ export class ANRXappService { * @param ggnbId Optional parameter for the gNB ID * @param servingCellNrcgi Serving cell NRCGI * @param neighborCellNrpci Neighbor cell NRPCI - * @returns Neighbor cell relation table, which wraps an array + * @returns Observable of ANR neighbor cell relation array */ getNcrtInfo(ggnodeb: string = '', servingCellNrcgi: string = '', neighborCellNrpci: string = ''): Observable { const url = this.buildPath(this.ncrtPath); @@ -115,9 +115,9 @@ export class ANRXappService { * @param servingCellNrcgi Serving cell NRCGI * @param neighborCellNrpci Neighbor cell NRPCI * @param mod Values to store in the specified relation - * @returns Response code only, no data + * @returns Observable that yields a response code only, no data */ - modifyNcr(servingCellNrcgi: string, neighborCellNrpci: string, mod: ANRNeighborCellRelationMod): Observable { + modifyNcr(servingCellNrcgi: string, neighborCellNrpci: string, mod: ANRNeighborCellRelationMod): Observable { const url = this.buildPath(this.ncrtPath, this.servingPath, servingCellNrcgi, this.neighborPath, neighborCellNrpci); return this.httpClient.put(url, mod, { observe: 'response' }); } @@ -126,9 +126,9 @@ export class ANRXappService { * Deletes neighbor cell relation based on Serving Cell NRCGI and Neighbor Cell NRPCI * @param servingCellNrcgi Serving cell NRCGI * @param neighborCellNrpci Neighbor cell NRPCI - * @returns Response code only, no data + * @returns Observable that yields a response code only, no data */ - deleteNcr(servingCellNrcgi: string, neighborCellNrpci: string): Observable { + deleteNcr(servingCellNrcgi: string, neighborCellNrpci: string): Observable { const url = this.buildPath(this.ncrtPath, this.servingPath, servingCellNrcgi, this.neighborPath, neighborCellNrpci); return this.httpClient.delete(url, { observe: 'response' }); } diff --git a/webapp-frontend/src/app/services/app-mgr/app-mgr.service.ts b/webapp-frontend/src/app/services/app-mgr/app-mgr.service.ts index 10683aef..13df94c2 100644 --- a/webapp-frontend/src/app/services/app-mgr/app-mgr.service.ts +++ b/webapp-frontend/src/app/services/app-mgr/app-mgr.service.ts @@ -18,7 +18,7 @@ * ========================LICENSE_END=================================== */ import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; +import { HttpClient, HttpResponse } from '@angular/common/http'; import { Observable } from 'rxjs'; import { XMXappInfo, XMDeployableApp, XMDeployedApp } from '../../interfaces/app-mgr.types'; @@ -39,12 +39,12 @@ export class AppMgrService { return this.httpClient.get(this.basePath); } - deployXapp(name: string) { + deployXapp(name: string): Observable> { const xappInfo: XMXappInfo = { name: name }; return this.httpClient.post(this.basePath, xappInfo, { observe: 'response' }); } - undeployXapp(name: string) { + undeployXapp(name: string): Observable> { return this.httpClient.delete((this.basePath + '/' + name), { observe: 'response' }); } diff --git a/webapp-frontend/src/app/services/ui/confirm-dialog.service.ts b/webapp-frontend/src/app/services/ui/confirm-dialog.service.ts index 2c38c319..10365046 100644 --- a/webapp-frontend/src/app/services/ui/confirm-dialog.service.ts +++ b/webapp-frontend/src/app/services/ui/confirm-dialog.service.ts @@ -29,7 +29,7 @@ export class ConfirmDialogService { constructor(private dialog: MatDialog) { } - openConfirmDialog(msg) { + openConfirmDialog(msg: string) { return this.dialog.open(ConfirmDialogComponent, { width: '480px', position: { top: '100px' }, diff --git a/webapp-frontend/src/app/user/user.component.html b/webapp-frontend/src/app/user/user.component.html index d32a3f25..b8cd9cbf 100644 --- a/webapp-frontend/src/app/user/user.component.html +++ b/webapp-frontend/src/app/user/user.component.html @@ -17,49 +17,60 @@ limitations under the License. ========================LICENSE_END=================================== --> -
-

Users

- -
- -
- +
+

Users

+ +
+ +
+
+ + + ID + {{element.id}} + + + + First Name + {{element.firstName}} + - - ID - {{element.id}} - + + Last Name + {{element.lastName}} + - - First Name - {{element.firstName}} - + + Status + {{element.status}} + - - Last Name - {{element.lastName}} - + + Action + +
+ + +
+
+
- - Status - {{element.status}} - + + No records found. + - - Action - -
- - -
-
-
+ + + - - -
+ + +
+
+ +
\ No newline at end of file diff --git a/webapp-frontend/src/app/user/user.component.scss b/webapp-frontend/src/app/user/user.component.scss index 4d06c6d9..80ddf638 100644 --- a/webapp-frontend/src/app/user/user.component.scss +++ b/webapp-frontend/src/app/user/user.component.scss @@ -49,3 +49,7 @@ .user-button-row button { margin-right: 5px; } + +.display-none { + display: none; +} -- 2.16.6