Add functionality to truncate amount of instances
[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(() => this.loadingSubject$.next(false))
125       )
126       .subscribe((res) => {
127         this.policyInstances = res.map((policy) => {
128           let policyInstance = <PolicyInstance>{};
129           policyInstance = policy[0];
130           policyInstance.lastModified = policy[1].last_modified;
131           return policyInstance;
132         });
133         this.policyInstanceSubject.next(this.policyInstances);
134       });
135   }
136
137   getSortedData(sort: Sort) {
138     const data = this.instanceDataSource.data;
139     data.sort((a: PolicyInstance, b: PolicyInstance) => {
140       const isAsc = sort.direction === "asc";
141       switch (sort.active) {
142         case "instanceId":
143           return compare(a.policy_id, b.policy_id, isAsc);
144         case "ric":
145           return compare(a.ric_id, b.ric_id, isAsc);
146         case "service":
147           return compare(a.service_id, b.service_id, isAsc);
148         case "lastModified":
149           return compare(a.lastModified, b.lastModified, isAsc);
150         default:
151           return 0;
152       }
153     });
154     this.instanceDataSource.data = data;
155   }
156
157   stopSort(event: any) {
158     event.stopPropagation();
159   }
160
161   isDataIncluding(data: string, filter: string): boolean {
162     return !filter || data.toLowerCase().includes(filter);
163   }
164
165   createPolicyInstance(policyTypeSchema: PolicyTypeSchema): void {
166     this.openInstanceDialog(null);
167   }
168
169   modifyInstance(instance: PolicyInstance): void {
170     this.policySvc
171       .getPolicyInstance(instance.policy_id)
172       .subscribe((refreshedJson: PolicyInstance) => {
173         this.openInstanceDialog(refreshedJson);
174       });
175   }
176
177   private openInstanceDialog(policy: PolicyInstance) {
178     const dialogData = getPolicyDialogProperties(
179       this.policyTypeSchema,
180       policy,
181       this.darkMode
182     );
183     const dialogRef = this.dialog.open(
184       PolicyInstanceDialogComponent,
185       dialogData
186     );
187     dialogRef.afterClosed().subscribe((ok: any) => {
188       if (ok) this.getPolicyInstances();
189     });
190   }
191
192   hasInstances(): boolean {
193     return this.instanceCount() > 0;
194   }
195
196   instanceCount(): number {
197     return this.policyInstances.length;
198   }
199
200   toLocalTime(utcTime: string): string {
201     const date = new Date(utcTime);
202     const toutc = date.toUTCString();
203     return new Date(toutc + " UTC").toLocaleString();
204   }
205
206   deleteInstance(instance: PolicyInstance): void {
207     this.confirmDialogService
208       .openConfirmDialog(
209         "Delete Policy",
210         "Are you sure you want to delete this policy instance?"
211       )
212       .afterClosed()
213       .subscribe((res: any) => {
214         if (res) {
215           this.policySvc
216             .deletePolicy(instance.policy_id)
217             .subscribe((response: HttpResponse<Object>) => {
218               if (response.status === 204) {
219                 this.notificationService.success("Delete succeeded!");
220                 this.getPolicyInstances();
221               }
222             });
223         }
224       });
225   }
226
227   refreshTable() {
228     this.truncated = false;
229     this.getPolicyInstances();
230   }
231 }
232
233 function compare(a: string, b: string, isAsc: boolean) {
234   return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
235 }