Create feature module for Enrichment coordinator 10/5710/1
authorychacon <yennifer.chacon@est.tech>
Mon, 1 Mar 2021 08:58:28 +0000 (09:58 +0100)
committerychacon <yennifer.chacon@est.tech>
Wed, 3 Mar 2021 10:49:35 +0000 (11:49 +0100)
- Create component for EI Jobs
- Add module for EI coordinator

Issue-ID: NONRTRIC-453
Signed-off-by: ychacon <yennifer.chacon@est.tech>
Change-Id: I01ad3581e536e85631237e661050c9d319a51215

18 files changed:
webapp-frontend/src/app/app.module.ts
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.spec.ts
webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.ts
webapp-frontend/src/app/ei-coordinator/ei-coordinator.module.ts [new file with mode: 0644]
webapp-frontend/src/app/ei-coordinator/ei-job.datasource.spec.ts
webapp-frontend/src/app/ei-coordinator/ei-job.datasource.ts
webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.spec.ts
webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.ts
webapp-frontend/src/app/ei-coordinator/jobs-list/jobs-list.component.html [new file with mode: 0644]
webapp-frontend/src/app/ei-coordinator/jobs-list/jobs-list.component.scss [new file with mode: 0644]
webapp-frontend/src/app/ei-coordinator/jobs-list/jobs-list.component.spec.ts [new file with mode: 0644]
webapp-frontend/src/app/ei-coordinator/jobs-list/jobs-list.component.ts [new file with mode: 0644]
webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.html
webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.scss
webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.spec.ts
webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.ts

index 20fe471..6ea9f03 100644 (file)
@@ -57,6 +57,7 @@ import { FooterComponent } from './footer/footer.component';
 import { MainComponent } from './main/main.component';
 import { MaterialDesignFrameworkModule } from 'angular6-json-schema-form';
 import { PolicyModule } from './policy/policy.module'
+import { EiCoordinatorModule } from './ei-coordinator/ei-coordinator.module'
 import { AppComponent } from './app.component';
 import { AppRoutingModule } from './app-routing.module';
 import { SidenavListComponent } from './navigation/sidenav-list/sidenav-list.component';
@@ -64,11 +65,9 @@ import { UiService } from './services/ui/ui.service';
 import { CookieService } from 'ngx-cookie-service';
 import { NodeModulesComponent } from './node-modules/node-modules.component';
 import { EICardComponent } from './ui/ei-card/ei-card.component';
-import { EICoordinatorComponent } from './ei-coordinator/ei-coordinator.component';
 import { HttpMockRequestInterceptor } from './interceptor.mock';
 import { environment } from 'src/environments/environment';
 import { HttpRequestInterceptor } from './interceptor';
-import { ProducersListComponent } from './ei-coordinator/producers-list/producers-list.component';
 
 export const isMock = environment.mock;
 
@@ -77,13 +76,11 @@ export const isMock = environment.mock;
     AppComponent,
     ConfirmDialogComponent,
     EICardComponent,
-    EICoordinatorComponent,
     ErrorDialogComponent,
     FooterComponent,
     MainComponent,
     NodeModulesComponent,
     SidenavListComponent,
-    ProducersListComponent,
   ],
   imports: [
     AppRoutingModule,
@@ -118,6 +115,7 @@ export const isMock = environment.mock;
     MaterialDesignFrameworkModule,
     MDBBootstrapModule.forRoot(),
     PolicyModule,
+    EiCoordinatorModule,
     ReactiveFormsModule,
     ToastrModule.forRoot(),
   ],
@@ -146,7 +144,6 @@ export const isMock = environment.mock;
   providers: [
     CookieService,
     ErrorDialogService,
-    ProducersListComponent,
     UiService,
     {
       provide: HTTP_INTERCEPTORS,
index 57a87f9..3162772 100644 (file)
@@ -21,7 +21,7 @@ limitations under the License.
 <div fxLayout="row">
   <div class="nrcp-global-page-title">Enrichment Information Coordinator</div>
   <div class="refresh-button">
-        <button id="refreshButton" mat-icon-button color="primary" (click)="refreshTables()">
+    <button id="refreshButton" mat-icon-button color="primary" (click)="refreshTables()">
       <mat-icon>refresh</mat-icon>
     </button>
   </div>
@@ -29,68 +29,8 @@ limitations under the License.
 
 <br>
 <h4>Producers</h4>
-  <nrcp-producers-list></nrcp-producers-list>
+<nrcp-producers-list></nrcp-producers-list>
 
 <br>
 <h4>Jobs</h4>
-
-<div class="table-container">
-    <mat-table id="jobsTable" [dataSource]="jobsDataSource" fixedLayout
-    matSort (matSortChange)="sortJobs($event)"
-    class="ei-coordinator-table mat-elevation-z8">
-    <ng-container matColumnDef="id">
-      <mat-header-cell *matHeaderCellDef mat-sort-header>
-        <div (click)="stopSort($event)">
-          <form style="display: flex" [formGroup]="jobsFormControl">
-            <mat-form-field>
-                        <input id="jobIdFilter" matInput formControlName="id">
-              <mat-placeholder>Job ID</mat-placeholder>
-            </mat-form-field>
-          </form>
-        </div>
-      </mat-header-cell>
-            <mat-cell *matCellDef="let eiJob"> {{eiJob.ei_job_identity}} </mat-cell>
-    </ng-container>
-    <ng-container matColumnDef="typeId">
-      <mat-header-cell *matHeaderCellDef mat-sort-header>
-        <div (click)="stopSort($event)">
-          <form style="display: flex" [formGroup]="jobsFormControl">
-            <mat-form-field>
-                        <input id="jobTypeIdFilter" matInput formControlName="typeId">
-              <mat-placeholder>Type ID</mat-placeholder>
-            </mat-form-field>
-          </form>
-        </div>
-      </mat-header-cell>
-            <mat-cell *matCellDef="let eiJob">{{this.getJobTypeId(eiJob)}} </mat-cell>
-    </ng-container>
-    <ng-container matColumnDef="owner">
-      <mat-header-cell *matHeaderCellDef mat-sort-header>
-        <div (click)="stopSort($event)">
-          <form style="display: flex" [formGroup]="jobsFormControl">
-            <mat-form-field>
-                        <input id="jobOwnerFilter" matInput formControlName="owner">
-              <mat-placeholder>Owner</mat-placeholder>
-            </mat-form-field>
-          </form>
-        </div>
-      </mat-header-cell>
-            <mat-cell *matCellDef="let eiJob">{{this.getJobOwner(eiJob)}} </mat-cell>
-    </ng-container>
-    <ng-container matColumnDef="targetUri">
-      <mat-header-cell *matHeaderCellDef mat-sort-header>
-        <div (click)="stopSort($event)">
-          <form style="display: flex" [formGroup]="jobsFormControl">
-            <mat-form-field>
-                        <input id="jobTargetUriFilter" matInput formControlName="targetUri">
-              <mat-placeholder>Target URI</mat-placeholder>
-            </mat-form-field>
-          </form>
-        </div>
-      </mat-header-cell>
-            <mat-cell *matCellDef="let eiJob"> {{eiJob.target_uri}}  </mat-cell>
-    </ng-container>
-    <mat-header-row *matHeaderRowDef="['id', 'typeId', 'owner', 'targetUri']"></mat-header-row>
-    <mat-row *matRowDef="let row; columns: ['id', 'typeId', 'owner', 'targetUri'];"></mat-row>
-  </mat-table>
-</div>
\ No newline at end of file
+<nrcp-jobs-list></nrcp-jobs-list>
\ No newline at end of file
index 109d883..31a6b18 100644 (file)
  * limitations under the License.
  * ========================LICENSE_END===================================
  */
-
-.ei-coordinator-table {
-  width: 100%;
-  min-height: 150px;
-  margin-top: 10px;
-  margin-bottom: 10px;
-  background-color: transparent;
-}
-
-.table-dark {
-  background-color: #2d2d3d;
-}
-
 .display-none {
   display: none;
 }
   display: flex;
   justify-content: space-between;
   flex-wrap: wrap;
-}
-
-.table-container {
-  margin-top: 10px;
-  max-height: 300px;
-  overflow: auto;
-}
-
-.filter-form {
-  width: 200px;
-}
-
-.mat-form-field {
-  font-size: 14px;
-  width: 100%;
-}
+}
\ No newline at end of file
index 5cda8e5..7c50ca0 100644 (file)
  */
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
-import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
-import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
+import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
 import { HarnessLoader } from '@angular/cdk/testing';
 import { MatButtonModule } from '@angular/material/button';
 import { MatButtonHarness } from '@angular/material/button/testing';
 import { MatIconModule } from '@angular/material/icon';
-import { MatInputHarness } from '@angular/material/input/testing'
 import { MatTableModule } from '@angular/material/table';
-import { MatTableHarness } from '@angular/material/table/testing';
 import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
-import { of } from 'rxjs';
 
 import { EICoordinatorComponent } from './ei-coordinator.component';
-import { EIJobDataSource } from './ei-job.datasource';
 import { UiService } from '../services/ui/ui.service';
-import { EIJob } from '../interfaces/ei.types';
 import { ProducersListComponent } from './producers-list/producers-list.component';
+import { JobsListComponent } from './jobs-list/jobs-list.component';
 
 describe('EICoordinatorComponent', () => {
   let component: EICoordinatorComponent;
   let fixture: ComponentFixture<EICoordinatorComponent>;
   let loader: HarnessLoader;
-  let producersListSpy: jasmine.SpyObj<ProducersListComponent>;
-  let jobDataSourceSpy: jasmine.SpyObj<EIJobDataSource>;
-
-  const job1 = {
-    ei_job_identity: 'job1',
-    ei_type_identity: 'type1',
-    owner: 'owner1',
-    target_uri: 'http://one'
-  } as EIJob;
-  const job2 = {
-    ei_job_identity: 'job2',
-    ei_type_identity: 'type2',
-    owner: 'owner2',
-    target_uri: 'http://two'
-  } as EIJob;
 
   beforeEach(async () => {
-    producersListSpy = jasmine.createSpyObj('producersListSpy', ['refresh']);
-    jobDataSourceSpy = jasmine.createSpyObj('EIJobDataSource', [ 'loadJobs', 'eiJobs', 'eiJobsSubject' ]);
-
-    jobDataSourceSpy.eiJobsSubject.and.returnValue(of([ job1, job2 ]));
 
     await TestBed.configureTestingModule({
       imports: [
         MatButtonModule,
         MatIconModule,
         MatTableModule,
-        BrowserAnimationsModule,
-        ReactiveFormsModule
+        BrowserAnimationsModule
       ],
       schemas: [
         CUSTOM_ELEMENTS_SCHEMA
       ],
       declarations: [
-        EICoordinatorComponent
+        EICoordinatorComponent,
+        JobsListStubComponent,
+        ProducerListStubComponent,
       ],
       providers: [
-        { provide: ProducersListComponent, useValue: producersListSpy },
-        { provide: EIJobDataSource, useValue: jobDataSourceSpy },
-        UiService,
-        FormBuilder,
+        UiService
       ]
     })
       .compileComponents();
 
     fixture = TestBed.createComponent(EICoordinatorComponent);
     component = fixture.componentInstance;
+
     fixture.detectChanges();
     loader = TestbedHarnessEnvironment.loader(fixture);
   });
@@ -97,7 +72,7 @@ describe('EICoordinatorComponent', () => {
   });
 
   describe('#content', () => {
-    it('should contain refresh button with coorect icon', async () => {
+    it('should contain refresh button with correct icon', async () => {
       let refreshButton = await loader.getHarness(MatButtonHarness.with({ selector: '#refreshButton' }));
       expect(refreshButton).toBeTruthy();
       expect(await refreshButton.getText()).toEqual('refresh');
@@ -108,12 +83,9 @@ describe('EICoordinatorComponent', () => {
       expect(producersTableComponent).toBeTruthy();
     });
 
-    it('should contain jobs table with correct columns', async () => {
-      let producersTable = await loader.getHarness(MatTableHarness.with({ selector: '#jobsTable' }));
-      let headerRow = (await producersTable.getHeaderRows())[0];
-      let headers = await headerRow.getCellTextByColumnName();
-
-      expect(headers).toEqual({ id: 'Job ID', typeId: 'Type ID', owner: 'Owner', targetUri: 'Target URI' });
+    it('should contain jobs table', async () => {
+      const jobsComponent = fixture.debugElement.nativeElement.querySelector('nrcp-jobs-list');
+      expect(jobsComponent).toBeTruthy();
     });
 
     it('should set correct dark mode from UIService', () => {
@@ -128,79 +100,41 @@ describe('EICoordinatorComponent', () => {
 
     it('should refresh tables', async () => {
       let refreshButton = await loader.getHarness(MatButtonHarness.with({ selector: '#refreshButton' }));
+      spyOn(component.producersList, 'refresh');
+      spyOn(component.jobComponent, 'refresh');
       await refreshButton.click();
 
-      expect(producersListSpy.refresh).toHaveBeenCalled();
+      expect(component.jobComponent.refresh).toHaveBeenCalled();
+      expect(component.producersList.refresh).toHaveBeenCalled();
     });
   });
 
-  describe('#jobsTable', () => {
-    const expectedJob1Row = { id: 'job1', typeId: 'type1', owner: 'owner1', targetUri: 'http://one' };
-    beforeEach(() => {
-      const jobs: EIJob[] = [ job1, job2 ];
-      jobDataSourceSpy.eiJobsSubject.and.returnValue(of(jobs));
-    });
-
-    it('should contain data after initialization', async () => {
-      component.ngOnInit();
-      const expectedJobRows = [
-        expectedJob1Row,
-        { id: 'job2', typeId: 'type2', owner: 'owner2', targetUri: 'http://two' }
-      ];
-      let jobsTable = await loader.getHarness(MatTableHarness.with({ selector: '#jobsTable' }));
-      let jobRows = await jobsTable.getRows();
-      expect(jobRows.length).toEqual(2);
-      jobRows.forEach(row => {
-        row.getCellTextByColumnName().then(values => {
-          expect(expectedJobRows).toContain(jasmine.objectContaining(values));
-        });
-      });
-    });
-
-    it('job defaults', async () => {
-      const jobMissingProperties = {
-        ei_job_identity: 'job1',
-        target_uri: 'http://one'
-      } as EIJob;
-      const jobs: EIJob[] = [jobMissingProperties];
-      jobDataSourceSpy.eiJobsSubject.and.returnValue(of(jobs));
-      component.ngOnInit();
-
-      const expectedJobRow = { id: 'job1', typeId: '< No type >', owner: '< No owner >', targetUri: 'http://one' };
-      let jobsTable = await loader.getHarness(MatTableHarness.with({ selector: '#jobsTable' }));
-      let jobRows = await jobsTable.getRows();
-      expect(await jobRows[0].getCellTextByColumnName()).toEqual(expectedJobRow);
-    });
+  @Component({
+    selector: 'nrcp-jobs-list',
+    template: '',
+    providers: [
+      {
+        provide: JobsListComponent,
+        useClass: JobsListStubComponent
+      }
+    ]
+  })
+  class JobsListStubComponent {
+    refresh() { }
+  }
+
+  @Component({
+    selector: 'nrcp-producers-list',
+    template: '',
+    providers: [
+      {
+        provide: ProducersListComponent,
+        useClass: ProducerListStubComponent
+      }
+    ]
+  })
+  class ProducerListStubComponent {
+    refresh() { }
+  }
 
-    it('filtering', async () => {
-      component.ngOnInit();
-      let jobsTable = await loader.getHarness(MatTableHarness.with({ selector: '#jobsTable' }));
-
-      let idFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#jobIdFilter' }));
-      await idFilterInput.setValue("1");
-      let jobRows = await jobsTable.getRows();
-      expect(jobRows.length).toEqual(1);
-      expect(await jobRows[0].getCellTextByColumnName()).toEqual(expectedJob1Row);
-
-      idFilterInput.setValue('');
-      let typeIdFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#jobTypeIdFilter' }));
-      await typeIdFilterInput.setValue("1");
-      jobRows = await jobsTable.getRows();
-      expect(jobRows.length).toEqual(1);
-
-      typeIdFilterInput.setValue('');
-      let ownerFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#jobOwnerFilter' }));
-      await ownerFilterInput.setValue("1");
-      jobRows = await jobsTable.getRows();
-      expect(jobRows.length).toEqual(1);
-      expect(await jobRows[0].getCellTextByColumnName()).toEqual(expectedJob1Row);
-
-      ownerFilterInput.setValue('');
-      let targetUriFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#jobTargetUriFilter' }));
-      await targetUriFilterInput.setValue("one");
-      jobRows = await jobsTable.getRows();
-      expect(jobRows.length).toEqual(1);
-      expect(await jobRows[0].getCellTextByColumnName()).toEqual(expectedJob1Row);
-    });
-  });
 });
index 79b7129..d531948 100644 (file)
  * limitations under the License.
  * ========================LICENSE_END===================================
  */
-import { Component, OnInit } from '@angular/core';
-import { Sort } from '@angular/material/sort';
-import { FormBuilder, FormGroup, AbstractControl } from '@angular/forms';
-import { MatTableDataSource } from '@angular/material/table';
+import { Component, OnInit, ViewChild } from '@angular/core';
 
-import { EIJob } from '../interfaces/ei.types';
-import { EIJobDataSource } from './ei-job.datasource';
 import { UiService } from '../services/ui/ui.service';
+import { JobsListComponent } from './jobs-list/jobs-list.component';
 import { ProducersListComponent } from './producers-list/producers-list.component';
 
 @Component({
     selector: 'nrcp-ei-coordinator',
     templateUrl: './ei-coordinator.component.html',
-    styleUrls: ['./ei-coordinator.component.scss']
+    styleUrls: ['./ei-coordinator.component.scss'],
+    providers: [
+        ProducersListComponent,
+        JobsListComponent
+    ]
 })
 export class EICoordinatorComponent implements OnInit {
 
     darkMode: boolean;
-    formGroup: FormGroup;
-    jobsDataSource: MatTableDataSource<EIJob> = new MatTableDataSource<EIJob>();
+    @ViewChild(ProducersListComponent) producersList: ProducersListComponent;
+    @ViewChild(JobsListComponent) jobComponent: JobsListComponent;
 
-    readonly jobsFormControl: AbstractControl;
 
     constructor(
-        private producersList: ProducersListComponent,
-        private eiJobsDataSource: EIJobDataSource,
-        private ui: UiService,
-        private formBuilder: FormBuilder) {
-            this.formGroup = formBuilder.group({ filter: [""] });
-
-            this.jobsFormControl = formBuilder.group({
-                id: '',
-                typeId: '',
-                owner: '',
-                targetUri:''
-            });
+        private ui: UiService) {
     }
 
     ngOnInit() {
-        this.eiJobsDataSource.loadJobs();
-
-        this.eiJobsDataSource.eiJobsSubject().subscribe((data) => {
-            this.jobsDataSource.data = data;
-        });
-
-        this.jobsFormControl.valueChanges.subscribe(value => {
-            const filter = {...value, id: value.id.trim().toLowerCase()} as string;
-            this.jobsDataSource.filter = filter;
-        });
-
-        this.jobsDataSource.filterPredicate = ((data: EIJob, filter) => {
-            return this.isDataIncluding(data.ei_job_identity, filter.id)
-                && this.isDataIncluding(data.target_uri, filter.targetUri)
-                && this.isDataIncluding(data.owner, filter.owner)
-                && this.isDataIncluding(data.ei_type_identity, filter.typeId);
-          }) as (data: EIJob, filter: any) => boolean;
-
         this.ui.darkModeState.subscribe((isDark) => {
             this.darkMode = isDark;
         });
     }
 
-    sortJobs(sort: Sort){
-        const data = this.jobsDataSource.data
-        data.sort((a: EIJob, b: EIJob) => {
-            const isAsc = sort.direction === 'asc';
-            switch (sort.active) {
-              case 'id': return this.compare(a.ei_job_identity, b.ei_job_identity, isAsc);
-              case 'typeId': return this.compare(a.ei_type_identity, b.ei_type_identity, isAsc);
-              case 'owner': return this.compare(a.owner, b.owner, isAsc);
-              case 'targetUri': return this.compare(a.target_uri, b.owner, isAsc);
-              default: return 0;
-            }
-          });
-          this.jobsDataSource.data = data;
-    }
-
-    compare(a: any, b: any, isAsc: boolean) {
-      return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
-    }
-
-    stopSort(event: any){
-        event.stopPropagation();
-    }
-
-    isDataIncluding(data: string, filter: string) : boolean {
-        return !filter || data.toLowerCase().includes(filter);
-    }
-
-    getJobTypeId(eiJob: EIJob): string {
-        if (eiJob.ei_type_identity) {
-            return eiJob.ei_type_identity;
-        }
-        return '< No type >';
-    }
-
-    getJobOwner(eiJob: EIJob): string {
-        if (eiJob.owner) {
-            return eiJob.owner;
-        }
-        return '< No owner >';
-    }
     refreshTables() {
-        this.eiJobsDataSource.loadJobs();
-        this.eiJobsDataSource.eiJobsSubject().subscribe((data) => {
-            this.jobsDataSource.data = data;
-        });
-
+        this.jobComponent.refresh();
         this.producersList.refresh();
     }
 }
diff --git a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.module.ts b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.module.ts
new file mode 100644 (file)
index 0000000..1e38575
--- /dev/null
@@ -0,0 +1,63 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2021 AT&T Intellectual Property
+ * Modifications Copyright (C) 2019 Nordix Foundation
+ * Modifications Copyright (C) 2020 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule, Routes } from '@angular/router';
+import { EICoordinatorComponent } from './ei-coordinator.component';
+import { ProducersListComponent } from './producers-list/producers-list.component';
+import { JobsListComponent } from './jobs-list/jobs-list.component';
+import { MatTableModule } from '@angular/material/table';
+import { MatIconModule } from '@angular/material/icon';
+import { MatInputModule } from '@angular/material/input';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatSortModule } from '@angular/material/sort';
+import { MatButtonModule } from '@angular/material/button';
+import { FlexLayoutModule } from '@angular/flex-layout';
+
+
+const routes: Routes = [
+  { path: 'ei-coordinator', component: EICoordinatorComponent }
+];
+
+@NgModule({
+  declarations: [
+    EICoordinatorComponent,
+    ProducersListComponent,
+    JobsListComponent
+  ],
+  imports: [
+    CommonModule,
+    FlexLayoutModule,
+    MatTableModule,
+    MatIconModule,
+    MatInputModule,
+    ReactiveFormsModule,
+    FormsModule,
+    MatSortModule,
+    MatButtonModule,
+    RouterModule.forChild(routes)
+  ],
+  exports: [
+    EICoordinatorComponent
+  ]
+})
+export class EiCoordinatorModule { }
index c50f69e..2487088 100644 (file)
@@ -29,12 +29,12 @@ describe('EIJobDataSource', () => {
     let dataSource: EIJobDataSource;
     let eiServiceSpy: any;
 
-    const job = { ei_job_identity: '1', ei_job_data: 'data', ei_type_identity: 'Type ID 1',  target_uri: 'hhtp://url', owner: 'owner'};
+    const job = { ei_job_identity: '1', ei_job_data: 'data', ei_type_identity: 'Type ID 1', target_uri: 'hhtp://url', owner: 'owner' };
 
     beforeEach(() => {
         eiServiceSpy = jasmine.createSpyObj('EIService', ['getProducerIds', 'getJobsForProducer']);
 
-        eiServiceSpy.getProducerIds.and.returnValue(of([ 'producer1', 'producer2']));
+        eiServiceSpy.getProducerIds.and.returnValue(of(['producer1', 'producer2']));
         eiServiceSpy.getJobsForProducer.and.returnValue(of([job]));
         TestBed.configureTestingModule({
             imports: [ToastrModule.forRoot()],
@@ -52,7 +52,7 @@ describe('EIJobDataSource', () => {
     it('#getJobs', () => {
         dataSource.loadJobs();
         const actualJobs: EIJob[] = dataSource.eiJobs();
-        expect(actualJobs).toEqual([ job, job ]);
+        expect(actualJobs).toEqual([job, job]);
         expect(dataSource.rowCount).toEqual(2);
     });
 });
index ac4109d..b008f80 100644 (file)
@@ -59,16 +59,16 @@ export class EIJobDataSource {
         this.loadingSubject.next(true);
         this.jobs = [];
         this.eiSvc.getProducerIds().pipe(
-            mergeMap(prodIds => 
+            mergeMap(prodIds =>
                 forkJoin(prodIds.map(id => this.eiSvc.getJobsForProducer(id)))),
             mergeMap(result => result),
             finalize(() => this.loadingSubject.next(false))
         ).subscribe(result => {
             this.jobs = this.jobs.concat(result);
             this.jobsSubject.next(this.jobs);
-        } );       
+        });
         this.rowCount = this.jobs.length;
     }
 
+
 }
index c519b12..d1f22e2 100644 (file)
@@ -30,10 +30,10 @@ describe('EIProducerDataSource', () => {
     let eiServiceSpy: any;
 
     let producer1 = {
-        supported_ei_types: [ 'type1', 'type2' ]
+        supported_ei_types: ['type1', 'type2']
     } as ProducerRegistrationInfo;
     let producer2 = {
-        supported_ei_types: [ 'type3', 'type4' ]
+        supported_ei_types: ['type3', 'type4']
     } as ProducerRegistrationInfo;
     let producerStatus1 = {
         operational_state: OperationalState.ENABLED
@@ -44,19 +44,19 @@ describe('EIProducerDataSource', () => {
 
     let expectedProducer1 = {
         ei_producer_id: 'producer1',
-        ei_producer_types: [ 'type1', 'type2' ],
+        ei_producer_types: ['type1', 'type2'],
         status: 'ENABLED'
     } as EIProducer;
     let expectedProducer2 = {
         ei_producer_id: 'producer2',
-        ei_producer_types: [ 'type3', 'type4' ],
+        ei_producer_types: ['type3', 'type4'],
         status: 'DISABLED'
     } as EIProducer;
 
     beforeEach(() => {
         eiServiceSpy = jasmine.createSpyObj('EIService', ['getProducerIds', 'getProducer', 'getProducerStatus']);
 
-        eiServiceSpy.getProducerIds.and.returnValue(of([ 'producer1', 'producer2']));
+        eiServiceSpy.getProducerIds.and.returnValue(of(['producer1', 'producer2']));
         eiServiceSpy.getProducer.and.returnValues(of(producer1), of(producer2));
         eiServiceSpy.getProducerStatus.and.returnValues(of(producerStatus1), of(producerStatus2));
         TestBed.configureTestingModule({
@@ -75,7 +75,7 @@ describe('EIProducerDataSource', () => {
     it('#loadProducers', () => {
         dataSource.loadProducers();
         const actualProducers: EIProducer[] = dataSource.eiProducers();
-        expect(actualProducers).toEqual([ expectedProducer1, expectedProducer2 ]);
+        expect(actualProducers).toEqual([expectedProducer1, expectedProducer2]);
         expect(dataSource.rowCount).toEqual(2);
     });
 });
index 439352d..cb4809c 100644 (file)
@@ -59,7 +59,7 @@ export class EIProducerDataSource {
         this.producers = [];
 
         this.eiSvc.getProducerIds().pipe(
-            mergeMap(prodIds => 
+            mergeMap(prodIds =>
                 forkJoin(prodIds.map(id => {
                     return forkJoin([
                         of(id),
@@ -67,7 +67,7 @@ export class EIProducerDataSource {
                         this.eiSvc.getProducerStatus(id)
                     ])
                 })
-            )),
+                )),
             finalize(() => this.loadingSubject.next(false))
         ).subscribe(result => {
             this.producers = result.map(producer => {
diff --git a/webapp-frontend/src/app/ei-coordinator/jobs-list/jobs-list.component.html b/webapp-frontend/src/app/ei-coordinator/jobs-list/jobs-list.component.html
new file mode 100644 (file)
index 0000000..840cc95
--- /dev/null
@@ -0,0 +1,78 @@
+<!--
+========================LICENSE_START=================================
+O-RAN-SC
+%%
+Copyright (C) 2021 Nordix Foundation
+%%
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+========================LICENSE_END===================================
+-->
+<div class="table-container">
+    <mat-table id="jobsTable" [dataSource]="jobsDataSource" fixedLayout matSort (matSortChange)="sortJobs($event)"
+        class="ei-coordinator-table mat-elevation-z8">
+        <ng-container matColumnDef="id">
+            <mat-header-cell *matHeaderCellDef mat-sort-header>
+                <div (click)="stopSort($event)">
+                    <form style="display: flex" [formGroup]="jobForm">
+                        <mat-form-field>
+                            <input id="jobIdFilter" matInput formControlName="id">
+                            <mat-placeholder>Job ID</mat-placeholder>
+                        </mat-form-field>
+                    </form>
+                </div>
+            </mat-header-cell>
+            <mat-cell *matCellDef="let eiJob"> {{eiJob.ei_job_identity}} </mat-cell>
+        </ng-container>
+        <ng-container matColumnDef="typeId">
+            <mat-header-cell *matHeaderCellDef mat-sort-header>
+                <div (click)="stopSort($event)">
+                    <form style="display: flex" [formGroup]="jobForm">
+                        <mat-form-field>
+                            <input id="jobTypeIdFilter" matInput formControlName="typeId">
+                            <mat-placeholder>Type ID</mat-placeholder>
+                        </mat-form-field>
+                    </form>
+                </div>
+            </mat-header-cell>
+            <mat-cell *matCellDef="let eiJob">{{this.getJobTypeId(eiJob)}} </mat-cell>
+        </ng-container>
+        <ng-container matColumnDef="owner">
+            <mat-header-cell *matHeaderCellDef mat-sort-header>
+                <div (click)="stopSort($event)">
+                    <form style="display: flex" [formGroup]="jobForm">
+                        <mat-form-field>
+                            <input id="jobOwnerFilter" matInput formControlName="owner">
+                            <mat-placeholder>Owner</mat-placeholder>
+                        </mat-form-field>
+                    </form>
+                </div>
+            </mat-header-cell>
+            <mat-cell *matCellDef="let eiJob">{{this.getJobOwner(eiJob)}} </mat-cell>
+        </ng-container>
+        <ng-container matColumnDef="targetUri">
+            <mat-header-cell *matHeaderCellDef mat-sort-header>
+                <div (click)="stopSort($event)">
+                    <form style="display: flex" [formGroup]="jobForm">
+                        <mat-form-field>
+                            <input id="jobTargetUriFilter" matInput formControlName="targetUri">
+                            <mat-placeholder>Target URI</mat-placeholder>
+                        </mat-form-field>
+                    </form>
+                </div>
+            </mat-header-cell>
+            <mat-cell *matCellDef="let eiJob"> {{eiJob.target_uri}} </mat-cell>
+        </ng-container>
+        <mat-header-row *matHeaderRowDef="['id', 'typeId', 'owner', 'targetUri']"></mat-header-row>
+        <mat-row *matRowDef="let row; columns: ['id', 'typeId', 'owner', 'targetUri'];"></mat-row>
+    </mat-table>
+</div>
\ No newline at end of file
diff --git a/webapp-frontend/src/app/ei-coordinator/jobs-list/jobs-list.component.scss b/webapp-frontend/src/app/ei-coordinator/jobs-list/jobs-list.component.scss
new file mode 100644 (file)
index 0000000..d0f2ee7
--- /dev/null
@@ -0,0 +1,31 @@
+/*-\r
+ * ========================LICENSE_START=================================\r
+ * O-RAN-SC\r
+ * %%\r
+ * Copyright (C) 2021 Nordix Foundation\r
+ * %%\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ========================LICENSE_END===================================\r
+ */\r
+.ei-coordinator-table {\r
+    width: 100%;\r
+    min-height: 150px;\r
+    margin-top: 10px;\r
+    margin-bottom: 10px;\r
+    background-color: transparent;\r
+}\r
+\r
+.mat-form-field {\r
+    font-size: 14px;\r
+    width: 100%;\r
+}
\ No newline at end of file
diff --git a/webapp-frontend/src/app/ei-coordinator/jobs-list/jobs-list.component.spec.ts b/webapp-frontend/src/app/ei-coordinator/jobs-list/jobs-list.component.spec.ts
new file mode 100644 (file)
index 0000000..24750eb
--- /dev/null
@@ -0,0 +1,161 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2021 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { HarnessLoader } from '@angular/cdk/testing';
+import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule, FormBuilder } from '@angular/forms';
+import { MatInputHarness } from '@angular/material/input/testing';
+import { MatTableModule } from '@angular/material/table';
+import { MatTableHarness } from '@angular/material/table/testing';
+import { of } from 'rxjs/observable/of';
+import { EIJob } from 'src/app/interfaces/ei.types';
+import { UiService } from 'src/app/services/ui/ui.service';
+import { EIJobDataSource } from '../ei-job.datasource';
+
+import { JobsListComponent } from './jobs-list.component';
+
+describe('JobsListComponent', () => {
+  let component: JobsListComponent;
+  let fixture: ComponentFixture<JobsListComponent>;
+  let loader: HarnessLoader;
+  let eiJobComponent: jasmine.SpyObj<JobsListComponent>;
+  let jobDataSourceSpy: jasmine.SpyObj<EIJobDataSource>;
+
+  const job1 = {
+    ei_job_identity: 'job1',
+    ei_type_identity: 'type1',
+    owner: 'owner1',
+    target_uri: 'http://one'
+  } as EIJob;
+  const job2 = {
+    ei_job_identity: 'job2',
+    ei_type_identity: 'type2',
+    owner: 'owner2',
+    target_uri: 'http://two'
+  } as EIJob;
+
+  beforeEach(async(() => {
+    eiJobComponent = jasmine.createSpyObj('producersListSpy', ['refresh']);
+    jobDataSourceSpy = jasmine.createSpyObj('EIJobDataSource', ['loadJobs', 'eiJobs', 'eiJobsSubject']);
+
+    jobDataSourceSpy.eiJobsSubject.and.returnValue(of([job1, job2]));
+
+    TestBed.configureTestingModule({
+      imports: [
+        MatTableModule,
+        ReactiveFormsModule
+      ],
+      schemas: [
+        CUSTOM_ELEMENTS_SCHEMA
+      ],
+      declarations: [JobsListComponent],
+      providers: [
+        { provide: EIJobDataSource, useValue: jobDataSourceSpy },
+        UiService,
+        FormBuilder,
+      ]
+    })
+      .compileComponents();
+  }));
+
+  const expectedJob1Row = { id: 'job1', typeId: 'type1', owner: 'owner1', targetUri: 'http://one' };
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(JobsListComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+    loader = TestbedHarnessEnvironment.loader(fixture);
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  it('should contain job table with correct columns', async () => {
+    let producersTable = await loader.getHarness(MatTableHarness.with({ selector: '#jobsTable' }));
+    let headerRow = (await producersTable.getHeaderRows())[0];
+    let headers = await headerRow.getCellTextByColumnName();
+
+    expect(headers).toEqual({ id: 'Job ID', typeId: 'Type ID', owner: 'Owner', targetUri: 'Target URI' });
+  });
+
+  it('should contain data after initialization', async () => {
+    component.ngOnInit();
+    const expectedJobRows = [
+      expectedJob1Row,
+      { id: 'job2', typeId: 'type2', owner: 'owner2', targetUri: 'http://two' }
+    ];
+    let jobsTable = await loader.getHarness(MatTableHarness.with({ selector: '#jobsTable' }));
+    let jobRows = await jobsTable.getRows();
+    expect(jobRows.length).toEqual(2);
+    jobRows.forEach(row => {
+      row.getCellTextByColumnName().then(values => {
+        expect(expectedJobRows).toContain(jasmine.objectContaining(values));
+      });
+    });
+  });
+
+  it('should display default values for non required properties ', async () => {
+    const jobMissingProperties = {
+      ei_job_identity: 'job1',
+      target_uri: 'http://one'
+    } as EIJob;
+    const jobs: EIJob[] = [jobMissingProperties];
+    jobDataSourceSpy.eiJobsSubject.and.returnValue(of(jobs));
+    component.ngOnInit();
+
+    const expectedJobRow = { id: 'job1', typeId: '< No type >', owner: '< No owner >', targetUri: 'http://one' };
+    let jobsTable = await loader.getHarness(MatTableHarness.with({ selector: '#jobsTable' }));
+    let jobRows = await jobsTable.getRows();
+    expect(await jobRows[0].getCellTextByColumnName()).toEqual(expectedJobRow);
+  });
+
+  it('filtering', async () => {
+    component.ngOnInit();
+    let jobsTable = await loader.getHarness(MatTableHarness.with({ selector: '#jobsTable' }));
+
+    let idFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#jobIdFilter' }));
+    await idFilterInput.setValue("1");
+    let jobRows = await jobsTable.getRows();
+    expect(jobRows.length).toEqual(1);
+    expect(await jobRows[0].getCellTextByColumnName()).toEqual(expectedJob1Row);
+
+    idFilterInput.setValue('');
+    let typeIdFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#jobTypeIdFilter' }));
+    await typeIdFilterInput.setValue("1");
+    jobRows = await jobsTable.getRows();
+    expect(jobRows.length).toEqual(1);
+
+    typeIdFilterInput.setValue('');
+    let ownerFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#jobOwnerFilter' }));
+    await ownerFilterInput.setValue("1");
+    jobRows = await jobsTable.getRows();
+    expect(jobRows.length).toEqual(1);
+    expect(await jobRows[0].getCellTextByColumnName()).toEqual(expectedJob1Row);
+
+    ownerFilterInput.setValue('');
+    let targetUriFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#jobTargetUriFilter' }));
+    await targetUriFilterInput.setValue("one");
+    jobRows = await jobsTable.getRows();
+    expect(jobRows.length).toEqual(1);
+    expect(await jobRows[0].getCellTextByColumnName()).toEqual(expectedJob1Row);
+  });
+});
diff --git a/webapp-frontend/src/app/ei-coordinator/jobs-list/jobs-list.component.ts b/webapp-frontend/src/app/ei-coordinator/jobs-list/jobs-list.component.ts
new file mode 100644 (file)
index 0000000..5208112
--- /dev/null
@@ -0,0 +1,121 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2021 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { Component, OnInit } from '@angular/core';
+import { FormControl, FormGroup } from '@angular/forms';
+import { Sort } from '@angular/material/sort';
+import { MatTableDataSource } from '@angular/material/table';
+import { EIJob } from 'src/app/interfaces/ei.types';
+import { UiService } from 'src/app/services/ui/ui.service';
+import { EIJobDataSource } from '../ei-job.datasource';
+
+@Component({
+  selector: 'nrcp-jobs-list',
+  templateUrl: './jobs-list.component.html',
+  styleUrls: ['./jobs-list.component.scss']
+})
+export class JobsListComponent implements OnInit {
+  darkMode: boolean;
+  jobsDataSource: MatTableDataSource<EIJob> = new MatTableDataSource<EIJob>();
+
+  jobForm: FormGroup;
+
+  constructor(
+    private eiJobsDataSource: EIJobDataSource,
+    private ui: UiService
+  ) {
+    this.jobForm = new FormGroup({
+      id: new FormControl(''),
+      typeId: new FormControl(''),
+      owner: new FormControl(''),
+      targetUri: new FormControl('')
+    });
+
+  }
+
+  ngOnInit(): void {
+    this.refresh();
+
+    this.jobForm.valueChanges.subscribe(value => {
+      const filter = { ...value, id: value.id.trim().toLowerCase() } as string;
+      this.jobsDataSource.filter = filter;
+    });
+
+    this.jobsDataSource.filterPredicate = ((data: EIJob, filter) => {
+      return this.isDataIncluding(data.ei_job_identity, filter.id)
+        && this.isDataIncluding(data.target_uri, filter.targetUri)
+        && this.isDataIncluding(data.owner, filter.owner)
+        && this.isDataIncluding(data.ei_type_identity, filter.typeId);
+    }) as (data: EIJob, filter: any) => boolean;
+
+    this.ui.darkModeState.subscribe((isDark) => {
+      this.darkMode = isDark;
+    });
+  }
+
+  sortJobs(sort: Sort) {
+    const data = this.jobsDataSource.data
+    data.sort((a: EIJob, b: EIJob) => {
+      const isAsc = sort.direction === 'asc';
+      switch (sort.active) {
+        case 'id': return this.compare(a.ei_job_identity, b.ei_job_identity, isAsc);
+        case 'typeId': return this.compare(a.ei_type_identity, b.ei_type_identity, isAsc);
+        case 'owner': return this.compare(a.owner, b.owner, isAsc);
+        case 'targetUri': return this.compare(a.target_uri, b.owner, isAsc);
+        default: return 0;
+      }
+    });
+    this.jobsDataSource.data = data;
+  }
+
+  compare(a: any, b: any, isAsc: boolean) {
+    return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
+  }
+
+  stopSort(event: any) {
+    event.stopPropagation();
+  }
+
+  isDataIncluding(data: string, filter: string): boolean {
+    return !filter || data.toLowerCase().includes(filter);
+  }
+
+  getJobTypeId(eiJob: EIJob): string {
+    if (eiJob.ei_type_identity) {
+      return eiJob.ei_type_identity;
+    }
+    return '< No type >';
+  }
+
+  getJobOwner(eiJob: EIJob): string {
+    if (eiJob.owner) {
+      return eiJob.owner;
+    }
+    return '< No owner >';
+  }
+
+  refresh() {
+    this.eiJobsDataSource.loadJobs();
+
+    this.eiJobsDataSource.eiJobsSubject().subscribe((data) => {
+      this.jobsDataSource.data = data;
+    });
+  }
+
+}
index 57e61c5..7e84ea4 100644 (file)
@@ -1,50 +1,68 @@
+<!--
+========================LICENSE_START=================================
+O-RAN-SC
+%%
+Copyright (C) 2021 Nordix Foundation
+%%
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+========================LICENSE_END===================================
+-->
 <div class="table-container">
-    <mat-table id="producersTable" [dataSource]="producersDataSource" fixedLayout
-      matSort (matSortChange)="sortProducers($event)"
-      class="ei-coordinator-table mat-elevation-z8">
-      <ng-container matColumnDef="id">
-        <mat-header-cell *matHeaderCellDef mat-sort-header>
-          <div (click)="stopSort($event)">
-          <form style="display: flex" [formGroup]="producersFormControl">
+  <mat-table id="producersTable" [dataSource]="producersDataSource" fixedLayout matSort
+    (matSortChange)="sortProducers($event)" class="ei-coordinator-table mat-elevation-z8">
+    <ng-container matColumnDef="id">
+      <mat-header-cell *matHeaderCellDef mat-sort-header>
+        <div (click)="stopSort($event)">
+          <form style="display: flex" [formGroup]="producerForm">
             <mat-form-field>
               <input id="producerIdFilter" matInput formControlName="ei_producer_id">
               <mat-placeholder>Producer ID</mat-placeholder>
             </mat-form-field>
           </form>
         </div>
-        </mat-header-cell>
-        <mat-cell *matCellDef="let eiProducer"> {{eiProducer.ei_producer_id}} </mat-cell>
-      </ng-container>
+      </mat-header-cell>
+      <mat-cell *matCellDef="let eiProducer"> {{eiProducer.ei_producer_id}} </mat-cell>
+    </ng-container>
 
-      <ng-container matColumnDef="types">
-        <mat-header-cell *matHeaderCellDef mat-sort-header>
-          <div (click)="stopSort($event)">
-          <form style="display: flex" [formGroup]="producersFormControl">
+    <ng-container matColumnDef="types">
+      <mat-header-cell *matHeaderCellDef mat-sort-header>
+        <div (click)="stopSort($event)">
+          <form style="display: flex" [formGroup]="producerForm">
             <mat-form-field>
               <input id="producerTypesFilter" matInput formControlName="ei_producer_types">
               <mat-placeholder>Producer types</mat-placeholder>
             </mat-form-field>
           </form>
-          </div>
-        </mat-header-cell>
-        <mat-cell *matCellDef="let eiProducer"> {{this.getProducerTypes(eiProducer)}} </mat-cell>
-      </ng-container>
+        </div>
+      </mat-header-cell>
+      <mat-cell *matCellDef="let eiProducer"> {{this.getProducerTypes(eiProducer)}} </mat-cell>
+    </ng-container>
 
-      <ng-container matColumnDef="status">
-        <mat-header-cell *matHeaderCellDef mat-sort-header>
-          <div (click)="stopSort($event)">
-          <form style="display: flex" [formGroup]="producersFormControl">
+    <ng-container matColumnDef="status">
+      <mat-header-cell *matHeaderCellDef mat-sort-header>
+        <div (click)="stopSort($event)">
+          <form style="display: flex" [formGroup]="producerForm">
             <mat-form-field>
               <input id="producerStatusFilter" matInput formControlName="status">
               <mat-placeholder>Producer status</mat-placeholder>
             </mat-form-field>
           </form>
-          </div>
-        </mat-header-cell>
-        <mat-cell *matCellDef="let eiProducer"> {{this.getProducerStatus(eiProducer)}} </mat-cell>
-      </ng-container>
+        </div>
+      </mat-header-cell>
+      <mat-cell *matCellDef="let eiProducer"> {{this.getProducerStatus(eiProducer)}} </mat-cell>
+    </ng-container>
 
-      <mat-header-row *matHeaderRowDef="['id', 'types', 'status']"></mat-header-row>
-      <mat-row *matRowDef="let row; columns: ['id', 'types', 'status'];"></mat-row>
-    </mat-table>
-  </div>
+    <mat-header-row *matHeaderRowDef="['id', 'types', 'status']"></mat-header-row>
+    <mat-row *matRowDef="let row; columns: ['id', 'types', 'status'];"></mat-row>
+  </mat-table>
+</div>
\ No newline at end of file
index b1963bb..a94c1a5 100644 (file)
@@ -1,7 +1,30 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2021 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
 .ei-coordinator-table {
-    width: 100%;
-    min-height: 150px;
-    margin-top: 10px;
-    margin-bottom: 10px;
-    background-color: transparent;
-  }
+  width: 100%;
+  min-height: 150px;
+  margin-top: 10px;
+  margin-bottom: 10px;
+  background-color: transparent;
+}
+.mat-form-field {
+  font-size: 14px;
+  width: 100%;
+}
\ No newline at end of file
index 2f537f4..9e4860d 100644 (file)
@@ -1,3 +1,22 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2021 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
 import { HarnessLoader } from '@angular/cdk/testing';
 import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
 import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@@ -7,8 +26,8 @@ import { MatInputHarness } from '@angular/material/input/testing';
 import { MatTableModule } from '@angular/material/table';
 import { MatTableHarness } from '@angular/material/table/testing';
 import { of } from 'rxjs/observable/of';
-import { EIProducer } from 'src/app/interfaces/ei.types';
-import { UiService } from 'src/app/services/ui/ui.service';
+import { EIProducer } from '../../interfaces/ei.types';
+import { UiService } from '../../services/ui/ui.service';
 import { EIProducerDataSource } from '../ei-producer.datasource';
 
 import { ProducersListComponent } from './producers-list.component';
index 8fc57b0..df1d0be 100644 (file)
@@ -1,9 +1,28 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2021 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
 import { Component, OnInit } from '@angular/core';
-import { AbstractControl, FormBuilder } from '@angular/forms';
+import { FormControl, FormGroup } from '@angular/forms';
 import { Sort } from '@angular/material/sort';
 import { MatTableDataSource } from '@angular/material/table';
-import { EIProducer } from 'src/app/interfaces/ei.types';
-import { UiService } from 'src/app/services/ui/ui.service';
+import { EIProducer } from '../../interfaces/ei.types';
+import { UiService } from '../../services/ui/ui.service';
 import { EIProducerDataSource } from '../ei-producer.datasource';
 
 @Component({
@@ -14,24 +33,23 @@ import { EIProducerDataSource } from '../ei-producer.datasource';
 export class ProducersListComponent implements OnInit {
   darkMode: boolean;
   producersDataSource: MatTableDataSource<EIProducer> = new MatTableDataSource<EIProducer>();
-
-  readonly producersFormControl: AbstractControl;
+  producerForm: FormGroup;
 
   constructor(
     private eiProducersDataSource: EIProducerDataSource,
-    private ui: UiService,
-    private formBuilder: FormBuilder) {
-    this.producersFormControl = formBuilder.group({
-      ei_producer_id: '',
-      ei_producer_types: '',
-      status: ''
+    private ui: UiService) {
+
+    this.producerForm = new FormGroup({
+      ei_producer_id: new FormControl(''),
+      ei_producer_types: new FormControl(''),
+      status: new FormControl('')
     });
   }
 
   ngOnInit(): void {
     this.refresh();
 
-    this.producersFormControl.valueChanges.subscribe(value => {
+    this.producerForm.valueChanges.subscribe(value => {
       const filter = { ...value, ei_producer_id: value.ei_producer_id.trim().toLowerCase() } as string;
       this.producersDataSource.filter = filter;
     });