Bug-Fix Last instance does not disappear when deleted
[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 { finalize, mergeMap, map } 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   public slice: number = 1000;
45   @Input() policyTypeSchema: PolicyTypeSchema;
46   darkMode: boolean;
47   instanceDataSource: MatTableDataSource<PolicyInstance>;
48   policyInstanceForm: FormGroup;
49   private policyInstanceSubject = new BehaviorSubject<PolicyInstance[]>([]);
50   policyInstances: PolicyInstance[] = [];
51   private loadingSubject$ = new BehaviorSubject<boolean>(false);
52   public loading$ = this.loadingSubject$.asObservable();
53   public truncated = false;
54
55   constructor(
56     private policySvc: PolicyService,
57     private dialog: MatDialog,
58     private notificationService: NotificationService,
59     private confirmDialogService: ConfirmDialogService,
60     private ui: UiService
61   ) {
62     this.policyInstanceForm = new FormGroup({
63       id: new FormControl(""),
64       target: new FormControl(""),
65       owner: new FormControl(""),
66       lastModified: new FormControl(""),
67     });
68   }
69
70   ngOnInit() {
71     this.getPolicyInstances();
72     this.policyInstanceSubject.subscribe((data) => {
73       this.instanceDataSource = new MatTableDataSource<PolicyInstance>(data);
74
75       this.instanceDataSource.filterPredicate = ((
76         data: PolicyInstance,
77         filter
78       ) => {
79         return (
80           this.isDataIncluding(data.policy_id, filter.id) &&
81           this.isDataIncluding(data.ric_id, filter.target) &&
82           this.isDataIncluding(data.service_id, filter.owner) &&
83           this.isDataIncluding(data.lastModified, filter.lastModified)
84         );
85       }) as (data: PolicyInstance, filter: any) => boolean;
86     });
87
88     this.policyInstanceForm.valueChanges.subscribe((value) => {
89       const filter = {
90         ...value,
91         id: value.id.trim().toLowerCase(),
92       } as string;
93       this.instanceDataSource.filter = filter;
94     });
95
96     this.ui.darkModeState.subscribe((isDark) => {
97       this.darkMode = isDark;
98     });
99   }
100
101   getPolicyInstances() {
102     this.policyInstances = [] as PolicyInstance[];
103     this.loadingSubject$.next(true);
104     this.policySvc
105       .getPolicyInstancesByType(this.policyTypeSchema.id)
106       .pipe(
107         map((data) => {
108           if (data.policy_ids.length > this.slice) {
109             this.truncated = true;
110             data.policy_ids = data.policy_ids.slice(0, this.slice);
111           }
112           return data;
113         }),
114         mergeMap((policyIds) =>
115           forkJoin(
116             policyIds.policy_ids.map((id) => {
117               return forkJoin([
118                 this.policySvc.getPolicyInstance(id),
119                 this.policySvc.getPolicyStatus(id),
120               ]);
121             })
122           )
123         ),
124         finalize(() => {
125           this.loadingSubject$.next(false);
126           this.policyInstanceSubject.next(this.policyInstances);
127         })
128       )
129       .subscribe((res) => {
130         this.policyInstances = res.map((policy) => {
131           let policyInstance = <PolicyInstance>{};
132           policyInstance = policy[0];
133           policyInstance.lastModified = policy[1].last_modified;
134           return policyInstance;
135         });
136       });
137   }
138
139   getSortedData(sort: Sort) {
140     const data = this.instanceDataSource.data;
141     data.sort((a: PolicyInstance, b: PolicyInstance) => {
142       const isAsc = sort.direction === "asc";
143       switch (sort.active) {
144         case "instanceId":
145           return compare(a.policy_id, b.policy_id, isAsc);
146         case "ric":
147           return compare(a.ric_id, b.ric_id, isAsc);
148         case "service":
149           return compare(a.service_id, b.service_id, isAsc);
150         case "lastModified":
151           return compare(a.lastModified, b.lastModified, isAsc);
152         default:
153           return 0;
154       }
155     });
156     this.instanceDataSource.data = data;
157   }
158
159   stopSort(event: any) {
160     event.stopPropagation();
161   }
162
163   isDataIncluding(data: string, filter: string): boolean {
164     return !filter || data.toLowerCase().includes(filter);
165   }
166
167   createPolicyInstance(policyTypeSchema: PolicyTypeSchema): void {
168     this.openInstanceDialog(null);
169   }
170
171   modifyInstance(instance: PolicyInstance): void {
172     this.policySvc
173       .getPolicyInstance(instance.policy_id)
174       .subscribe((refreshedJson: PolicyInstance) => {
175         this.openInstanceDialog(refreshedJson);
176       });
177   }
178
179   private openInstanceDialog(policy: PolicyInstance) {
180     const dialogData = getPolicyDialogProperties(
181       this.policyTypeSchema,
182       policy,
183       this.darkMode
184     );
185     const dialogRef = this.dialog.open(
186       PolicyInstanceDialogComponent,
187       dialogData
188     );
189     dialogRef.afterClosed().subscribe((ok: any) => {
190       if (ok) this.getPolicyInstances();
191     });
192   }
193
194   hasInstances(): boolean {
195     return this.instanceCount() > 0;
196   }
197
198   instanceCount(): number {
199     return this.instanceDataSource.data.length;
200   }
201
202   toLocalTime(utcTime: string): string {
203     const date = new Date(utcTime);
204     const toutc = date.toUTCString();
205     return new Date(toutc + " UTC").toLocaleString();
206   }
207
208   deleteInstance(instance: PolicyInstance): void {
209     this.confirmDialogService
210       .openConfirmDialog(
211         "Delete Policy",
212         "Are you sure you want to delete this policy instance?"
213       )
214       .afterClosed()
215       .subscribe((res: any) => {
216         if (res) {
217           this.policySvc
218             .deletePolicy(instance.policy_id)
219             .subscribe((response: HttpResponse<Object>) => {
220               if (response.status === 204) {
221                 this.notificationService.success("Delete succeeded!");
222                 this.getPolicyInstances();
223               }
224             });
225         }
226       });
227   }
228
229   refreshTable() {
230     this.truncated = false;
231     this.getPolicyInstances();
232   }
233 }
234
235 function compare(a: string, b: string, isAsc: boolean) {
236   return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
237 }