Merge "Tweaks for Policy Control UI"
[portal/nonrtric-controlpanel.git] / webapp-frontend / src / app / policy / policy-instance / policy-instance.component.ts
1 /*-
2  * ========================LICENSE_START=================================
3  * O-RAN-SC
4  * %%
5  * Copyright (C) 2019 Nordix Foundation
6  * %%
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ========================LICENSE_END===================================
19  */
20
21 import { Sort } from "@angular/material/sort";
22 import { Component, OnInit, Input } from "@angular/core";
23 import { MatDialog } from "@angular/material/dialog";
24 import { PolicyTypeSchema } from "@interfaces/policy.types";
25 import { NotificationService } from "@services/ui/notification.service";
26 import { PolicyService } from "@services/policy/policy.service";
27 import { ConfirmDialogService } from "@services/ui/confirm-dialog.service";
28 import { PolicyInstance } from "@interfaces/policy.types";
29 import { PolicyInstanceDialogComponent } from "../policy-instance-dialog/policy-instance-dialog.component";
30 import { getPolicyDialogProperties } from "../policy-instance-dialog/policy-instance-dialog.component";
31 import { HttpResponse } from "@angular/common/http";
32 import { BehaviorSubject, forkJoin } from "rxjs";
33 import { UiService } from "@services/ui/ui.service";
34 import { FormControl, FormGroup } from "@angular/forms";
35 import { MatTableDataSource } from "@angular/material/table";
36 import { mergeMap } from "rxjs/operators";
37
38 @Component({
39   selector: "nrcp-policy-instance",
40   templateUrl: "./policy-instance.component.html",
41   styleUrls: ["./policy-instance.component.scss"],
42 })
43 export class PolicyInstanceComponent implements OnInit {
44   @Input() policyTypeSchema: PolicyTypeSchema;
45   darkMode: boolean;
46   instanceDataSource: MatTableDataSource<PolicyInstance>;
47   policyInstanceForm: FormGroup;
48   private policyInstanceSubject = new BehaviorSubject<PolicyInstance[]>([]);
49   policyInstances: PolicyInstance[] = [];
50
51   constructor(
52     private policySvc: PolicyService,
53     private dialog: MatDialog,
54     private notificationService: NotificationService,
55     private confirmDialogService: ConfirmDialogService,
56     private ui: UiService
57   ) {
58     this.policyInstanceForm = new FormGroup({
59       id: new FormControl(""),
60       target: new FormControl(""),
61       owner: new FormControl(""),
62       lastModified: new FormControl(""),
63     });
64   }
65
66   ngOnInit() {
67     this.getPolicyInstances();
68     this.policyInstanceSubject.subscribe((data) => {
69       this.instanceDataSource = new MatTableDataSource<PolicyInstance>(data);
70
71       this.instanceDataSource.filterPredicate = ((
72         data: PolicyInstance,
73         filter
74       ) => {
75         return (
76           this.isDataIncluding(data.policy_id, filter.id) &&
77           this.isDataIncluding(data.ric_id, filter.target) &&
78           this.isDataIncluding(data.service_id, filter.owner) &&
79           this.isDataIncluding(data.lastModified, filter.lastModified)
80         );
81       }) as (data: PolicyInstance, filter: any) => boolean;
82     });
83
84     this.policyInstanceForm.valueChanges.subscribe((value) => {
85       const filter = {
86         ...value,
87         id: value.id.trim().toLowerCase(),
88       } as string;
89       this.instanceDataSource.filter = filter;
90     });
91
92     this.ui.darkModeState.subscribe((isDark) => {
93       this.darkMode = isDark;
94     });
95   }
96
97   getPolicyInstances() {
98     this.policyInstances = [] as PolicyInstance[];
99     this.policySvc
100       .getPolicyInstancesByType(this.policyTypeSchema.id)
101       .pipe(
102         mergeMap((policyIds) =>
103           forkJoin(
104             policyIds.policy_ids.map((id) => {
105               return forkJoin([
106                 this.policySvc.getPolicyInstance(id),
107                 this.policySvc.getPolicyStatus(id),
108               ]);
109             })
110           )
111         )
112       )
113       .subscribe((res) => {
114         this.policyInstances = res.map((policy) => {
115           let policyInstance = <PolicyInstance>{};
116           policyInstance = policy[0];
117           policyInstance.lastModified = policy[1].last_modified;
118           return policyInstance;
119         });
120         this.policyInstanceSubject.next(this.policyInstances);
121       });
122   }
123
124   getSortedData(sort: Sort) {
125     const data = this.instanceDataSource.data;
126     data.sort((a: PolicyInstance, b: PolicyInstance) => {
127       const isAsc = sort.direction === "asc";
128       switch (sort.active) {
129         case "instanceId":
130           return compare(a.policy_id, b.policy_id, isAsc);
131         case "ric":
132           return compare(a.ric_id, b.ric_id, isAsc);
133         case "service":
134           return compare(a.service_id, b.service_id, isAsc);
135         case "lastModified":
136           return compare(a.lastModified, b.lastModified, isAsc);
137         default:
138           return 0;
139       }
140     });
141     this.instanceDataSource.data = data;
142   }
143
144   stopSort(event: any) {
145     event.stopPropagation();
146   }
147
148   isDataIncluding(data: string, filter: string): boolean {
149     return !filter || data.toLowerCase().includes(filter);
150   }
151
152   createPolicyInstance(policyTypeSchema: PolicyTypeSchema): void {
153     this.openInstanceDialog(null);
154   }
155
156   modifyInstance(instance: PolicyInstance): void {
157     let refreshedInstance: PolicyInstance;
158     this.policySvc
159       .getPolicyInstance(instance.policy_id)
160       .subscribe((refreshedJson: any) => {
161         refreshedInstance = refreshedJson;
162       });
163
164     this.openInstanceDialog(refreshedInstance);
165   }
166
167   private openInstanceDialog(policy: PolicyInstance) {
168     const dialogData = getPolicyDialogProperties(
169       this.policyTypeSchema,
170       policy,
171       this.darkMode
172     );
173     const dialogRef = this.dialog.open(
174       PolicyInstanceDialogComponent,
175       dialogData
176     );
177     dialogRef.afterClosed().subscribe((ok: any) => {
178       if (ok) this.getPolicyInstances();
179     });
180   }
181
182   hasInstances(): boolean {
183     return this.instanceCount() > 0;
184 }
185
186   instanceCount(): number {
187     return this.policyInstances.length;
188   }
189
190   toLocalTime(utcTime: string): string {
191     const date = new Date(utcTime);
192     const toutc = date.toUTCString();
193     return new Date(toutc + " UTC").toLocaleString();
194   }
195
196   deleteInstance(instance: PolicyInstance): void {
197     this.confirmDialogService
198       .openConfirmDialog(
199         "Delete Policy",
200         "Are you sure you want to delete this policy instance?"
201       )
202       .afterClosed()
203       .subscribe((res: any) => {
204         if (res) {
205           this.policySvc
206             .deletePolicy(instance.policy_id)
207             .subscribe((response: HttpResponse<Object>) => {
208               if (response.status === 204) {
209                 this.notificationService.success("Delete succeeded!");
210                 this.getPolicyInstances();
211               }
212             });
213         }
214       });
215   }
216
217   refreshTable() {
218     this.getPolicyInstances();
219   }
220 }
221
222 function compare(a: string, b: string, isAsc: boolean) {
223   return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
224 }