Simplify PolicyInstanceComponent
[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 { ErrorDialogService } from "@services/ui/error-dialog.service";
26 import { NotificationService } from "@services/ui/notification.service";
27 import { PolicyService } from "@services/policy/policy.service";
28 import { ConfirmDialogService } from "@services/ui/confirm-dialog.service";
29 import { PolicyInstance } from "@interfaces/policy.types";
30 import { PolicyInstanceDialogComponent } from "../policy-instance-dialog/policy-instance-dialog.component";
31 import { getPolicyDialogProperties } from "../policy-instance-dialog/policy-instance-dialog.component";
32 import { HttpErrorResponse, HttpResponse } from "@angular/common/http";
33 import { BehaviorSubject, Observable } from "rxjs";
34 import { UiService } from "@services/ui/ui.service";
35 import { FormControl, FormGroup } from "@angular/forms";
36 import { MatTableDataSource } from "@angular/material/table";
37
38 class PolicyTypeInfo {
39   constructor(public type: PolicyTypeSchema) {}
40
41   isExpanded: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
42 }
43
44 @Component({
45   selector: "nrcp-policy-instance",
46   templateUrl: "./policy-instance.component.html",
47   styleUrls: ["./policy-instance.component.scss"],
48 })
49 export class PolicyInstanceComponent implements OnInit {
50   @Input() policyTypeSchema: PolicyTypeSchema;
51   @Input() expanded: Observable<boolean>;
52   policyInstances: PolicyInstance[] = [];
53   private policyInstanceSubject = new BehaviorSubject<PolicyInstance[]>([]);
54   policyTypeInfo = new Map<string, PolicyTypeInfo>();
55   instanceDataSource: MatTableDataSource<PolicyInstance> = new MatTableDataSource<PolicyInstance>();
56   policyInstanceForm: FormGroup;
57   darkMode: boolean;
58
59   constructor(
60     private policySvc: PolicyService,
61     private dialog: MatDialog,
62     private errorDialogService: ErrorDialogService,
63     private notificationService: NotificationService,
64     private confirmDialogService: ConfirmDialogService,
65     private ui: UiService
66   ) {
67     this.policyInstanceForm = new FormGroup({
68       id: new FormControl(""),
69       target: new FormControl(""),
70       owner: new FormControl(""),
71       lastModified: new FormControl(""),
72     });
73   }
74
75   ngOnInit() {
76     this.expanded.subscribe((isExpanded: boolean) => this.onExpand(isExpanded));
77
78     this.getPolicyInstances();
79     this.policyInstanceSubject.subscribe((data) => {
80       this.instanceDataSource.data = data;
81     });
82
83     this.policyInstanceForm.valueChanges.subscribe((value) => {
84       const filter = { ...value, id: value.id.trim().toLowerCase() } as string;
85       this.instanceDataSource.filter = filter;
86     });
87
88     this.instanceDataSource.filterPredicate = ((
89       data: PolicyInstance,
90       filter
91     ) => {
92       return (
93         this.isDataIncluding(data.policy_id, filter.id) &&
94         this.isDataIncluding(data.ric_id, filter.target) &&
95         this.isDataIncluding(data.service_id, filter.owner) &&
96         this.isDataIncluding(data.lastModified, filter.lastModified)
97       );
98     }) as (data: PolicyInstance, filter: any) => boolean;
99
100     this.ui.darkModeState.subscribe((isDark) => {
101       this.darkMode = isDark;
102     });
103   }
104
105   getPolicyInstances() {
106     this.policyInstances = [] as PolicyInstance[];
107     this.policySvc
108       .getPolicyInstancesByType(this.policyTypeSchema.id)
109       .subscribe((policies) => {
110         if (policies.policy_ids.length != 0) {
111           policies.policy_ids.forEach((policyId) => {
112             this.policySvc
113               .getPolicyInstance(policyId)
114               .subscribe((policyInstance) => {
115                 this.policySvc
116                   .getPolicyStatus(policyId)
117                   .subscribe((policyStatus) => {
118                     policyInstance.lastModified = policyStatus.last_modified;
119                   });
120                 this.policyInstances.push(policyInstance);
121               });
122             this.policyInstanceSubject.next(this.policyInstances);
123           });
124         }
125       });
126   }
127
128   getSortedData(sort: Sort) {
129     const data = this.instanceDataSource.data;
130     data.sort((a, b) => {
131       const isAsc = sort.direction === "asc";
132       switch (sort.active) {
133         case "instanceId":
134           return compare(a.policy_id, b.policy_id, isAsc);
135         case "ric":
136           return compare(a.ric_id, b.ric_id, isAsc);
137         case "service":
138           return compare(a.service_id, b.service_id, isAsc);
139         case "lastModified":
140           return compare(a.lastModified, b.lastModified, isAsc);
141         default:
142           return 0;
143       }
144     });
145     this.instanceDataSource.data = data;
146   }
147
148   stopSort(event: any) {
149     event.stopPropagation();
150   }
151
152   isDataIncluding(data: string, filter: string): boolean {
153     return !filter || data.toLowerCase().includes(filter);
154   }
155
156   private onExpand(isExpanded: boolean) {
157     if (isExpanded) {
158       this.getPolicyInstances();
159     }
160   }
161
162   private isSchemaEmpty(): boolean {
163     return this.policyTypeSchema.schemaObject === "{}";
164   }
165
166   modifyInstance(instance: PolicyInstance): void {
167     this.policySvc.getPolicyInstance(instance.policy_id).subscribe(
168       (refreshedJson: any) => {
169         instance = refreshedJson;
170         this.dialog
171           .open(
172             PolicyInstanceDialogComponent,
173             getPolicyDialogProperties(
174               this.policyTypeSchema,
175               instance,
176               this.darkMode
177             )
178           )
179           .afterClosed()
180           .subscribe((_: any) => {
181             this.getPolicyInstances();
182           });
183       },
184       (httpError: HttpErrorResponse) => {
185         this.notificationService.error(
186           "Could not refresh instance. Please try again." + httpError.message
187         );
188       }
189     );
190   }
191
192   nbInstances(): number {
193     return this.policyInstances.length;
194   }
195
196   toLocalTime(utcTime: string): string {
197     const date = new Date(utcTime);
198     const toutc = date.toUTCString();
199     return new Date(toutc + " UTC").toLocaleString();
200   }
201
202   createPolicyInstance(policyTypeSchema: PolicyTypeSchema): void {
203     let dialogRef = this.dialog.open(
204       PolicyInstanceDialogComponent,
205       getPolicyDialogProperties(policyTypeSchema, null, this.darkMode)
206     );
207     const info: PolicyTypeInfo = this.getPolicyTypeInfo(policyTypeSchema);
208     dialogRef.afterClosed().subscribe((_) => {
209       info.isExpanded.next(info.isExpanded.getValue());
210     });
211   }
212
213   deleteInstance(instance: PolicyInstance): void {
214     this.confirmDialogService
215       .openConfirmDialog(
216         "Are you sure you want to delete this policy instance?"
217       )
218       .afterClosed()
219       .subscribe((res: any) => {
220         if (res) {
221           this.policySvc.deletePolicy(instance.policy_id).subscribe(
222             (response: HttpResponse<Object>) => {
223               switch (response.status) {
224                 case 204:
225                   this.notificationService.success("Delete succeeded!");
226                   this.getPolicyInstances();
227                   break;
228                 default:
229                   this.notificationService.warn(
230                     "Delete failed " + response.status + " " + response.body
231                   );
232               }
233             },
234             (error: HttpErrorResponse) => {
235               this.errorDialogService.displayError(
236                 error.statusText + ", " + error.error
237               );
238             }
239           );
240         }
241       });
242   }
243
244   getPolicyTypeInfo(policyTypeSchema: PolicyTypeSchema): PolicyTypeInfo {
245     let info: PolicyTypeInfo = this.policyTypeInfo.get(policyTypeSchema.name);
246     if (!info) {
247       info = new PolicyTypeInfo(policyTypeSchema);
248       this.policyTypeInfo.set(policyTypeSchema.name, info);
249     }
250     return info;
251   }
252
253   refreshTable() {
254     this.getPolicyInstances();
255   }
256 }
257
258 function compare(a: string, b: string, isAsc: boolean) {
259   return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
260 }