Add AC xApp control screen 16/216/3
authorLott, Christopher (cl778h) <cl778h@att.com>
Thu, 30 May 2019 13:17:43 +0000 (09:17 -0400)
committerLott, Christopher (cl778h) <cl778h@att.com>
Fri, 31 May 2019 15:21:29 +0000 (11:21 -0400)
Change-Id: I55f0cda8e9207936390aa59b0852a816cce2f2dd
Signed-off-by: Lott, Christopher (cl778h) <cl778h@att.com>
17 files changed:
docs/release-notes.rst
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/AcXappController.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/AnrXappController.java
webapp-frontend/src/app/ac-xapp/ac-xapp.component.html [new file with mode: 0644]
webapp-frontend/src/app/ac-xapp/ac-xapp.component.scss [new file with mode: 0644]
webapp-frontend/src/app/ac-xapp/ac-xapp.component.spec.ts [new file with mode: 0644]
webapp-frontend/src/app/ac-xapp/ac-xapp.component.ts [new file with mode: 0644]
webapp-frontend/src/app/anr-xapp/anr-edit-ncr-dialog.component.scss
webapp-frontend/src/app/anr-xapp/anr-edit-ncr-dialog.component.ts
webapp-frontend/src/app/app-routing.module.ts
webapp-frontend/src/app/app.module.ts
webapp-frontend/src/app/control/control.component.ts
webapp-frontend/src/app/ran-connection/ran-connection.component.ts
webapp-frontend/src/app/services/ac-xapp/ac-xapp.service.spec.ts
webapp-frontend/src/app/services/ac-xapp/ac-xapp.service.ts
webapp-frontend/src/app/services/anr-xapp/anr-xapp.service.spec.ts
webapp-frontend/src/app/services/anr-xapp/anr-xapp.service.ts

index c50e4cc..4ed30c7 100644 (file)
@@ -22,6 +22,7 @@ RIC Dashboard Release Notes
 
 Version 1.0.4, 30 May 2019
 --------------------------
+* Add AC xApp neighbor control screen
 * Add ANR xApp neighbor cell relation table
 * Drop the pendulum xApp control screen
 * Add column sorting on xApp catalog and xApp control 
index 69864d9..3782656 100644 (file)
@@ -44,7 +44,7 @@ import io.swagger.annotations.ApiParam;
 
 /**
  * Provides methods to manage policies of the Admission Control xApp, which
- * initially defines just one. All requests go via the A1 Mediatior.
+ * initially defines just one. All requests go via the A1 Mediator.
  */
 @RestController
 @RequestMapping(value = DashboardConstants.ENDPOINT_PREFIX + "/xapp/ac", produces = MediaType.APPLICATION_JSON_VALUE)
@@ -75,18 +75,18 @@ public class AcXappController {
         */
        @ApiOperation(value = "Gets the admission control policy for AC xApp via the A1 Mediator")
        @RequestMapping(value = "admctrl", method = RequestMethod.GET)
-       public Object getAdmissionControlPolicy() {
+       public Object getAdmissionControlPolicy(HttpServletResponse response) {
                logger.debug("getAdmissionControlPolicy");
-               a1MediatorApi.a1ControllerGetHandler(AC_CONTROL_NAME);
+               response.setStatus(HttpServletResponse.SC_NOT_IMPLEMENTED);
                return null;
        }
 
        /*
-        * This controller is deliberately kept ignorant of the
-        * ACAdmissionIntervalControl Typescript interface.
+        * This controller is deliberately kept ignorant of the data expected by AC. The
+        * fields are defined in the ACAdmissionIntervalControl Typescript interface.
         */
        @ApiOperation(value = "Sets the admission control policy for AC xApp via the A1 Mediator")
-       @RequestMapping(value = "admctrl", method = RequestMethod.PUT)
+       @RequestMapping(value = "catime", method = RequestMethod.PUT)
        public void setAdmissionControlPolicy(@ApiParam(value = "Admission control policy") @RequestBody JsonNode acPolicy, //
                        HttpServletResponse response) {
                logger.debug("setAdmissionControlPolicy {}", acPolicy);
index 5b1a6e2..dae8ae2 100644 (file)
@@ -105,11 +105,11 @@ public class AnrXappController {
 
        @ApiOperation(value = "Returns neighbor cell relation table for all gNodeBs or based on query parameters", response = NeighborCellRelationTable.class)
        @RequestMapping(value = "/ncrt", method = RequestMethod.GET)
-       public NeighborCellRelationTable getNcrtInfo( //
+       public NeighborCellRelationTable getNcrt( //
                        @RequestParam(name = QP_NODEB, required = false) String ggnbId, //
                        @RequestParam(name = QP_SERVING, required = false) String servingCellNrcgi, //
                        @RequestParam(name = QP_NEIGHBOR, required = false) String neighborCellNrpci) {
-               logger.debug("getNcrtInfo: ggnbid {}, servingCellNrpci {}, neighborCellNrcgi {}", ggnbId, servingCellNrcgi,
+               logger.debug("getNcrt: ggnbid {}, servingCellNrpci {}, neighborCellNrcgi {}", ggnbId, servingCellNrcgi,
                                neighborCellNrpci);
                return ncrtApi.getNcrt(ggnbId, servingCellNrcgi, neighborCellNrpci);
        }
diff --git a/webapp-frontend/src/app/ac-xapp/ac-xapp.component.html b/webapp-frontend/src/app/ac-xapp/ac-xapp.component.html
new file mode 100644 (file)
index 0000000..f8125f5
--- /dev/null
@@ -0,0 +1,56 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property and Nokia
+  %%
+  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===================================
+  -->
+<div class="ac__section">
+  <h3 class="ac__header">AC xApp Policy</h3>
+
+  <form [formGroup]="acForm" novalidate autocomplete="off" (ngSubmit)="updateAc(acForm.value)">
+    <div name="enforce">
+      <mat-checkbox formControlName="enforce">Enforce</mat-checkbox>
+    </div>
+    <mat-form-field class="input-display-block">
+      <input matInput type="text" placeholder="Window length" formControlName="windowLength">
+      <mat-hint align="end">Sliding window length in minutes for measurement, range 1..60.</mat-hint>
+      <mat-error *ngIf="validateControl('windowLength') && hasError('windowLength', 'required')">Number is required
+      </mat-error>
+      <mat-error *ngIf="hasError('windowLength', 'pattern')">Valid number is required</mat-error>
+    </mat-form-field>
+    <mat-form-field class="input-display-block">
+      <input matInput type="text" placeholder="Blocking rate" formControlName="blockingRate">
+      <mat-hint align="end">Connections to block if above trigger threshold, range 1..100.</mat-hint>
+      <mat-error *ngIf="validateControl('blockingRate') && hasError('blockingRate', 'required')">Number is required
+      </mat-error>
+      <mat-error *ngIf="hasError('blockingRate', 'pattern')">Valid number is required</mat-error>
+    </mat-form-field>
+    <mat-form-field class="input-display-block">
+      <input matInput type="text" placeholder="Trigger threshold" formControlName="triggerThreshold">
+      <mat-hint align="end">Number of events in window to trigger blocking, minimum 1.</mat-hint>
+      <mat-error *ngIf="validateControl('triggerThreshold') && hasError('triggerThreshold', 'required')">Number is
+        required</mat-error>
+      <mat-error *ngIf="hasError('triggerThreshold', 'pattern')">Valid number is required</mat-error>
+    </mat-form-field>
+    <div class="input-display-block">
+      <button class="mat-raised-button mat-primary update-button" [disabled]="!acForm.valid">Update</button>
+    </div>
+    <div class="input-display-block">
+      <span class="version__text">AC API version {{acVersion}}</span>
+    </div>
+</form>
+
+</div>
\ No newline at end of file
diff --git a/webapp-frontend/src/app/ac-xapp/ac-xapp.component.scss b/webapp-frontend/src/app/ac-xapp/ac-xapp.component.scss
new file mode 100644 (file)
index 0000000..42bf59c
--- /dev/null
@@ -0,0 +1,49 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property and Nokia
+ * %%
+ * 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===================================
+ */
+
+ .ac__section {
+    position: relative;
+    top: -50px;
+}
+
+.ac__header {
+    text-align: center;
+    color: #432c85;
+    font-size: 50px;
+    font-weight: 200;
+    letter-spacing: .1em;
+    transform: translate(149 56);
+}
+
+ /* used to place form fields on separate lines/rows */
+.input-display-block {
+  display: block;
+  width: 400px;
+}
+
+.version__text {
+  color: gray;
+  font-size: 10px;
+}
+
+.update-button {
+  margin-top: 10px;
+  float: right;
+}
diff --git a/webapp-frontend/src/app/ac-xapp/ac-xapp.component.spec.ts b/webapp-frontend/src/app/ac-xapp/ac-xapp.component.spec.ts
new file mode 100644 (file)
index 0000000..d42065f
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property and Nokia
+ * %%
+ * 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 { AcXappComponent } from './ac-xapp.component';
+
+describe('AcXappComponent', () => {
+  let component: AcXappComponent;
+  let fixture: ComponentFixture<AcXappComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ AcXappComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(AcXappComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/webapp-frontend/src/app/ac-xapp/ac-xapp.component.ts b/webapp-frontend/src/app/ac-xapp/ac-xapp.component.ts
new file mode 100644 (file)
index 0000000..a0b4327
--- /dev/null
@@ -0,0 +1,88 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property and Nokia
+ * %%
+ * 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, OnInit } from '@angular/core';
+import { FormGroup, FormControl, Validators } from '@angular/forms';
+import { ACAdmissionIntervalControl, ACAdmissionIntervalControlAck } from '../interfaces/ac-xapp.types';
+import { ACXappService } from '../services/ac-xapp/ac-xapp.service';
+import { ErrorDialogService } from '../services/ui/error-dialog.service';
+import { NotificationService } from './../services/ui/notification.service';
+
+@Component({
+  selector: 'app-ac-xapp',
+  templateUrl: './ac-xapp.component.html',
+  styleUrls: ['./ac-xapp.component.scss']
+})
+export class AcXappComponent implements OnInit {
+
+  private acForm: FormGroup;
+
+  // this is probably the A1 version string
+  acVersion: string;
+
+  constructor(
+    private acXappService: ACXappService,
+    private errorDialogService: ErrorDialogService,
+    private notificationService: NotificationService) { }
+
+  ngOnInit() {
+    const windowLengthPattern = /^([0-9]{1}|[1-5][0-9]{1}|60)$/;
+    const blockingRatePattern = /^([0-9]{1,2}|100)$/;
+    const triggerPattern = /^([0-9]+)$/;
+    // No way to fetch current settings via A1 at present
+    this.acForm = new FormGroup({
+      enforce: new FormControl(true,  [Validators.required]),
+      windowLength: new FormControl('', [Validators.required, Validators.pattern(windowLengthPattern)]),
+      blockingRate: new FormControl('', [Validators.required, Validators.pattern(blockingRatePattern)]),
+      triggerThreshold: new FormControl('', [Validators.required, Validators.pattern(triggerPattern)])
+    });
+    this.acXappService.getVersion().subscribe((res: string) => this.acVersion = res);
+  }
+
+  updateAc = (acFormValue: ACAdmissionIntervalControl) => {
+    if (this.acForm.valid) {
+      this.acXappService.putPolicy(acFormValue).subscribe(
+        response => {
+          if (response.status === 200 ) {
+            this.notificationService.success('AC update policy succeeded!');
+          }
+        },
+        (error => {
+          this.errorDialogService.displayError('AC update policy failed: ' + error.message);
+        })
+      );
+    }
+  }
+
+  hasError(controlName: string, errorName: string) {
+    if (this.acForm.controls[controlName].hasError(errorName)) {
+      return true;
+    }
+    return false;
+  }
+
+  validateControl(controlName: string) {
+    if (this.acForm.controls[controlName].invalid && this.acForm.controls[controlName].touched) {
+      return true;
+    }
+    return false;
+  }
+
+}
index 400600c..b0a8a94 100644 (file)
@@ -20,5 +20,5 @@
 
  /* used to place form fields on separate lines/rows in dialog */
 .input-display-block {
-    display: block;
-  }
\ No newline at end of file
+  display: block;
+}
index 2857f55..046a624 100644 (file)
@@ -23,7 +23,6 @@ import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
 import { ANRXappService } from '../services/anr-xapp/anr-xapp.service';
 import { ErrorDialogService } from '../services/ui/error-dialog.service';
 import { ANRNeighborCellRelation, ANRNeighborCellRelationMod } from '../interfaces/anr-xapp.types';
-import { modelGroupProvider } from '@angular/forms/src/directives/ng_model_group';
 
 @Component({
     selector: 'app-ncr-edit-dialog',
@@ -37,10 +36,9 @@ export class ANREditNCRDialogComponent implements OnInit {
 
     constructor(
         private dialogRef: MatDialogRef<ANREditNCRDialogComponent>,
-        private dataService: ANRXappService, private errorService: ErrorDialogService,
-        @Inject(MAT_DIALOG_DATA) private data: ANRNeighborCellRelation) {
-        console.log('constructed with data ' + data);
-    }
+        private dataService: ANRXappService,
+        private errorService: ErrorDialogService,
+        @Inject(MAT_DIALOG_DATA) private data: ANRNeighborCellRelation) { }
 
     ngOnInit() {
         const namePattern = /^([A-Z])+([0-9])+$/;
@@ -59,31 +57,31 @@ export class ANREditNCRDialogComponent implements OnInit {
     }
 
     modifyNcr = (ncrFormValue: ANRNeighborCellRelation) => {
-      if (this.ncrDialogForm.valid) {
-        const ncrm = {} as ANRNeighborCellRelationMod;
-        // there must be a btter way
-        ncrm.neighborCellNrcgi = ncrFormValue.neighborCellNrcgi;
-        ncrm.neighborCellNrpci = ncrFormValue.neighborCellNrpci;
-        ncrm.flagNoHo = ncrFormValue.flagNoHo;
-        ncrm.flagNoXn = ncrFormValue.flagNoXn;
-        ncrm.flagNoRemove = ncrFormValue.flagNoRemove;
-        this.dataService.modifyNcr(ncrFormValue.servingCellNrcgi, ncrFormValue.neighborCellNrpci, ncrm).subscribe((val: any[]) => {},
-            (error => {
-                this.errorService.displayError('NCR update failed: ' + error.message);
-            })
-        );
-        this.dialogRef.close();
-      }
+        if (this.ncrDialogForm.valid) {
+            const ncrm = {} as ANRNeighborCellRelationMod;
+            // there must be a better way
+            ncrm.neighborCellNrcgi = ncrFormValue.neighborCellNrcgi;
+            ncrm.neighborCellNrpci = ncrFormValue.neighborCellNrpci;
+            ncrm.flagNoHo = ncrFormValue.flagNoHo;
+            ncrm.flagNoXn = ncrFormValue.flagNoXn;
+            ncrm.flagNoRemove = ncrFormValue.flagNoRemove;
+            this.dataService.modifyNcr(ncrFormValue.servingCellNrcgi, ncrFormValue.neighborCellNrpci, ncrm).subscribe((val: any[]) => { },
+                (error => {
+                    this.errorService.displayError('NCR update failed: ' + error.message);
+                })
+            );
+            this.dialogRef.close();
+        }
     }
 
-    public hasError(controlName: string, errorName: string) {
+    hasError(controlName: string, errorName: string) {
         if (this.ncrDialogForm.controls[controlName].hasError(errorName)) {
-          return true;
+            return true;
         }
         return false;
     }
 
-    public validateControl(controlName: string) {
+    validateControl(controlName: string) {
         if (this.ncrDialogForm.controls[controlName].invalid && this.ncrDialogForm.controls[controlName].touched) {
             return true;
         }
index 130703c..10f329e 100644 (file)
@@ -26,6 +26,7 @@ import { ControlComponent } from './control/control.component';
 import { RANConnectionComponent } from './ran-connection/ran-connection.component';
 import { StatsComponent } from './stats/stats.component';
 import { AdminComponent } from './admin/admin.component';
+import { AcXappComponent } from './ac-xapp/ac-xapp.component';
 import { AnrXappComponent } from './anr-xapp/anr-xapp.component';
 
 const routes: Routes = [
@@ -36,6 +37,7 @@ const routes: Routes = [
     {path: 'ran-connection', component: RANConnectionComponent},
     {path: 'stats', component: StatsComponent},
     {path: 'admin', component: AdminComponent},
+    {path: 'ac', component: AcXappComponent},
     {path: 'anr', component: AnrXappComponent},
 ];
 
index ab3afd0..b170af3 100644 (file)
@@ -61,28 +61,30 @@ import { FooterComponent } from './footer/footer.component';
 import { AnrXappComponent } from './anr-xapp/anr-xapp.component';
 import { ErrorDialogComponent } from './ui/error-dialog/error-dialog.component';
 import { ErrorDialogService } from './services/ui/error-dialog.service';
+import { AcXappComponent } from './ac-xapp/ac-xapp.component';
 
 @NgModule({
   declarations: [
+    AcXappComponent,
+    AdminComponent,
+    ANREditNCRDialogComponent,
+    AnrXappComponent,
     AppComponent,
-    LoginComponent,
     CatalogComponent,
-    SidenavListComponent,
     CatalogCardComponent,
+    ConfigEventComponent,
+    ConfirmDialogComponent,
     ControlCardComponent,
-    StatCardComponent,
     ControlComponent,
-    RANConnectionComponent,
-    StatsComponent,
-    AdminComponent,
+    ErrorDialogComponent,
+    FooterComponent,
+    LoginComponent,
     ModalEventComponent,
-    ConfigEventComponent,
-    AnrXappComponent,
+    RANConnectionComponent,
     RANConnectionDialogComponent,
-    ANREditNCRDialogComponent,
-    ConfirmDialogComponent,
-    FooterComponent,
-    ErrorDialogComponent
+    SidenavListComponent,
+    StatCardComponent,
+    StatsComponent
   ],
     imports: [
     AppRoutingModule,
index 755625c..8835946 100644 (file)
@@ -53,8 +53,11 @@ export class ControlComponent implements OnInit {
   }
 
   controlApp(app: XappControlRow): void {
+    const acXappPattern =  /[Aa][Dd][Mm][Ii][Ss]{2}[Ii][Oo][Nn]/;
     const anrXappPattern = /[Aa][Nn][Rr]/;
-    if (anrXappPattern.test(app.xapp)) {
+    if (acXappPattern.test(app.xapp)) {
+      this.router.navigate(['/ac']);
+    } else if (anrXappPattern.test(app.xapp)) {
       this.router.navigate(['/anr']);
     } else {
       this.errorDialogService.displayError('No control available for ' + app.xapp + ' (yet)');
index ee1d4c6..932bca6 100644 (file)
@@ -24,11 +24,8 @@ import { E2ManagerService } from '../services/e2-mgr/e2-mgr.service';
 import { ErrorDialogService } from '../services/ui/error-dialog.service';
 import { ConfirmDialogService } from './../services/ui/confirm-dialog.service';
 import { NotificationService } from './../services/ui/notification.service';
-import { E2SetupRequest } from '../interfaces/e2-mgr.types';
 import { RANConnectionDataSource } from './ran-connection.datasource';
 import { HttpErrorResponse } from '@angular/common/http';
-import { Observable } from 'rxjs';
-
 
 @Component({
   selector: 'app-ran-connection',
@@ -39,8 +36,10 @@ export class RANConnectionComponent implements OnInit {
   displayedColumns: string[] = ['requestType', 'ranName', 'ranIp', 'ranPort', 'responseCode', 'timeStamp'];
   dataSource: RANConnectionDataSource;
 
-  constructor(private e2MgrSvc: E2ManagerService, private errorSvc: ErrorDialogService,
-    private confirmDialogService: ConfirmDialogService, private notification: NotificationService,
+  constructor(private e2MgrSvc: E2ManagerService,
+    private errorSvc: ErrorDialogService,
+    private confirmDialogService: ConfirmDialogService,
+    private notification: NotificationService,
     public dialog: MatDialog) { }
 
   ngOnInit() {
index 669f261..008538f 100644 (file)
  */
 import { TestBed } from '@angular/core/testing';
 
-import { AcXappService } from './ac-xapp.service';
+import { ACXappService } from './ac-xapp.service';
 
-describe('AcXappService', () => {
+describe('ACXappService', () => {
   beforeEach(() => TestBed.configureTestingModule({}));
 
   it('should be created', () => {
-    const service: AcXappService = TestBed.get(AcXappService);
+    const service: ACXappService = TestBed.get(ACXappService);
     expect(service).toBeTruthy();
   });
 });
index 740fcbc..907c325 100644 (file)
  import { Injectable } from '@angular/core';
  import { HttpClient } from '@angular/common/http';
  import { Observable } from 'rxjs';
+ import { map } from 'rxjs/operators';
 import { ACAdmissionIntervalControl, ACAdmissionIntervalControlAck } from '../../interfaces/ac-xapp.types';
 import { DashboardSuccessTransport } from '../../interfaces/dashboard.types';
 
+/**
+ * Services for calling the Dashboard's AC endpoints.
+ */
 @Injectable({
   providedIn: 'root'
 })
-export class AcXappService {
+export class ACXappService {
+
+  private basePath = 'api/xapp/ac';
 
-  private basePath = 'api/xapp/ac/';
+  private buildPath(...args: any[]) {
+    let result = this.basePath;
+    args.forEach(part => {
+      result = result + '/' + part;
+    });
+    return result;
+  }
 
   constructor(private httpClient: HttpClient) {
     // injects to variable httpClient
   }
 
   /**
-   * Gets A1 Mediator client version details
-   * @returns Observable that should yield a SuccessTransport object
+   * Gets version details
+   * @returns Observable that should yield a String
    */
-  getVersion() {
-    // Remember that AC traffic goes via A1!
-    return this.httpClient.get<DashboardSuccessTransport>(this.basePath + 'version');
+  getVersion(): Observable<string> {
+    const url = this.buildPath('version');
+    return this.httpClient.get<DashboardSuccessTransport>(url).pipe(
+      // Extract the string here
+      map(res => res['data'])
+    );
   }
 
   /**
-   * Puts control admission time parameters to AC via A1
+   * Puts admission control parameters.
    * @param policy an instance of ACAdmissionIntervalControl
-   * @returns Observable that should yield an ACAdmissionIntervalControlAck
+   * @returns Observable that should yield a response code, no data
    */
-  putCaTime(policy: ACAdmissionIntervalControl): Observable<ACAdmissionIntervalControlAck> {
-    return this.httpClient.put<ACAdmissionIntervalControlAck>(this.basePath + 'catime', policy);
+  putPolicy(policy: ACAdmissionIntervalControl): Observable<any> {
+    const url = this.buildPath('catime');
+    return this.httpClient.put<ACAdmissionIntervalControlAck>(url, policy, { observe: 'response' });
   }
 
 }
index a36dd8b..ea0cb22 100644 (file)
 
  import { TestBed } from '@angular/core/testing';
 
-import { AnrXappService } from './anr-xapp.service';
+import { ANRXappService } from './anr-xapp.service';
 
-describe('AnrXappService', () => {
+describe('ANRXappService', () => {
   beforeEach(() => TestBed.configureTestingModule({}));
 
   it('should be created', () => {
-    const service: AnrXappService = TestBed.get(AnrXappService);
+    const service: ANRXappService = TestBed.get(ANRXappService);
     expect(service).toBeTruthy();
   });
 });
index a2dfb75..759ad7e 100644 (file)
@@ -50,7 +50,7 @@ export class ANRXappService {
 
   /**
    * Gets ANR xApp client version details
-   * @returns Observable that should yield a DashboardSuccessTransport
+   * @returns Observable that should yield a String
    */
   getVersion(): Observable<string> {
     const url = this.buildPath('version');
@@ -66,7 +66,7 @@ export class ANRXappService {
    */
   getHealthAlive(): Observable<any> {
     const url = this.buildPath('health/alive');
-    return this.httpClient.get(url);
+    return this.httpClient.get(url, { observe: 'response' });
   }
 
   /**
@@ -75,13 +75,13 @@ export class ANRXappService {
    */
   getHealthReady(): Observable<any> {
     const url = this.buildPath('health/ready');
-    return this.httpClient.get(url);
+    return this.httpClient.get(url, { observe: 'response' });
   }
 
-    /**
  * Gets ANR xApp client version details
-   * @returns Observable that should yield a DashboardSuccessTransport
  */
+/**
* Gets array of gNodeB IDs
+ * @returns Observable that should yield a string array
+ */
   getgNodeBs(): Observable<string[]> {
     const url = this.buildPath('gnodebs');
     return this.httpClient.get<string[]>(url).pipe(