Filtering the producer in the frontend 06/5406/5
authormaximesson <maxime.bonneau@est.tech>
Mon, 11 Jan 2021 09:53:10 +0000 (10:53 +0100)
committermaximesson <maxime.bonneau@est.tech>
Mon, 18 Jan 2021 12:36:45 +0000 (13:36 +0100)
Change-Id: Ib7c1aacccd01e610a7d3f7bb445d60b46b7e1abc
Issue-ID: NONRTRIC-338
Signed-off-by: maximesson <maxime.bonneau@est.tech>
13 files changed:
webapp-backend/src/test/java/org/oransc/portal/nonrtric/controlpanel/RestApiTest.java
webapp-backend/src/test/java/org/oransc/portal/nonrtric/controlpanel/mock/EnrichmentControllerMockConfiguration.java
webapp-backend/src/test/resources/job-2.json [new file with mode: 0644]
webapp-frontend/package.json
webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.html
webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.scss
webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.ts
webapp-frontend/src/app/ei-coordinator/ei-job.datasource.ts
webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.ts
webapp-frontend/src/app/interfaces/ei.jobs.ts
webapp-frontend/src/app/mock/ei-jobs.json
webapp-frontend/src/app/mock/ei-producers.json
webapp-frontend/src/app/services/ei/ei.service.ts

index 5a0cd71..5309d98 100644 (file)
@@ -94,8 +94,16 @@ class RestApiTest {
             .targetUri("http://example.com/") //
             .owner("owner") //
             .build();
-        assertThat(jobs).hasSize(1) //
-            .contains(gson.toJsonTree(wantedJobInfo));
+        JobInfo wantedJobInfo2 = JobInfo.builder() //
+            .id("job2") //
+            .typeId("type2") //
+            .jobData(getStringFromFile("job-2.json")) //
+            .targetUri("http://example.com/") //
+            .owner("owner") //
+            .build();
+        assertThat(jobs).hasSize(6) //
+            .contains(gson.toJsonTree(wantedJobInfo), //
+            gson.toJsonTree(wantedJobInfo2));
     }
 
     @Test
@@ -111,8 +119,20 @@ class RestApiTest {
             .types(new String[] {"type1", "type2"}) //
             .status("ENABLED") //
             .build();
-        assertThat(producers).hasSize(1) //
-            .contains(gson.toJsonTree(wantedProducerInfo));
+        ProducerInfo wantedProducerInfo2 = ProducerInfo.builder() //
+            .id("prod-2") //
+            .types(new String[] {"type1"}) //
+            .status("DISABLED") //
+            .build();
+        ProducerInfo wantedProducerInfo3 = ProducerInfo.builder() //
+            .id("3-prod") //
+            .types(new String[] {"type1", "type2"}) //
+            .status("ENABLED") //
+            .build();
+        assertThat(producers).hasSize(3) //
+            .contains(gson.toJsonTree(wantedProducerInfo), //
+            gson.toJsonTree(wantedProducerInfo2), //
+            gson.toJsonTree(wantedProducerInfo3));
     }
 
     private AsyncRestClient restClient() {
index b9dcc6b..b8d75c3 100644 (file)
@@ -123,9 +123,18 @@ public class EnrichmentControllerMockConfiguration {
             putEiProducerInstance("prod-1", "http://example.com/", "http://example.com/", "http://example.com/",
                 supported_types, new ProducerStatusInfo(ProducerStatusInfo.OperationalState.ENABLED));
 
+            putEiProducerInstance("prod-2", "http://example.com/", "http://example.com/", "http://example.com/",
+                Arrays.asList(supported_types.get(0)), new ProducerStatusInfo(ProducerStatusInfo.OperationalState.DISABLED));
+
+            putEiProducerInstance("3-prod", "http://example.com/", "http://example.com/", "http://example.com/",
+                supported_types, new ProducerStatusInfo(ProducerStatusInfo.OperationalState.ENABLED));
+
             // Create EiJob instance
             schema = getStringFromFile("job-1.json");
             putEiJobInstance("type1", "job1", schema, "owner", "http://example.com/");
+
+            schema = getStringFromFile("job-1.json");
+            putEiJobInstance("type2", "job2", schema, "owner", "http://example.com/");
         }
 
         private String getStringFromFile(String path) {
diff --git a/webapp-backend/src/test/resources/job-2.json b/webapp-backend/src/test/resources/job-2.json
new file mode 100644 (file)
index 0000000..3f9e757
--- /dev/null
@@ -0,0 +1,5 @@
+{
+    "jobparam1":"value1",
+    "jobparam2":"value2",
+    "jobparam3":"value3"
+}
index 95ff727..ee07def 100644 (file)
@@ -17,7 +17,6 @@
     "@angular/common": "^8.2.14",
     "@angular/flex-layout": "^7.0.0-beta.24",
     "@angular/forms": "^8.2.14",
-    "@angular/material": "~7.2.0",
     "@angular/platform-browser": "^8.2.14",
     "@angular/platform-browser-dynamic": "^8.2.14",
     "@angular/router": "^8.2.14",
@@ -50,6 +49,7 @@
     "@angular/compiler-cli": "^8.2.14",
     "@angular/core": "^8.2.14",
     "@angular/language-service": "^8.2.14",
+    "@angular/material": "^7.2.2",
     "@nguniversal/express-engine": "^8.2.6",
     "@types/jasmine": "^2.8.16",
     "@types/jasminewd2": "^2.0.8",
index 30f1eee..9e99cf0 100644 (file)
@@ -29,48 +29,59 @@ limitations under the License.
 
 <br>
 <h4>Producers</h4>
-<table mat-table EIProducerTable [dataSource]="eiProducersDataSource" [ngClass]="{'table-dark': darkMode}" matSort
-    multiTemplateDataRows class="ei-coordinator-table mat-elevation-z8">
-    <ng-container matColumnDef="id">
-        <th mat-header-cell *matHeaderCellDef> Producer ID </th>
-        <td mat-cell *matCellDef="let eiProducer"> {{this.getEIProducerId(eiProducer)}} </td>
-    </ng-container>
-    <ng-container matColumnDef="type">
-        <th mat-header-cell *matHeaderCellDef> Producer type </th>
-        <td mat-cell *matCellDef="let eiProducer"> {{this.getEIProducerTypes(eiProducer)}} </td>
-    </ng-container>
-    <ng-container matColumnDef="status">
-        <th mat-header-cell *matHeaderCellDef> Producer status </th>
-        <td mat-cell *matCellDef="let eiProducer"> {{this.getEIProducerStatus(eiProducer)}} </td>
-    </ng-container>
-    <tr mat-header-row *matHeaderRowDef="['id', 'type', 'status']"></tr>
-    <tr mat-row *matRowDef="let row; columns: ['id', 'type', 'status'];"></tr>
-</table>
+<form [formGroup]="formGroup" class="filter-form">
+    <input
+      type="text"
+      class="form-control"
+      name="searchString"
+      placeholder="Search Producer"
+      formControlName="filter"
+    />
+</form>
+<div class="table-container">
+    <table [ngClass]="{'table-dark': darkMode}" matSort
+    class="ei-coordinator-table mat-elevation-z8">
+        <tr>
+            <th>Producer ID</th>
+            <th>Producer type</th>
+            <th>Producer status</th>
+        </tr>
+        <tr *ngFor="let eiProducer of filteredProducers$ | async">
+            <td class="text-left">
+                {{eiProducer.ei_producer_id}}
+            </td>
+            <td class="text-left">
+                {{this.getEIProducerTypes(eiProducer)}}
+            </td>
+            <td class="text-left">
+                {{this.getEIProducerStatus(eiProducer)}}
+            </td>
+        </tr>
+    </table>
+</div>
 
 <br>
 <h4>Jobs</h4>
-<table mat-table EIJobTable [dataSource]="eiJobsDataSource" [ngClass]="{'table-dark': darkMode}" matSort
-    multiTemplateDataRows class="ei-coordinator-table mat-elevation-z8">
-    <ng-container matColumnDef="id">
-        <th mat-header-cell *matHeaderCellDef> Job ID </th>
-        <td mat-cell *matCellDef="let eiJob"> {{this.getDisplayName(eiJob)}} </td>
-    </ng-container>
-    <!--ng-container matColumnDef="data">
-        <th mat-header-cell *matHeaderCellDef> Job data </th>
-        <td mat-cell *matCellDef="let eiJob"> {{this.getEIJobInfo(eiJob)}} </td>
-    </ng-container-->
-    <ng-container matColumnDef="typeId">
-        <th mat-header-cell *matHeaderCellDef> Type ID </th>
-        <td mat-cell *matCellDef="let eiJob"> {{this.getEITypeId(eiJob)}} </td>
-    </ng-container>
-    <ng-container matColumnDef="owner">
-        <th mat-header-cell *matHeaderCellDef> Owner </th>
-        <td mat-cell *matCellDef="let eiJob"> {{eiJob.owner}} </td>
-    </ng-container>
-    <ng-container matColumnDef="targetUri">
-        <th mat-header-cell *matHeaderCellDef> Target URI </th>
-        <td mat-cell *matCellDef="let eiJob"> {{this.getTargetUri(eiJob)}} </td>
-    </ng-container>
-    <tr mat-header-row *matHeaderRowDef="['id', 'typeId', 'owner', 'targetUri']"></tr>
-    <tr mat-row *matRowDef="let row; columns: ['id', 'typeId', 'owner', 'targetUri'];"></tr>
-</table>
\ No newline at end of file
+<div class="table-container">
+    <table mat-table EIJobTable [dataSource]="eiJobsDataSource" [ngClass]="{'table-dark': darkMode}" matSort
+        multiTemplateDataRows class="ei-coordinator-table mat-elevation-z8">
+        <ng-container matColumnDef="id">
+            <th mat-header-cell *matHeaderCellDef> Job ID </th>
+            <td mat-cell *matCellDef="let eiJob"> {{this.getDisplayName(eiJob)}} </td>
+        </ng-container>
+        <ng-container matColumnDef="typeId">
+            <th mat-header-cell *matHeaderCellDef> Type ID </th>
+            <td mat-cell *matCellDef="let eiJob"> {{this.getEITypeId(eiJob)}} </td>
+        </ng-container>
+        <ng-container matColumnDef="owner">
+            <th mat-header-cell *matHeaderCellDef> Owner </th>
+            <td mat-cell *matCellDef="let eiJob"> {{eiJob.owner}} </td>
+        </ng-container>
+        <ng-container matColumnDef="targetUri">
+            <th mat-header-cell *matHeaderCellDef> Target URI </th>
+            <td mat-cell *matCellDef="let eiJob"> {{this.getTargetUri(eiJob)}} </td>
+        </ng-container>
+        <tr mat-header-row *matHeaderRowDef="['id', 'typeId', 'owner', 'targetUri']"></tr>
+        <tr mat-row *matRowDef="let row; columns: ['id', 'typeId', 'owner', 'targetUri'];"></tr>
+    </table>
+</div>
\ No newline at end of file
index 5038944..759f2a8 100644 (file)
   background-color: transparent;
 }
 
+.table-dark {
+  background-color: #2d2d3d;
+}
+
 .action-cell {
   display: flex;
   justify-content: flex-end;
   display: flex;
   justify-content: space-between;
   flex-wrap: wrap;
+}
+
+.table-container {
+  margin-top: 10px;
+  max-height: 300px;
+  overflow: auto;
+}
+
+.filter-form {
+  width: 200px;
 }
\ No newline at end of file
index c76bd89..7c4979e 100644 (file)
  * limitations under the License.
  * ========================LICENSE_END===================================
  */
-import { Component, OnInit, ViewChild } from '@angular/core';
+import { Component, OnInit, ViewChild, Version } from '@angular/core';
 import { MatDialog } from '@angular/material/dialog';
 import { MatSort } from '@angular/material/sort';
 import { animate, state, style, transition, trigger } from '@angular/animations';
+import { FormBuilder, FormGroup } from '@angular/forms';
+import { MatTableDataSource } from '@angular/material';
 
 import { EIService } from '../services/ei/ei.service';
 import { EIJob, EIProducer } from '../interfaces/ei.jobs';
 import { EIProducerDataSource } from './ei-producer.datasource';
 import { EIJobDataSource } from './ei-job.datasource';
 import { NotificationService } from '../services/ui/notification.service';
-import { BehaviorSubject, Observable } from 'rxjs';
+import { defer, BehaviorSubject, Observable } from 'rxjs';
+import { map, withLatestFrom, startWith, tap } from 'rxjs/operators';
 import { UiService } from '../services/ui/ui.service';
 
 class EIJobInfo {
@@ -51,34 +54,54 @@ class EIJobInfo {
 })
 export class EICoordinatorComponent implements OnInit {
 
-
     eiJobsDataSource: EIJobDataSource;
     eiProducersDataSource: EIProducerDataSource;
+    producers$: Observable<EIProducer[]>;
+    filteredProducers$: Observable<EIProducer[]>;
     @ViewChild(MatSort, { static: true }) sort: MatSort;
 
     eiJobInfo = new Map<string, EIJobInfo>();
     darkMode: boolean;
+    searchString: string;
+    formGroup: FormGroup;
+    eiProducersData: MatTableDataSource<EIProducerDataSource>;
+
 
     constructor(
         private eiSvc: EIService,
         private dialog: MatDialog,
         private notificationService: NotificationService,
-        private ui: UiService) { }
+        private ui: UiService,
+        private formBuilder: FormBuilder) {
+            this.formGroup = formBuilder.group({ filter: [""] });
+        }
 
     ngOnInit() {
         this.eiJobsDataSource = new EIJobDataSource(this.eiSvc, this.sort, this.notificationService);
         this.eiProducersDataSource = new EIProducerDataSource(this.eiSvc, this.sort, this.notificationService);
         this.eiJobsDataSource.loadTable();
-        this.eiProducersDataSource.loadTable();
+        //this.eiProducersDataSource.loadTable();
+
+        this.producers$= this.eiProducersDataSource.getProducers();
+        this.filteredProducers$ = defer(() => this.formGroup.get("filter")
+        .valueChanges.pipe(
+            startWith(""),
+            withLatestFrom(this.producers$),
+            map(([val, producers]) =>
+            !val ? producers : producers.filter((x) =>
+            x.ei_producer_id.toLowerCase().includes(val))))
+        );
+
         this.ui.darkModeState.subscribe((isDark) => {
             this.darkMode = isDark;
         });
     }
 
-    toggleListInstances(eiJob: EIJob): void {
-        const info = this.getEIJobInfo(eiJob);
-        info.isExpanded.next(!info.isExpanded.getValue());
-    }
+    ngAfterViewInit() {
+        this.eiJobsDataSource.sort = this.sort;
+        this.eiProducersDataSource.sort = this.sort;
+
+      }
 
     getEIJobInfo(eiJob: EIJob): EIJobInfo {
         let info: EIJobInfo = this.eiJobInfo.get(eiJob.ei_job_data);
index a8a786f..b0a348a 100644 (file)
@@ -58,7 +58,6 @@ export class EIJobDataSource extends DataSource<EIJob> {
                 finalize(() => this.loadingSubject.next(false))
             )
             .subscribe((instances: EIJob[]) => {
-                console.log("Jobs: " + instances);
                 this.rowCount = instances.length;
                 this.eiJobSubject.next(instances);
             });
@@ -87,12 +86,9 @@ export class EIJobDataSource extends DataSource<EIJob> {
         return data.sort((a, b) => {
             const isAsc = this.sort.direction === 'asc';
             switch (this.sort.active) {
-                case 'id': return compare(a.ei_job_identity, b.ei_job_identity, isAsc);
-                //case 'eiTypeId': return compare(a.eiTypeId, b.eiTypeId, isAsc);
-                //case 'jobResultUri': return compare(a.jobResultUri, b.jobResultUri, isAsc);
-                //case 'jobOwner': return compare(a.jobOwner, b.jobOwner, isAsc);
-                //case 'jobStatusNotificationUri': return compare(a.jobStatusNotificationUri, b.jobStatusNotificationUri, isAsc);
-                //case 'jobDefinition': return compare(a.jobDefinition, b.jobDefinition, isAsc);
+                case 'ei_job_identity': return compare(a.ei_job_identity, b.ei_job_identity, isAsc);
+                case 'owner': return compare(a.owner, b.owner, isAsc);
+                case 'ei_type_identity': return compare(a.ei_type_identity, b.ei_type_identity, isAsc);
                 default: return 0;
             }
         });
index 866d785..44af50a 100644 (file)
  * ========================LICENSE_END===================================
  */
 
-import { DataSource } from '@angular/cdk/collections';
+import { CollectionViewer, DataSource } from '@angular/cdk/collections';
 import { HttpErrorResponse } from '@angular/common/http';
 import { MatSort } from '@angular/material';
 import { Observable } from 'rxjs/Observable';
 import { BehaviorSubject } from 'rxjs/BehaviorSubject';
 import { merge } from 'rxjs';
 import { of } from 'rxjs/observable/of';
-import { catchError, finalize, map } from 'rxjs/operators';
+import { catchError, finalize, map, tap } from 'rxjs/operators';
 import { EIProducer } from '../interfaces/ei.jobs';
 import { EIService } from '../services/ei/ei.service';
 import { NotificationService } from '../services/ui/notification.service';
@@ -62,6 +62,7 @@ export class EIProducerDataSource extends DataSource<EIProducer> {
                 this.rowCount = prods.length;
                 this.producerSubject.next(prods);
             });
+            this.connect();
     }
 
     connect(): Observable<EIProducer[]> {
@@ -87,11 +88,18 @@ export class EIProducerDataSource extends DataSource<EIProducer> {
         return data.sort((a, b) => {
             const isAsc = this.sort.direction === 'asc';
             switch (this.sort.active) {
-                case 'ei_producer_id': return compare(a.ei_producer_id, b.ei_producer_id, isAsc);
+                case 'id': return compare(a.ei_producer_id, b.ei_producer_id, isAsc);
+                case 'type': return compare(a.ei_producer_types[0], b.ei_producer_types[0], isAsc);
+                case 'status': return compare(a.status, b.status, isAsc);
                 default: return 0;
             }
         });
     }
+
+    getProducers(): Observable<EIProducer[]> {
+        return this.eiSvc.getEIProducers()
+        .pipe(tap(console.log));
+    }
 }
 
 function compare(a: string, b: string, isAsc: boolean) {
index 4ead13f..29c2a8b 100644 (file)
 
 // Models of data used by the EI Coordinator
 
-export interface EIJobBis {
-  eiTypeId: string;
-  jobResultUri: string;
-  jobOwner: string;
-  jobStatusNotificationUri: string;
-  jobDefinition: any;
-}
-
 export interface EIJob {
   ei_job_identity: string;
   ei_job_data: any;
index 6d96872..79b4c44 100644 (file)
@@ -9,5 +9,15 @@
         "jobparam1": "value1_job1"
       },
       "target_uri": "https://ricsim_g3_1:8185/datadelivery"
+    },
+    {
+      "ei_job_identity": "job2",
+      "ei_type_identity": "type2",
+      "ei_job_data": {
+        "jobparam2": "value2_job2",
+        "jobparam3": "value3_job2",
+        "jobparam1": "value1_job2"
+      },
+      "target_uri": "https://ricsim_g3_1:8185/datadelivery"
     }
   ]
\ No newline at end of file
index 75cedc5..2a2be7a 100644 (file)
@@ -5,5 +5,19 @@
         "type1"
       ],
       "status": "ENABLED"
+    },
+    {
+      "ei_producer_id": "prod-2",
+      "ei_producer_types": [
+        "type2"
+      ],
+      "status": "ENABLED"
+    },
+    {
+      "ei_producer_id": "3-prod",
+      "ei_producer_types": [
+        "type1"
+      ],
+      "status": "DISABLED"
     }
   ]
\ No newline at end of file
index cbc0a55..976b7b8 100644 (file)
@@ -43,7 +43,6 @@ export class EIService {
         args.forEach(part => {
             result = result + '/' + part;
         });
-        console.log("URL: "+result);
         return result;
     }