Polling mechanism to get jobs
[portal/nonrtric-controlpanel.git] / webapp-frontend / src / app / ei-coordinator / jobs-list / jobs-list.component.ts
1 /*-
2  * ========================LICENSE_START=================================
3  * O-RAN-SC
4  * %%
5  * Copyright (C) 2021 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 import { Component, OnInit, ViewChild } from "@angular/core";
21 import { FormControl, FormGroup } from "@angular/forms";
22 import { MatPaginator } from "@angular/material/paginator";
23 import { Sort } from "@angular/material/sort";
24 import { MatTableDataSource } from "@angular/material/table";
25 import {
26   forkJoin,
27   Subscription,
28   timer,
29 } from "rxjs";
30 import { BehaviorSubject } from "rxjs/BehaviorSubject";
31 import {
32   mergeMap,
33   finalize,
34   map,
35   tap,
36   switchMap,
37 } from "rxjs/operators";
38 import { EIJob } from "@interfaces/ei.types";
39 import { EIService } from "@services/ei/ei.service";
40 import { UiService } from "@services/ui/ui.service";
41
42 export interface Job {
43   jobId: string;
44   jobData: any;
45   typeId: string;
46   targetUri: string;
47   owner: string;
48   prodId: string;
49 }
50
51 @Component({
52   selector: "nrcp-jobs-list",
53   templateUrl: "./jobs-list.component.html",
54   styleUrls: ["./jobs-list.component.scss"],
55 })
56 export class JobsListComponent implements OnInit {
57   @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
58   jobsDataSource: MatTableDataSource<Job>;
59   jobForm: FormGroup;
60   darkMode: boolean;
61
62   private jobsSubject = new BehaviorSubject<Job[]>([]);
63   private refresh$ = new BehaviorSubject("");
64   private loadingSubject = new BehaviorSubject<boolean>(false);
65   public loading$ = this.loadingSubject.asObservable();
66   subscription: Subscription;
67
68   constructor(private eiSvc: EIService, private ui: UiService) {
69     this.jobForm = new FormGroup({
70       jobId: new FormControl(""),
71       typeId: new FormControl(""),
72       owner: new FormControl(""),
73       targetUri: new FormControl(""),
74       prodId: new FormControl(""),
75     });
76   }
77
78   ngOnInit(): void {
79     this.subscription = this.dataSubscription();
80
81     this.jobsSubject.subscribe((data) => {
82       this.jobsDataSource = new MatTableDataSource<Job>(data);
83       this.jobsDataSource.paginator = this.paginator;
84
85       this.jobsDataSource.filterPredicate = ((data: Job, filter) => {
86         let searchTerms = JSON.parse(filter);
87         return (
88           this.isDataIncluding(data.targetUri, searchTerms.targetUri) &&
89           this.isDataIncluding(data.jobId, searchTerms.jobId) &&
90           this.isDataIncluding(data.owner, searchTerms.owner) &&
91           this.isDataIncluding(data.typeId, searchTerms.typeId) &&
92           this.isDataIncluding(data.prodId, searchTerms.prodId)
93         );
94       }) as (data: Job, filter: any) => boolean;
95     });
96
97     this.jobForm.valueChanges.subscribe((value) => {
98       this.jobsDataSource.filter = JSON.stringify(value);
99     });
100
101     this.ui.darkModeState.subscribe((isDark) => {
102       this.darkMode = isDark;
103     });
104   }
105
106   dataSubscription(): Subscription {
107     let prodId = [];
108     const jobs$ = this.eiSvc.getProducerIds().pipe(
109       tap((data) => (prodId = data)),
110       mergeMap((prodIds) =>
111         forkJoin(prodIds.map((id) => this.eiSvc.getJobsForProducer(id)))
112       ),
113       finalize(() => this.loadingSubject.next(false))
114     );
115
116     return this.refresh$
117       .pipe(
118         switchMap((_) =>
119           timer(0, 10000).pipe(
120             tap((_) => {
121               this.loadingSubject.next(true);
122             }),
123             switchMap((_) => jobs$),
124             map((response) => this.extractJobs(prodId, response))
125           )
126         )
127       )
128       .subscribe();
129   }
130
131   ngOnDestroy() {
132     this.subscription.unsubscribe();
133   }
134
135   clearFilter() {
136     this.jobForm.get("jobId").setValue("");
137     this.jobForm.get("typeId").setValue("");
138     this.jobForm.get("owner").setValue("");
139     this.jobForm.get("targetUri").setValue("");
140     this.jobForm.get("prodId").setValue("");
141   }
142
143   sortJobs(sort: Sort) {
144     const data = this.jobsDataSource.data;
145     data.sort((a: Job, b: Job) => {
146       const isAsc = sort.direction === "asc";
147       switch (sort.active) {
148         case "jobId":
149           return this.compare(a.jobId, b.jobId, isAsc);
150         case "typeId":
151           return this.compare(a.typeId, b.typeId, isAsc);
152         case "owner":
153           return this.compare(a.owner, b.owner, isAsc);
154         case "targetUri":
155           return this.compare(a.targetUri, b.targetUri, isAsc);
156         case "prodId":
157           return this.compare(a.prodId, b.prodId, isAsc);
158         default:
159           return 0;
160       }
161     });
162     this.jobsDataSource.data = data;
163   }
164
165   compare(a: any, b: any, isAsc: boolean) {
166     return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
167   }
168
169   stopSort(event: any) {
170     event.stopPropagation();
171   }
172
173   isDataIncluding(data: string, filter: string): boolean {
174     const transformedFilter = filter.trim().toLowerCase();
175     return data.toLowerCase().includes(transformedFilter);
176   }
177
178   getJobTypeId(eiJob: Job): string {
179     if (eiJob.typeId) {
180       return eiJob.typeId;
181     }
182     return "< No type >";
183   }
184
185   getJobOwner(eiJob: Job): string {
186     if (eiJob.owner) {
187       return eiJob.owner;
188     }
189     return "< No owner >";
190   }
191
192   public jobs(): Job[] {
193     return this.jobsSubject.value;
194   }
195
196   private extractJobs(prodId: number[], res: EIJob[][]) {
197     console.log(res.length);
198     let jobList = [];
199     prodId.forEach((element, index) => {
200       let jobs = res[index];
201       jobList = jobList.concat(jobs.map((job) => this.createJob(element, job)));
202     });
203     this.jobsSubject.next(jobList);
204     return jobList;
205   }
206
207   createJobList(prodId: any[], result: EIJob[][]) {
208     let jobList = [];
209     prodId.forEach((element, index) => {
210       let jobs = result[index];
211       jobList = jobList.concat(jobs.map((job) => this.createJob(element, job)));
212     });
213     return jobList;
214   }
215
216   createJob(element: any, job: EIJob): any {
217     let eiJob = <Job>{};
218     eiJob.jobId = job.ei_job_identity;
219     eiJob.typeId = job.ei_type_identity;
220     eiJob.owner = job.owner;
221     eiJob.targetUri = job.target_uri;
222     eiJob.prodId = element;
223     return eiJob;
224   }
225
226   refreshDataClick() {
227     this.refresh$.next("");
228   }
229 }