Merge "Tweaks for Policy Control UI"
authorPatrik Buhr <patrik.buhr@est.tech>
Thu, 15 Apr 2021 09:56:15 +0000 (09:56 +0000)
committerGerrit Code Review <gerrit@o-ran-sc.org>
Thu, 15 Apr 2021 09:56:15 +0000 (09:56 +0000)
13 files changed:
webapp-frontend/src/app/app.module.ts
webapp-frontend/src/app/interceptor.mock.ts
webapp-frontend/src/app/mock/policy-type0.json [new file with mode: 0644]
webapp-frontend/src/app/mock/policy-types.json
webapp-frontend/src/app/mock/policytypes.json
webapp-frontend/src/app/mock/ric1.json
webapp-frontend/src/app/policy/policy-control.component.html
webapp-frontend/src/app/policy/policy-control.component.spec.ts
webapp-frontend/src/app/policy/policy-control.component.ts
webapp-frontend/src/app/policy/policy-instance/policy-instance.component.html
webapp-frontend/src/app/policy/policy-instance/policy-instance.component.ts
webapp-frontend/src/app/policy/policy-type/policy-type.component.html
webapp-frontend/src/app/policy/policy-type/policy-type.component.scss

index a8cbb2c..adca33a 100644 (file)
@@ -22,8 +22,9 @@
 import { BrowserModule } from '@angular/platform-browser';
 import { MatDialogModule } from '@angular/material/dialog';
 import { MatIconModule } from '@angular/material/icon';
-import {MatListModule} from '@angular/material/list';
+import { MatListModule} from '@angular/material/list';
 import { MatSidenavModule } from '@angular/material/sidenav';
+import { MatTooltipModule } from '@angular/material/tooltip';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
 import { NgModule } from '@angular/core';
@@ -65,6 +66,7 @@ export const isMock = environment.mock;
     MatListModule,
     MatSidenavModule,
     MatSlideToggleModule,
+    MatTooltipModule,
     MaterialDesignFrameworkModule,
     MDBBootstrapModule.forRoot(),
     PolicyModule,
index 6fc5c14..ad0d080 100644 (file)
@@ -37,6 +37,7 @@ import * as eiproducerstatus1 from './mock/ei-producer-status1.json';
 import * as eiproducerstatus2 from './mock/ei-producer-status2.json';
 import * as policytypesList from './mock/policy-types.json';
 import * as policytypes1 from './mock/policy-type1.json';
+import * as policytypes0 from './mock/policy-type0.json';
 import * as policyinstanceedit from './mock/policy-instance-edit.json';
 import * as ric1 from './mock/ric1.json';
 import * as ric2 from './mock/ric2.json';
@@ -50,6 +51,10 @@ const urls = [
         url: '/a1-policy/v2/policy-types/1',
         json: policytypes1
     },
+    {
+        url: '/a1-policy/v2/policy-types/0',
+        json: policytypes0
+    },
     {
         url: '/a1-policy/v2/policies?policytype_id=',
         json: noTypePolicies
@@ -143,12 +148,19 @@ const urls = [
 @Injectable()
 export class HttpMockRequestInterceptor implements HttpInterceptor {
     constructor(private injector: Injector) { }
+    private numberOfTypes = 0;
 
     intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
         if (request.method === "PUT" && request.url.includes("policies")) {
             console.log('Answered PUT policy ', request.url, request.body);
             return of(new HttpResponse({ status: 200 }));
         }
+        if (request.url === "/a1-policy/v2/policy-types" && this.numberOfTypes > 0) {
+            this.numberOfTypes = 0;
+            return of(new HttpResponse({status: 200, body:JSON.parse('{"policytype_ids": ["","1"]}')}));
+        } else {
+            this.numberOfTypes = 1;
+        }
         for (const element of urls) {
             if (request.url === element.url) {
                 console.log('Loaded from stub json : ' + request.url);
diff --git a/webapp-frontend/src/app/mock/policy-type0.json b/webapp-frontend/src/app/mock/policy-type0.json
new file mode 100644 (file)
index 0000000..a3a03b8
--- /dev/null
@@ -0,0 +1,43 @@
+{
+  "policy_schema": {
+    "$schema": "http://json-schema.org/draft-07/schema#",
+    "description": "Type 0 policy type (no instances)",
+    "additionalProperties": false,
+    "title": "0",
+    "type": "object",
+    "properties": {
+      "qosObjectives": {
+        "additionalProperties": false,
+        "type": "object",
+        "properties": {
+          "priorityLevel": {
+            "type": "number"
+          }
+        },
+        "required": [
+          "priorityLevel"
+        ]
+      },
+      "scope": {
+        "additionalProperties": false,
+        "type": "object",
+        "properties": {
+          "qosId": {
+            "type": "string"
+          },
+          "ueId": {
+            "type": "string"
+          }
+        },
+        "required": [
+          "ueId",
+          "qosId"
+        ]
+      }
+    },
+    "required": [
+      "scope",
+      "qosObjectives"
+    ]
+  }
+}
\ No newline at end of file
index 9bad9ad..c65b820 100644 (file)
@@ -1,6 +1,7 @@
 {
   "policytype_ids": [
     "",
-    "1"
+    "1",
+    "0"
   ]
 }
\ No newline at end of file
index 89a7d0b..a59e12d 100644 (file)
@@ -6,5 +6,9 @@
   {
     "name": "1",
     "schema": "{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"description\":\"Type 1 policy type\",\"additionalProperties\":false,\"title\":\"1\",\"type\":\"object\",\"properties\":{\"qosObjectives\":{\"additionalProperties\":false,\"type\":\"object\",\"properties\":{\"priorityLevel\":{\"type\":\"number\"}},\"required\":[\"priorityLevel\"]},\"scope\":{\"additionalProperties\":false,\"type\":\"object\",\"properties\":{\"qosId\":{\"type\":\"string\"},\"ueId\":{\"type\":\"string\"}},\"required\":[\"ueId\",\"qosId\"]}},\"required\":[\"scope\",\"qosObjectives\"]}"
+  },
+  {
+    "name": "0",
+    "schema": "{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"description\":\"Type 0 policy type (no instances)\",\"additionalProperties\":false,\"title\":\"1\",\"type\":\"object\",\"properties\":{\"qosObjectives\":{\"additionalProperties\":false,\"type\":\"object\",\"properties\":{\"priorityLevel\":{\"type\":\"number\"}},\"required\":[\"priorityLevel\"]},\"scope\":{\"additionalProperties\":false,\"type\":\"object\",\"properties\":{\"qosId\":{\"type\":\"string\"},\"ueId\":{\"type\":\"string\"}},\"required\":[\"ueId\",\"qosId\"]}},\"required\":[\"scope\",\"qosObjectives\"]}"
   }
   ]
\ No newline at end of file
index de92d04..bae205e 100644 (file)
@@ -7,7 +7,8 @@
                 "kista_2"
             ],
             "policytype_ids": [
-                "1"
+                "1",
+                "0"
             ],
             "state": "AVAILABLE"
         }
index b9f4c34..e8b6ae9 100644 (file)
   -->
 
   <div fxLayout="row">
-    <div class="nrcp-global-page-title">Policy Control</div>
+    <div class="nrcp-global-page-title">Policy Types</div>
+    <div class="refresh-button">
+      <button #refreshButton mat-icon-button color="primary" (click)="refreshTables()">
+          <mat-icon>refresh</mat-icon>
+      </button>
+  </div>
 </div>
+<br>
 
 <nrcp-policy-type *ngFor="let policyTypeId of this.policyTypeIds" [policyTypeId]="policyTypeId"></nrcp-policy-type>
+
+<div *ngIf="this.policyTypeIds.length==0">There are no policy types to display.</div>
\ No newline at end of file
index 05f95db..4109dbd 100644 (file)
@@ -30,10 +30,14 @@ import { PolicyTypes } from "@interfaces/policy.types";
 import { PolicyService } from "@services/policy/policy.service";
 import { MockComponent } from "ng-mocks";
 import { PolicyTypeComponent } from "./policy-type/policy-type.component";
+import { MatButtonHarness } from '@angular/material/button/testing';
+import { HarnessLoader } from '@angular/cdk/testing';
+import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
 
 describe("PolicyControlComponent", () => {
   let component: PolicyControlComponent;
   let fixture: ComponentFixture<PolicyControlComponent>;
+  let loader: HarnessLoader;
 
   beforeEach(async(() => {
     const policyServiceSpy = jasmine.createSpyObj("PolicyService", [
@@ -57,6 +61,7 @@ describe("PolicyControlComponent", () => {
     fixture = TestBed.createComponent(PolicyControlComponent);
     component = fixture.componentInstance;
     fixture.detectChanges();
+    loader = TestbedHarnessEnvironment.loader(fixture);
   });
 
   it("should create", () => {
@@ -72,4 +77,11 @@ describe("PolicyControlComponent", () => {
     expect(typeComponents[0].policyTypeId).toEqual("type1");
     expect(typeComponents[1].policyTypeId).toEqual("type2");
   });
+
+  /*it("should reload when clicking on refresh button", async () => {
+    let refreshButton: MatButtonHarness = await loader.getHarness(
+      MatButtonHarness.with({ selector: "#refreshButton" })
+    );
+
+  })*/
 });
index df49c76..feb4cfb 100644 (file)
@@ -21,20 +21,30 @@ import { Component, OnInit } from "@angular/core";
 
 import { PolicyTypes } from "@interfaces/policy.types";
 import { PolicyService } from "@services/policy/policy.service";
+import { PolicyTypeComponent } from "./policy-type/policy-type.component"
 
 @Component({
   selector: "nrcp-policy-control",
   templateUrl: "./policy-control.component.html",
   styleUrls: ["./policy-control.component.scss"]
 })
+
 export class PolicyControlComponent implements OnInit {
-  policyTypeIds: Array<string>;
+  policyTypeIds = [];
+  ptComponent: PolicyTypeComponent;
 
-  constructor(private policyService: PolicyService) {}
+  constructor(private policyService: PolicyService) {
+    this.ptComponent = new PolicyTypeComponent(policyService);
+  }
 
   ngOnInit() {
+    this.refreshTables();
+  }
+
+  refreshTables() {
     this.policyService.getPolicyTypes().subscribe((policyType: PolicyTypes) => {
-      this.policyTypeIds = policyType.policytype_ids;
+      this.policyTypeIds = policyType.policytype_ids.sort();
     });
+    this.ptComponent.toggleVisible();
   }
 }
index 29f0579..3203c0d 100644 (file)
@@ -18,7 +18,7 @@
   ========================LICENSE_END===================================
   -->
 <div>
-    Number of instances: {{noInstances()}}
+    Number of instances: {{instanceCount()}}
     <button id="createButton" mat-icon-button (click)="createPolicyInstance(policyTypeSchema)">
         <mat-icon id="createIcon" matTooltip="Create instance">add_box</mat-icon>
     </button>
         <mat-footer-cell *matFooterCellDef>No records found.</mat-footer-cell>
     </ng-container>
 
-    <mat-header-row *matHeaderRowDef="['instanceId', 'ric', 'service', 'lastModified', 'action']">
+    <mat-header-row *matHeaderRowDef="['instanceId', 'ric', 'service', 'lastModified', 'action']" [ngClass]="{'display-none': !this.hasInstances()}">
     </mat-header-row>
     <mat-row *matRowDef="let instance; columns: ['instanceId', 'ric', 'service', 'lastModified', 'action'];"></mat-row>
-</mat-table>
\ No newline at end of file
+
+    <mat-footer-row *matFooterRowDef="['noRecordsFound']" [ngClass]="{'display-none': this.hasInstances()}">
+    </mat-footer-row>
+
+</mat-table>
index 8d1924a..53ab8b1 100644 (file)
@@ -179,7 +179,11 @@ export class PolicyInstanceComponent implements OnInit {
     });
   }
 
-  noInstances(): number {
+  hasInstances(): boolean {
+    return this.instanceCount() > 0;
+}
+
+  instanceCount(): number {
     return this.policyInstances.length;
   }
 
index 6c95bf9..5b92a7d 100644 (file)
 
 <div fxLayout="row" fxLayoutGap="10px">
   <div id="visible" class="default-cursor" (click)="toggleVisible()">
-    <mat-icon matTooltip="Properties">{{isVisible.value? 'expand_less' : 'expand_more'}}</mat-icon>
+    <mat-icon matTooltip="Show instances">{{isVisible.value? 'expand_less' : 'expand_more'}}</mat-icon>
   </div>
-  <div>
-    <b><u>Policy type:</u></b> {{policyType}}
+  <div matTooltip={{policyDescription}} matTooltipPosition="after" class="default-cursor" (click)="toggleVisible()">
+    {{policyType}}
   </div>
-  <div>
-    <b><u>Description:</u></b> {{policyDescription}}
+</div>
+<div class="description">
+  <div *ngIf="isVisible.value">
+    <u><b>Description</b></u>: {{policyDescription}}
   </div>
 </div>
 
index 26245c9..ef1fc68 100644 (file)
@@ -16,4 +16,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * ========================LICENSE_END===================================
- */
\ No newline at end of file
+ */
+
+ .description {
+     margin-left: 40px;
+ }
\ No newline at end of file