From d5e2acb3624c6705f47bed520d1330c0e75f78e4 Mon Sep 17 00:00:00 2001 From: ychacon Date: Wed, 3 Mar 2021 13:21:26 +0100 Subject: [PATCH] Include datasource of jobs and producers into component Issue-ID: NONRTRIC-453 Signed-off-by: ychacon Change-Id: I3b743e87149c80115571e92e0bfd9696d8fef659 --- .../ei-coordinator.component.spec.ts | 12 +- .../app/ei-coordinator/ei-coordinator.component.ts | 4 +- .../app/ei-coordinator/ei-coordinator.module.ts | 4 + .../app/ei-coordinator/ei-job.datasource.spec.ts | 58 ---- .../src/app/ei-coordinator/ei-job.datasource.ts | 74 ----- .../ei-coordinator/ei-producer.datasource.spec.ts | 81 ------ .../app/ei-coordinator/ei-producer.datasource.ts | 84 ------ .../jobs-list/jobs-list.component.html | 8 +- .../jobs-list/jobs-list.component.spec.ts | 305 ++++++++++++++------- .../jobs-list/jobs-list.component.ts | 53 +++- .../producers-list/producers-list.component.html | 5 +- .../producers-list.component.spec.ts | 291 ++++++++++++-------- .../producers-list/producers-list.component.ts | 70 ++++- 13 files changed, 506 insertions(+), 543 deletions(-) delete mode 100644 webapp-frontend/src/app/ei-coordinator/ei-job.datasource.spec.ts delete mode 100644 webapp-frontend/src/app/ei-coordinator/ei-job.datasource.ts delete mode 100644 webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.spec.ts delete mode 100644 webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.ts diff --git a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.spec.ts b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.spec.ts index 7c50ca0..cdc1b84 100644 --- a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.spec.ts +++ b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.spec.ts @@ -100,12 +100,12 @@ describe('EICoordinatorComponent', () => { it('should refresh tables', async () => { let refreshButton = await loader.getHarness(MatButtonHarness.with({ selector: '#refreshButton' })); - spyOn(component.producersList, 'refresh'); - spyOn(component.jobComponent, 'refresh'); + spyOn(component.producersList, 'loadProducers'); + spyOn(component.jobComponent, 'loadJobs'); await refreshButton.click(); - expect(component.jobComponent.refresh).toHaveBeenCalled(); - expect(component.producersList.refresh).toHaveBeenCalled(); + expect(component.jobComponent.loadJobs).toHaveBeenCalled(); + expect(component.producersList.loadProducers).toHaveBeenCalled(); }); }); @@ -120,7 +120,7 @@ describe('EICoordinatorComponent', () => { ] }) class JobsListStubComponent { - refresh() { } + loadJobs() { } } @Component({ @@ -134,7 +134,7 @@ describe('EICoordinatorComponent', () => { ] }) class ProducerListStubComponent { - refresh() { } + loadProducers() { } } }); diff --git a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.ts b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.ts index d531948..1bb082c 100644 --- a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.ts +++ b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.ts @@ -50,7 +50,7 @@ export class EICoordinatorComponent implements OnInit { } refreshTables() { - this.jobComponent.refresh(); - this.producersList.refresh(); + this.jobComponent.loadJobs(); + this.producersList.loadProducers(); } } diff --git a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.module.ts b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.module.ts index cda22ce..8da3d03 100644 --- a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.module.ts +++ b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.module.ts @@ -33,6 +33,8 @@ import { MatSortModule } from '@angular/material/sort'; import { MatButtonModule } from '@angular/material/button'; import { FlexLayoutModule } from '@angular/flex-layout'; import { EiCardComponent } from './ei-card/ei-card.component'; +import { MatPaginatorModule } from '@angular/material/paginator'; +import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; const routes: Routes = [ @@ -55,7 +57,9 @@ const routes: Routes = [ ReactiveFormsModule, FormsModule, MatSortModule, + MatPaginatorModule, MatButtonModule, + MatProgressSpinnerModule, RouterModule.forChild(routes) ], exports: [ diff --git a/webapp-frontend/src/app/ei-coordinator/ei-job.datasource.spec.ts b/webapp-frontend/src/app/ei-coordinator/ei-job.datasource.spec.ts deleted file mode 100644 index 2487088..0000000 --- a/webapp-frontend/src/app/ei-coordinator/ei-job.datasource.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -/*- - * ========================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 { TestBed } from '@angular/core/testing'; -import { of } from 'rxjs'; - -import { EIJobDataSource } from './ei-job.datasource'; -import { EIService } from '../services/ei/ei.service'; -import { ToastrModule } from 'ngx-toastr'; -import { EIJob } from '../interfaces/ei.types'; - -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' }; - - beforeEach(() => { - eiServiceSpy = jasmine.createSpyObj('EIService', ['getProducerIds', 'getJobsForProducer']); - - eiServiceSpy.getProducerIds.and.returnValue(of(['producer1', 'producer2'])); - eiServiceSpy.getJobsForProducer.and.returnValue(of([job])); - TestBed.configureTestingModule({ - imports: [ToastrModule.forRoot()], - providers: [ - { provide: EIService, useValue: eiServiceSpy } - ] - }); - }); - - it('should create', () => { - dataSource = TestBed.inject(EIJobDataSource); - expect(dataSource).toBeTruthy(); - }); - - it('#getJobs', () => { - dataSource.loadJobs(); - const actualJobs: EIJob[] = dataSource.eiJobs(); - expect(actualJobs).toEqual([job, job]); - expect(dataSource.rowCount).toEqual(2); - }); -}); diff --git a/webapp-frontend/src/app/ei-coordinator/ei-job.datasource.ts b/webapp-frontend/src/app/ei-coordinator/ei-job.datasource.ts deleted file mode 100644 index b008f80..0000000 --- a/webapp-frontend/src/app/ei-coordinator/ei-job.datasource.ts +++ /dev/null @@ -1,74 +0,0 @@ -/*- - * ========================LICENSE_START================================= - * O-RAN-SC - * %% - * Copyright (C) 2019 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 { Injectable } from '@angular/core'; - -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; -import { mergeMap, finalize } from 'rxjs/operators'; -import { Observable, forkJoin } from 'rxjs'; - -import { EIJob } from '../interfaces/ei.types'; -import { EIService } from '../services/ei/ei.service'; - - -@Injectable({ - providedIn: 'root' -}) - -export class EIJobDataSource { - - private jobs: Array = []; - - public eiJobs(): EIJob[] { - return this.jobs; - } - - public eiJobsSubject(): Observable { - return this.jobsSubject.asObservable() as Observable; - } - - private loadingSubject = new BehaviorSubject(false); - private jobsSubject = new BehaviorSubject([]); - - public loading$ = this.loadingSubject.asObservable(); - - public rowCount = 1; // hide footer during intial load - - constructor( - private eiSvc: EIService) { - } - - loadJobs() { - this.loadingSubject.next(true); - this.jobs = []; - this.eiSvc.getProducerIds().pipe( - 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; - } - - -} diff --git a/webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.spec.ts b/webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.spec.ts deleted file mode 100644 index d1f22e2..0000000 --- a/webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.spec.ts +++ /dev/null @@ -1,81 +0,0 @@ -/*- - * ========================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 { TestBed } from '@angular/core/testing'; -import { of } from 'rxjs'; - -import { EIService } from '../services/ei/ei.service'; -import { ToastrModule } from 'ngx-toastr'; -import { EIProducer, OperationalState, ProducerRegistrationInfo, ProducerStatus } from '../interfaces/ei.types'; -import { EIProducerDataSource } from './ei-producer.datasource'; - -describe('EIProducerDataSource', () => { - let dataSource: EIProducerDataSource; - let eiServiceSpy: any; - - let producer1 = { - supported_ei_types: ['type1', 'type2'] - } as ProducerRegistrationInfo; - let producer2 = { - supported_ei_types: ['type3', 'type4'] - } as ProducerRegistrationInfo; - let producerStatus1 = { - operational_state: OperationalState.ENABLED - } as ProducerStatus; - let producerStatus2 = { - operational_state: OperationalState.DISABLED - } as ProducerStatus; - - let expectedProducer1 = { - ei_producer_id: 'producer1', - ei_producer_types: ['type1', 'type2'], - status: 'ENABLED' - } as EIProducer; - let expectedProducer2 = { - ei_producer_id: 'producer2', - 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.getProducer.and.returnValues(of(producer1), of(producer2)); - eiServiceSpy.getProducerStatus.and.returnValues(of(producerStatus1), of(producerStatus2)); - TestBed.configureTestingModule({ - imports: [ToastrModule.forRoot()], - providers: [ - { provide: EIService, useValue: eiServiceSpy } - ] - }); - }); - - it('should create', () => { - dataSource = TestBed.inject(EIProducerDataSource); - expect(dataSource).toBeTruthy(); - }); - - it('#loadProducers', () => { - dataSource.loadProducers(); - const actualProducers: EIProducer[] = dataSource.eiProducers(); - expect(actualProducers).toEqual([expectedProducer1, expectedProducer2]); - expect(dataSource.rowCount).toEqual(2); - }); -}); diff --git a/webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.ts b/webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.ts deleted file mode 100644 index cb4809c..0000000 --- a/webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.ts +++ /dev/null @@ -1,84 +0,0 @@ -/*- - * ========================LICENSE_START================================= - * O-RAN-SC - * %% - * Copyright (C) 2019 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 { Injectable } from '@angular/core'; - -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; -import { mergeMap, finalize } from 'rxjs/operators'; -import { Observable, forkJoin, of } from 'rxjs'; - -import { EIProducer } from '../interfaces/ei.types'; -import { EIService } from '../services/ei/ei.service'; - -@Injectable({ - providedIn: 'root' -}) - -export class EIProducerDataSource { - - private producers: Array = []; - - public eiProducers(): EIProducer[] { - return this.producers; - } - - public eiProducersSubject(): Observable { - return this.producersSubject.asObservable() as Observable; - } - - private loadingSubject = new BehaviorSubject(false); - private producersSubject = new BehaviorSubject([]); - - public loading$ = this.loadingSubject.asObservable(); - - public rowCount = 1; // hide footer during intial load - - constructor( - private eiSvc: EIService) { - } - - loadProducers() { - this.loadingSubject.next(true); - this.producers = []; - - this.eiSvc.getProducerIds().pipe( - mergeMap(prodIds => - forkJoin(prodIds.map(id => { - return forkJoin([ - of(id), - this.eiSvc.getProducer(id), - this.eiSvc.getProducerStatus(id) - ]) - }) - )), - finalize(() => this.loadingSubject.next(false)) - ).subscribe(result => { - this.producers = result.map(producer => { - let eiProducer = {}; - eiProducer.ei_producer_id = producer[0]; - eiProducer.ei_producer_types = producer[1].supported_ei_types; - eiProducer.status = producer[2].operational_state.toString(); - return eiProducer; - }); - this.producersSubject.next(this.producers); - }); - this.rowCount = this.producers.length; - } -} \ No newline at end of file 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 index 840cc95..c7f3a20 100644 --- 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 @@ -18,8 +18,12 @@ limitations under the License. ========================LICENSE_END=================================== -->
+
+ +
+ matSortDisableClear matSortDirection="asc" class="ei-coordinator-table mat-elevation-z8">
@@ -75,4 +79,6 @@ limitations under the License. +
\ 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 index 24750eb..0e1f9d3 100644 --- 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 @@ -21,141 +21,244 @@ 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 { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; import { MatInputHarness } from '@angular/material/input/testing'; +import { MatPaginatorModule } from '@angular/material/paginator'; +import { MatSortModule } from '@angular/material/sort'; +import { MatSortHarness } from '@angular/material/sort/testing'; +import { MatPaginatorHarness } from '@angular/material/paginator/testing'; import { MatTableModule } from '@angular/material/table'; import { MatTableHarness } from '@angular/material/table/testing'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 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 { EIJob } from '../../interfaces/ei.types'; +import { EIService } from '../../services/ei/ei.service'; +import { UiService } from '../../services/ui/ui.service'; import { JobsListComponent } from './jobs-list.component'; +let component: JobsListComponent; +let fixture: ComponentFixture; + +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; + describe('JobsListComponent', () => { - let component: JobsListComponent; - let fixture: ComponentFixture; let loader: HarnessLoader; - let eiJobComponent: jasmine.SpyObj; - let jobDataSourceSpy: jasmine.SpyObj; - - 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])); + const spy = jasmine.createSpyObj('EIService', ['getProducerIds', 'getJobsForProducer']); TestBed.configureTestingModule({ imports: [ MatTableModule, - ReactiveFormsModule - ], - schemas: [ - CUSTOM_ELEMENTS_SCHEMA + MatPaginatorModule, + FormsModule, + MatSortModule, + ReactiveFormsModule, + BrowserAnimationsModule, + MatFormFieldModule, + MatInputModule ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], declarations: [JobsListComponent], providers: [ - { provide: EIJobDataSource, useValue: jobDataSourceSpy }, - UiService, - FormBuilder, + { provide: EIService, useValue: spy }, + UiService ] }) - .compileComponents(); + .compileComponents() + .then(() => { + fixture = TestBed.createComponent(JobsListComponent); + component = fixture.componentInstance; + loader = TestbedHarnessEnvironment.loader(fixture); + }); })); 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(); + describe('#content', () => { + + it('should loadJobs', () => { + setServiceSpy(); + component.loadJobs(); + const actualJobs: EIJob[] = component.jobs(); + expect(actualJobs.length).toEqual(4); + expect(actualJobs).toEqual([job1, job2, job1, job2]); + }); + + it('should contain job table with correct columns', async () => { + setServiceSpy(); + let jobsTable = await loader.getHarness(MatTableHarness.with({ selector: '#jobsTable' })); + let headerRow = (await jobsTable.getHeaderRows())[0]; + let headers = await headerRow.getCellTextByColumnName(); + + expect(headers).toEqual({ id: 'Job ID', typeId: 'Type ID', owner: 'Owner', targetUri: 'Target URI' }); + }); + + it('should set correct dark mode from UIService', () => { + setServiceSpy(); + component.ngOnInit(); + const uiService: UiService = TestBed.inject(UiService); + expect(component.darkMode).toBeTruthy(); - expect(headers).toEqual({ id: 'Job ID', typeId: 'Type ID', owner: 'Owner', targetUri: 'Target URI' }); + uiService.darkModeState.next(false); + fixture.detectChanges(); + expect(component.darkMode).toBeFalsy(); + }); }); - 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)); + describe('#jobsTable', () => { + + it('should contain data after initialization', async () => { + setServiceSpy(); + 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(4); + 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('should display default values for non required properties ', async () => { + + const jobMissingProperties = { + "ei_job_identity": "job1", + "ei_job_data": { + "jobparam2": "value2_job2", + "jobparam3": "value3_job2", + "jobparam1": "value1_job2" + }, + "target_uri": "http://one" + } as EIJob; + + let eiServiceSpy = TestBed.inject(EIService) as jasmine.SpyObj; + eiServiceSpy.getProducerIds.and.returnValue(of(['producer1'])); + eiServiceSpy.getJobsForProducer.and.returnValue(of([jobMissingProperties])); + + 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 () => { + setServiceSpy(); + component.ngOnInit(); + let jobsTable = await loader.getHarness(MatTableHarness.with({ selector: '#jobsTable' })); - 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); + let idFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#jobIdFilter' })); + await idFilterInput.setValue("1"); + let jobRows = await jobsTable.getRows(); + expect(jobRows.length).toEqual(2); + 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(2); + + typeIdFilterInput.setValue(''); + let ownerFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#jobOwnerFilter' })); + await ownerFilterInput.setValue("1"); + jobRows = await jobsTable.getRows(); + expect(jobRows.length).toEqual(2); + 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(2); + expect(await jobRows[0].getCellTextByColumnName()).toEqual(expectedJob1Row); + }); + + describe('#sorting', () => { + + it('should verify sort functionality on the table', async () => { + setServiceSpy(); + const sort = await loader.getHarness(MatSortHarness); + let headers = await sort.getSortHeaders({ sortDirection: '' }); + expect(headers.length).toBe(4); + + await headers[0].click(); + expect(await headers[0].isActive()).toBe(true); + expect(await headers[0].getSortDirection()).toBe('asc'); + + await headers[0].click(); + expect(await headers[0].getSortDirection()).toBe('desc'); + + }); + + it('should sort table asc and desc by first header', async () => { + setServiceSpy(); + const sort = await loader.getHarness(MatSortHarness); + let jobsTable = await loader.getHarness(MatTableHarness.with({ selector: '#jobsTable' })); + const firstHeader = (await sort.getSortHeaders())[0]; + expect(await firstHeader.getSortDirection()).toBe(''); + + await firstHeader.click(); + expect(await firstHeader.getSortDirection()).toBe('asc'); + let jobRows = await jobsTable.getRows(); + jobRows = await jobsTable.getRows(); + expect(await jobRows[0].getCellTextByColumnName()).toEqual(expectedJob1Row); + + await firstHeader.click(); + expect(await firstHeader.getSortDirection()).toBe('desc'); + jobRows = await jobsTable.getRows(); + expect(await jobRows[jobRows.length - 1].getCellTextByColumnName()).toEqual(expectedJob1Row); + }); + }); + + describe('#paging', () => { + it('should work properly on the table', async () => { + let eiServiceSpy = TestBed.inject(EIService) as jasmine.SpyObj; + eiServiceSpy.getProducerIds.and.returnValue(of(['producer1', 'producer2'])); + eiServiceSpy.getJobsForProducer.and.returnValue(of([job1, job2, job1])); + + const paging = await loader.getHarness(MatPaginatorHarness); + await paging.setPageSize(5); + + let jobsTable = await loader.getHarness(MatTableHarness.with({ selector: '#jobsTable' })); + let jobRows = await jobsTable.getRows(); + expect(jobRows.length).toEqual(5); + + await paging.goToNextPage(); + jobRows = await jobsTable.getRows(); + expect(jobRows.length).toEqual(1); + expect(await jobRows[jobRows.length - 1].getCellTextByColumnName()).toEqual(expectedJob1Row); + }); + }); }); }); + +function setServiceSpy() { + let eiServiceSpy = TestBed.inject(EIService) as jasmine.SpyObj; + eiServiceSpy.getProducerIds.and.returnValue(of(['producer1', 'producer2'])); + eiServiceSpy.getJobsForProducer.and.returnValue(of([job1, job2])); +} 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 index 5208112..2991c28 100644 --- 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 @@ -17,13 +17,17 @@ * limitations under the License. * ========================LICENSE_END=================================== */ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; +import { MatPaginator } from '@angular/material/paginator'; 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'; +import { forkJoin } from 'rxjs'; +import { BehaviorSubject } from 'rxjs/BehaviorSubject'; +import { mergeMap, finalize } from 'rxjs/operators'; +import { EIJob } from '../../interfaces/ei.types'; +import { EIService } from '../../services/ei/ei.service'; +import { UiService } from '../../services/ui/ui.service'; @Component({ selector: 'nrcp-jobs-list', @@ -31,13 +35,18 @@ import { EIJobDataSource } from '../ei-job.datasource'; styleUrls: ['./jobs-list.component.scss'] }) export class JobsListComponent implements OnInit { + + @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; + darkMode: boolean; jobsDataSource: MatTableDataSource = new MatTableDataSource(); - jobForm: FormGroup; + private loadingSubject = new BehaviorSubject(false); + private jobsSubject = new BehaviorSubject([]); + public loading$ = this.loadingSubject.asObservable(); constructor( - private eiJobsDataSource: EIJobDataSource, + private eiSvc: EIService, private ui: UiService ) { this.jobForm = new FormGroup({ @@ -46,11 +55,15 @@ export class JobsListComponent implements OnInit { owner: new FormControl(''), targetUri: new FormControl('') }); - } ngOnInit(): void { - this.refresh(); + this.loadJobs(); + this.jobsSubject.subscribe((data) => { + this.jobsDataSource = new MatTableDataSource(data); + //this.jobsDataSource.data = data; + this.jobsDataSource.paginator = this.paginator; + }); this.jobForm.valueChanges.subscribe(value => { const filter = { ...value, id: value.id.trim().toLowerCase() } as string; @@ -69,6 +82,12 @@ export class JobsListComponent implements OnInit { }); } + ngOnDestroy() { + if (!this.jobsSubject) this.jobsSubject.unsubscribe(); + if (!this.loadingSubject) this.loadingSubject.unsubscribe(); + if (!this.ui.darkModeState) this.ui.darkModeState.unsubscribe(); + } + sortJobs(sort: Sort) { const data = this.jobsDataSource.data data.sort((a: EIJob, b: EIJob) => { @@ -110,11 +129,21 @@ export class JobsListComponent implements OnInit { return '< No owner >'; } - refresh() { - this.eiJobsDataSource.loadJobs(); + public jobs(): EIJob[] { + return this.jobsSubject.value; + } - this.eiJobsDataSource.eiJobsSubject().subscribe((data) => { - this.jobsDataSource.data = data; + loadJobs() { + this.loadingSubject.next(true); + let jobs = []; + this.eiSvc.getProducerIds().pipe( + mergeMap(prodIds => + forkJoin(prodIds.map(id => this.eiSvc.getJobsForProducer(id)))), + mergeMap(result => result), + finalize(() => this.loadingSubject.next(false)) + ).subscribe(result => { + jobs = jobs.concat(result); + this.jobsSubject.next(jobs); }); } diff --git a/webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.html b/webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.html index 7e84ea4..8982c05 100644 --- a/webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.html +++ b/webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.html @@ -18,8 +18,9 @@ limitations under the License. ========================LICENSE_END=================================== -->
- +
diff --git a/webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.spec.ts b/webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.spec.ts index 9e4860d..ce54d18 100644 --- a/webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.spec.ts +++ b/webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.spec.ts @@ -1,63 +1,38 @@ -/*- - * ========================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 { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { MatTableHarness } from '@angular/material/table/testing'; +import { MatSortHarness } from '@angular/material/sort/testing'; +import { ProducersListComponent } from "./producers-list.component"; +import { EIService } from 'src/app/services/ei/ei.service'; +import { EIProducer, OperationalState, ProducerRegistrationInfo, ProducerStatus } from 'src/app/interfaces/ei.types'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; -import { MatInputHarness } from '@angular/material/input/testing'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatIconModule } from '@angular/material/icon'; import { MatTableModule } from '@angular/material/table'; -import { MatTableHarness } from '@angular/material/table/testing'; -import { of } from 'rxjs/observable/of'; -import { EIProducer } from '../../interfaces/ei.types'; -import { UiService } from '../../services/ui/ui.service'; -import { EIProducerDataSource } from '../ei-producer.datasource'; +import { MatInputHarness } from '@angular/material/input/testing'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { UiService } from 'src/app/services/ui/ui.service'; +import { of } from 'rxjs'; +import { MatSortModule } from '@angular/material/sort'; -import { ProducersListComponent } from './producers-list.component'; +let component: ProducersListComponent; +let fixture: ComponentFixture; describe('ProducersListComponent', () => { - let component: ProducersListComponent; - let fixture: ComponentFixture; + let loader: HarnessLoader; - let producerDataSourceSpy: jasmine.SpyObj; - - const producer1 = { - ei_producer_id: 'producer1', - ei_producer_types: ['type1', 'type2'], - status: 'ENABLED' - } as EIProducer; - const producer2 = { - ei_producer_id: 'producer2', - ei_producer_types: ['type2', 'type3'], - status: 'DISABLED' - } as EIProducer; beforeEach(async(() => { - producerDataSourceSpy = jasmine.createSpyObj('EIProducerDataSource', ['loadProducers', 'eiProducers', 'eiProducersSubject']); - - const producers: EIProducer[] = [producer1, producer2]; - producerDataSourceSpy.eiProducersSubject.and.returnValue(of(producers)); + const spy = jasmine.createSpyObj('EIService', ['getProducerIds', 'getProducer', 'getProducerStatus']); TestBed.configureTestingModule({ imports: [ + MatIconModule, MatTableModule, + MatSortModule, + BrowserAnimationsModule, ReactiveFormsModule ], schemas: [ @@ -67,93 +42,185 @@ describe('ProducersListComponent', () => { ProducersListComponent ], providers: [ - { provide: EIProducerDataSource, useValue: producerDataSourceSpy }, + { provide: EIService, useValue: spy }, UiService, - FormBuilder, ] }) - .compileComponents(); + .compileComponents() + .then(() => { + fixture = TestBed.createComponent(ProducersListComponent); + component = fixture.componentInstance; + loader = TestbedHarnessEnvironment.loader(fixture); + }); })); - const expectedProducer1Row = { id: 'producer1', types: 'type1,type2', status: 'ENABLED' }; - beforeEach(() => { - fixture = TestBed.createComponent(ProducersListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - loader = TestbedHarnessEnvironment.loader(fixture); - }); - it('should create', () => { expect(component).toBeTruthy(); }); - it('should contain producers table with correct columns', async () => { - let producersTable = await loader.getHarness(MatTableHarness.with({ selector: '#producersTable' })); - let headerRow = (await producersTable.getHeaderRows())[0]; - let headers = await headerRow.getCellTextByColumnName(); + describe('#content', () => { - expect(headers).toEqual({ id: 'Producer ID', types: 'Producer types', status: 'Producer status' }); - }); + it('should loadProducers', () => { + const producer1 = { + ei_producer_id: 'producer1', + ei_producer_types: ['type1', 'type2'], + status: 'ENABLED' + } as EIProducer; + const producer2 = { + ei_producer_id: 'producer2', + ei_producer_types: ['type2', 'type3'], + status: 'DISABLED' + } as EIProducer; + setServiceSpy(); + component.loadProducers(); + const actualProducers: EIProducer[] = component.eiProducers(); + expect(actualProducers).toEqual([producer1, producer2]); + }); - it('should contain data after initialization', async () => { - component.ngOnInit(); - const expectedProducerRows = [ - expectedProducer1Row, - { id: 'producer2', types: 'type2,type3', status: 'DISABLED' } - ]; - let producersTable = await loader.getHarness(MatTableHarness.with({ selector: '#producersTable' })); - let producerRows = await producersTable.getRows(); - expect(producerRows.length).toEqual(2); - producerRows.forEach(row => { - row.getCellTextByColumnName().then(values => { - expect(expectedProducerRows).toContain(jasmine.objectContaining(values)); - }); + it('should contain producers table with correct columns', async () => { + setServiceSpy(); + + let producersTable = await loader.getHarness(MatTableHarness.with({ selector: '#producersTable' })); + let headerRow = (await producersTable.getHeaderRows())[0]; + let headers = await headerRow.getCellTextByColumnName(); + expect(headers).toEqual({ id: 'Producer ID', types: 'Producer types', status: 'Producer status' }); + }); + + it('should set correct dark mode from UIService', () => { + setServiceSpy(); + component.ngOnInit(); + expect(component.darkMode).toBeTruthy(); + + const uiService: UiService = TestBed.inject(UiService); + uiService.darkModeState.next(false); + fixture.detectChanges(); + expect(component.darkMode).toBeFalsy(); }); }); - describe('should display default values for non required properties', () => { - it('producer defaults', async () => { - const producerMissingProperties = { - ei_producer_id: 'producer1' - } as EIProducer; - const producers: EIProducer[] = [producerMissingProperties]; - producerDataSourceSpy.eiProducersSubject.and.returnValue(of(producers)); + describe('#producersTable', () => { + + const expectedProducer1Row = { id: 'producer1', types: 'type1,type2', status: 'ENABLED' }; + + it('should contain data after initialization', async () => { + setServiceSpy(); component.ngOnInit(); + const expectedProducerRows = [ + expectedProducer1Row, + { id: 'producer2', types: 'type2,type3', status: 'DISABLED' } + ]; + let producersTable = await loader.getHarness(MatTableHarness.with({ selector: '#producersTable' })); + let producerRows = await producersTable.getRows(); + expect(producerRows.length).toEqual(2); + producerRows.forEach(row => { + row.getCellTextByColumnName().then(values => { + expect(expectedProducerRows).toContain(jasmine.objectContaining(values)); + }); + }); + }); + it('should display defaults values for non required properties', async () => { + let eiServiceSpy = TestBed.inject(EIService) as jasmine.SpyObj; + + eiServiceSpy.getProducerIds.and.returnValue(of(['producer1'])); + eiServiceSpy.getProducer.and.returnValues(of({} as ProducerRegistrationInfo)); + eiServiceSpy.getProducerStatus.and.returnValues(of({} as ProducerStatus)); + + component.ngOnInit(); const expectedProducerRow = { id: 'producer1', types: '< No types >', status: '< No status >' }; let producersTable = await loader.getHarness(MatTableHarness.with({ selector: '#producersTable' })); let producerRows = await producersTable.getRows(); expect(await producerRows[0].getCellTextByColumnName()).toEqual(expectedProducerRow); }); - }); - it('filtering', async () => { - const expectedProducer1Row = { id: 'producer1', types: 'type1,type2', status: 'ENABLED' }; - component.ngOnInit(); - let producersTable = await loader.getHarness(MatTableHarness.with({ selector: '#producersTable' })); - - let idFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#producerIdFilter' })); - await idFilterInput.setValue("1"); - let producerRows = await producersTable.getRows(); - expect(producerRows.length).toEqual(1); - expect(await producerRows[0].getCellTextByColumnName()).toEqual(expectedProducer1Row); - - idFilterInput.setValue(''); - let typesFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#producerTypesFilter' })); - await typesFilterInput.setValue("1"); - producerRows = await producersTable.getRows(); - expect(producerRows.length).toEqual(1); - expect(await producerRows[0].getCellTextByColumnName()).toEqual(expectedProducer1Row); - await typesFilterInput.setValue("2"); - producerRows = await producersTable.getRows(); - expect(producerRows.length).toEqual(2); - - typesFilterInput.setValue(''); - let statusFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#producerStatusFilter' })); - await statusFilterInput.setValue("enabled"); - producerRows = await producersTable.getRows(); - expect(producerRows.length).toEqual(1); - expect(await producerRows[0].getCellTextByColumnName()).toEqual(expectedProducer1Row); + it('filtering', async () => { + setServiceSpy(); + component.ngOnInit(); + let producersTable = await loader.getHarness(MatTableHarness.with({ selector: '#producersTable' })); + + let idFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#producerIdFilter' })); + await idFilterInput.setValue("1"); + let producerRows = await producersTable.getRows(); + expect(producerRows.length).toEqual(1); + expect(await producerRows[0].getCellTextByColumnName()).toEqual(expectedProducer1Row); + + idFilterInput.setValue(''); + let typesFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#producerTypesFilter' })); + await typesFilterInput.setValue("1"); + producerRows = await producersTable.getRows(); + expect(producerRows.length).toEqual(1); + expect(await producerRows[0].getCellTextByColumnName()).toEqual(expectedProducer1Row); + await typesFilterInput.setValue("2"); + producerRows = await producersTable.getRows(); + expect(producerRows.length).toEqual(2); + + typesFilterInput.setValue(''); + let statusFilterInput = await loader.getHarness(MatInputHarness.with({ selector: '#producerStatusFilter' })); + await statusFilterInput.setValue("enabled"); + producerRows = await producersTable.getRows(); + expect(producerRows.length).toEqual(1); + expect(await producerRows[0].getCellTextByColumnName()).toEqual(expectedProducer1Row); + }); + + describe('#sorting', () => { + + it('should verify sort functionality on the table', async () => { + setServiceSpy(); + const sort = await loader.getHarness(MatSortHarness); + let headers = await sort.getSortHeaders({ sortDirection: '' }); + expect(headers.length).toBe(3); + + await headers[0].click(); + expect(await headers[0].isActive()).toBe(true); + expect(await headers[0].getSortDirection()).toBe('asc'); + + await headers[0].click(); + expect(await headers[0].getSortDirection()).toBe('desc'); + + }); + + it('should sort table asc and desc by first header', async () => { + setServiceSpy(); + const sort = await loader.getHarness(MatSortHarness); + let producersTable = await loader.getHarness(MatTableHarness.with({ selector: '#producersTable' })); + const firstHeader = (await sort.getSortHeaders())[0]; + expect(await firstHeader.getSortDirection()).toBe(''); + + await firstHeader.click(); + expect(await firstHeader.getSortDirection()).toBe('asc'); + let prodRows = await producersTable.getRows(); + prodRows = await producersTable.getRows(); + expect(await prodRows[0].getCellTextByColumnName()).toEqual(expectedProducer1Row); + + await firstHeader.click(); + expect(await firstHeader.getSortDirection()).toBe('desc'); + prodRows = await producersTable.getRows(); + expect(await prodRows[prodRows.length - 1].getCellTextByColumnName()).toEqual(expectedProducer1Row); + }); + }); }); }); + +function setServiceSpy() { + let producerRegInfo1 = { + supported_ei_types: ['type1', 'type2'] + } as ProducerRegistrationInfo; + let producerRegInfo2 = { + supported_ei_types: ['type2', 'type3'] + } as ProducerRegistrationInfo; + let producerStatus1 = { + operational_state: OperationalState.ENABLED + } as ProducerStatus; + let producerStatus2 = { + operational_state: OperationalState.DISABLED + } as ProducerStatus; + + let eiServiceSpy = TestBed.inject(EIService) as jasmine.SpyObj; + + eiServiceSpy.getProducerIds.and.returnValue(of(['producer1', 'producer2'])); + eiServiceSpy.getProducer.and.returnValues(of(producerRegInfo1), of(producerRegInfo2)); + eiServiceSpy.getProducerStatus.and.returnValues(of(producerStatus1), of(producerStatus2)); +} + + diff --git a/webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.ts b/webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.ts index df1d0be..68f4f3f 100644 --- a/webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.ts +++ b/webapp-frontend/src/app/ei-coordinator/producers-list/producers-list.component.ts @@ -17,13 +17,16 @@ * limitations under the License. * ========================LICENSE_END=================================== */ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; -import { Sort } from '@angular/material/sort'; +import { MatSort, Sort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; +import { forkJoin, of } from 'rxjs'; +import { BehaviorSubject } from 'rxjs/BehaviorSubject'; +import { mergeMap, finalize, catchError } from 'rxjs/operators'; +import { EIService } from 'src/app/services/ei/ei.service'; import { EIProducer } from '../../interfaces/ei.types'; import { UiService } from '../../services/ui/ui.service'; -import { EIProducerDataSource } from '../ei-producer.datasource'; @Component({ selector: 'nrcp-producers-list', @@ -31,12 +34,19 @@ import { EIProducerDataSource } from '../ei-producer.datasource'; styleUrls: ['./producers-list.component.scss'] }) export class ProducersListComponent implements OnInit { - darkMode: boolean; + + @ViewChild(MatSort) sort: MatSort; + producersDataSource: MatTableDataSource = new MatTableDataSource(); producerForm: FormGroup; + darkMode: boolean; + + private loadingSubject = new BehaviorSubject(false); + private producerSubject = new BehaviorSubject([]); + public loading$ = this.loadingSubject.asObservable(); constructor( - private eiProducersDataSource: EIProducerDataSource, + private eiSvc: EIService, private ui: UiService) { this.producerForm = new FormGroup({ @@ -47,7 +57,11 @@ export class ProducersListComponent implements OnInit { } ngOnInit(): void { - this.refresh(); + this.loadProducers(); + this.producerSubject.subscribe((data) => { + this.producersDataSource = new MatTableDataSource(data); + //this.producersDataSource.data = data; + }); this.producerForm.valueChanges.subscribe(value => { const filter = { ...value, ei_producer_id: value.ei_producer_id.trim().toLowerCase() } as string; @@ -65,6 +79,12 @@ export class ProducersListComponent implements OnInit { }); } + ngOnDestroy() { + if (!this.producerSubject) this.producerSubject.unsubscribe(); + if (!this.loadingSubject) this.loadingSubject.unsubscribe(); + if (!this.ui.darkModeState) this.ui.darkModeState.unsubscribe(); + } + isDataIncluding(data: string, filter: string): boolean { return !filter || data.toLowerCase().includes(filter); } @@ -105,10 +125,40 @@ export class ProducersListComponent implements OnInit { return '< No status >'; } - refresh() { - this.eiProducersDataSource.loadProducers(); - this.eiProducersDataSource.eiProducersSubject().subscribe((data) => { - this.producersDataSource.data = data; + public eiProducers(): EIProducer[] { + return this.producerSubject.value; + } + + loadProducers() { + this.loadingSubject.next(true); + let producers = []; + + this.eiSvc.getProducerIds().pipe( + mergeMap(prodIds => + forkJoin(prodIds.map(id => { + return forkJoin([ + of(id), + this.eiSvc.getProducer(id), + this.eiSvc.getProducerStatus(id) + ]) + }) + )), + finalize(() => this.loadingSubject.next(false)), + ).subscribe(result => { + producers = result.map(producer => { + let eiProducer = {}; + eiProducer.ei_producer_id = producer[0]; + if (producer[1].supported_ei_types) { + eiProducer.ei_producer_types = producer[1].supported_ei_types; + } + if (producer[2].operational_state) { + eiProducer.status = producer[2].operational_state.toString(); + } + return eiProducer; + }); + this.producerSubject.next(producers); + }, err => { + console.error("Subscribe function error:" + err); }); } } -- 2.16.6