2 * ========================LICENSE_START=================================
5 * Copyright (C) 2021 Nordix Foundation
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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===================================
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 { EMPTY, forkJoin, of, Subscription, concat } from "rxjs";
26 import { BehaviorSubject } from "rxjs/BehaviorSubject";
27 import { mergeMap, finalize, map, tap, concatMap, delay, skip, catchError } from "rxjs/operators";
28 import { ConsumerService } from "@services/ei/consumer.service";
29 import { UiService } from "@services/ui/ui.service";
30 import { OperationalState } from '@app/interfaces/consumer.types';
32 export interface Job {
38 status: OperationalState;
42 selector: "nrcp-jobs-list",
43 templateUrl: "./jobs-list.component.html",
44 styleUrls: ["./jobs-list.component.scss"],
46 export class JobsListComponent implements OnInit {
47 @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
48 jobsDataSource: MatTableDataSource<Job>;
52 private jobsSubject$ = new BehaviorSubject<Job[]>([]);
53 private refresh$ = new BehaviorSubject("");
54 private loadingSubject$ = new BehaviorSubject<boolean>(false);
55 private polling$ = new BehaviorSubject(0);
56 public loading$ = this.loadingSubject$.asObservable();
57 subscription: Subscription;
58 checked: boolean = false;
59 firstTime: boolean = true;
62 constructor(private consumerService: ConsumerService, private ui: UiService) {
63 this.jobForm = new FormGroup({
64 jobId: new FormControl(""),
65 typeId: new FormControl(""),
66 owner: new FormControl(""),
67 targetUri: new FormControl(""),
68 prodIds: new FormControl(""),
69 status: new FormControl("")
74 this.subscription = this.dataSubscription();
76 this.jobsSubject$.subscribe((data) => {
77 this.jobsDataSource = new MatTableDataSource<Job>(data);
78 this.jobsDataSource.paginator = this.paginator;
80 this.jobsDataSource.filterPredicate = ((data: Job, filter) => {
81 let searchTerms = JSON.parse(filter);
83 this.isDataIncluding(data.targetUri, searchTerms.targetUri) &&
84 this.isDataIncluding(data.jobId, searchTerms.jobId) &&
85 this.isDataIncluding(data.owner, searchTerms.owner) &&
86 this.isDataIncluding(data.typeId, searchTerms.typeId) &&
87 this.isArrayIncluding(data.prodIds, searchTerms.prodIds) &&
88 this.isDataIncluding(data.status, searchTerms.status)
90 }) as (data: Job, filter: any) => boolean;
93 this.jobForm.valueChanges.subscribe((value) => {
94 this.jobsDataSource.filter = JSON.stringify(value);
97 this.ui.darkModeState.subscribe((isDark) => {
98 this.darkMode = isDark;
102 dataSubscription(): Subscription {
103 const jobsInfo$ = this.consumerService.getJobIds().pipe(
104 catchError(_ => { return EMPTY }),
106 this.jobList = [] as Job[];
109 forkJoin(jobIds.map((jobId) => {
116 this.consumerService.getJobInfo(jobId).pipe(
120 this.consumerService.getConsumerStatus(jobId).pipe(
128 this.loadingSubject$.next(false);
129 this.jobsSubject$.next(this.jobList);
133 const whenToRefresh$ = of('').pipe(
135 tap((_) => this.refresh$.next('')),
139 const poll$ = concat(jobsInfo$, whenToRefresh$);
141 const refreshedJobs$ = this.refresh$.pipe(
143 this.loadingSubject$.next(true);
145 concatMap((_) => this.checked ? poll$ : jobsInfo$),
146 map((response) => this.extractJobs(response))
151 concatMap((value) => {
152 let pollCondition = value == 0 || this.checked;
153 return pollCondition ? refreshedJobs$ : EMPTY;
160 this.subscription.unsubscribe();
164 this.jobForm.get("jobId").setValue("");
165 this.jobForm.get("typeId").setValue("");
166 this.jobForm.get("owner").setValue("");
167 this.jobForm.get("targetUri").setValue("");
168 this.jobForm.get("prodIds").setValue("");
169 this.jobForm.get("status").setValue("");
172 sortJobs(sort: Sort) {
173 const data = this.jobsDataSource.data;
174 data.sort((a: Job, b: Job) => {
175 const isAsc = sort.direction === "asc";
176 switch (sort.active) {
178 return this.compare(a.jobId, b.jobId, isAsc);
180 return this.compare(a.typeId, b.typeId, isAsc);
182 return this.compare(a.owner, b.owner, isAsc);
184 return this.compare(a.targetUri, b.targetUri, isAsc);
186 return this.compare(a.prodIds, b.prodIds, isAsc);
188 return this.compare(a.status, b.status, isAsc);
193 this.jobsDataSource.data = data;
196 stopPolling(checked) {
197 this.checked = checked;
198 this.polling$.next(this.jobs().length);
200 this.refreshDataClick();
204 compare(a: any, b: any, isAsc: boolean) {
205 return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
208 stopSort(event: any) {
209 event.stopPropagation();
212 isDataIncluding(data: string, filter: string): boolean {
213 const transformedFilter = filter.trim().toLowerCase();
214 return data.toLowerCase().includes(transformedFilter);
217 isArrayIncluding(data: string[], filter: string): boolean {
220 for (let i = 0; i < data.length; i++) {
221 return this.isDataIncluding(data[i], filter);
225 getJobTypeId(job: Job): string {
229 return "< No type >";
232 getJobOwner(job: Job): string {
236 return "< No owner >";
239 public jobs(): Job[] {
240 return this.jobsSubject$.value;
243 private extractJobs(res: any) {
245 res.forEach(element => {
246 if (element[0] != -1) {
247 if (element[1] != -1 && element[2] != -1) {
248 let jobObj = <Job>{};
249 jobObj.jobId = element[0];
250 jobObj.owner = element[1].job_owner;
251 jobObj.targetUri = element[1].job_result_uri;
252 jobObj.typeId = element[1].info_type_id;
253 jobObj.prodIds = (element[2].producers) ? element[2].producers : ["No Producers"];
254 jobObj.status = element[2].info_job_status;
255 this.jobList = this.jobList.concat(jobObj);
257 let jobObj = <Job>{};
258 jobObj.jobId = element[0];
259 if (element[1] == -1) {
260 jobObj.owner = "--Missing information--";
261 jobObj.targetUri = "--Missing information--";
262 jobObj.typeId = "--Missing information--";
264 if (element[2] == -1) {
265 jobObj.prodIds = "--Missing information--" as unknown as [];
266 jobObj.status = "--Missing information--" as OperationalState;
268 this.jobList = this.jobList.concat(jobObj);
273 if (this.firstTime && this.jobList.length > 0) {
274 this.polling$.next(this.jobList.length);
275 this.firstTime = false;
281 this.refresh$.next("");
284 jobsNumber() : number {
285 return this.jobsDataSource.data.length;
289 return this.jobsNumber() > 0;