From: Patrik Buhr Date: Thu, 11 Feb 2021 12:25:28 +0000 (+0000) Subject: Merge "Fix the Nginx conf to start even when Upstream is unavailable" X-Git-Tag: 2.2.0~85 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=49a6c6aa1b48fb4d2a7e7fb5b80aead0b281aff5;hp=64b35796309259667d0dac6f9cdc2ad00bca53ee;p=portal%2Fnonrtric-controlpanel.git Merge "Fix the Nginx conf to start even when Upstream is unavailable" --- diff --git a/webapp-frontend/src/app/app.component.html b/webapp-frontend/src/app/app.component.html index 0f2aa0d..202afc5 100644 --- a/webapp-frontend/src/app/app.component.html +++ b/webapp-frontend/src/app/app.component.html @@ -80,7 +80,7 @@
Light diff --git a/webapp-frontend/src/app/app.component.spec.ts b/webapp-frontend/src/app/app.component.spec.ts index ed040a0..af5126c 100644 --- a/webapp-frontend/src/app/app.component.spec.ts +++ b/webapp-frontend/src/app/app.component.spec.ts @@ -26,9 +26,12 @@ import { UiService } from './services/ui/ui.service'; describe('AppComponent', () => { let fixture: ComponentFixture; + let app: AppComponent; + let cookieServiceSpy: any; + let uiService: UiService; beforeEach(async(() => { - const cookieSpy = jasmine.createSpyObj('CookieService', [ 'get' ]); + cookieServiceSpy = jasmine.createSpyObj('CookieService', [ 'get', 'put' ]); TestBed.configureTestingModule({ imports: [ RouterTestingModule @@ -40,7 +43,7 @@ describe('AppComponent', () => { AppComponent ], providers: [ - { provide: CookieService, useValue: cookieSpy }, + { provide: CookieService, useValue: cookieServiceSpy }, UiService ] }).compileComponents(); @@ -48,11 +51,12 @@ describe('AppComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(AppComponent); + app = fixture.componentInstance; + uiService = TestBed.get(UiService); fixture.detectChanges(); }); it('should create the app', () => { - const app = fixture.componentInstance; expect(app).toBeTruthy(); }); @@ -62,6 +66,16 @@ describe('AppComponent', () => { expect(ele.src).toContain('assets/oran-logo.png'); })); + it('should contain navigation menu', async(() => { + const ele = fixture.debugElement.nativeElement.querySelector('nrcp-sidenav-list'); + expect(ele).toBeTruthy(); + })); + + it('should contain dark mode selector', async(() => { + const ele = fixture.debugElement.nativeElement.querySelector('#darkModeSwitch'); + expect(ele).toBeTruthy(); + })); + it('should contain heading', async(() => { const ele = fixture.debugElement.nativeElement.querySelector('tspan'); expect(ele.textContent.trim()).toBe('Non-RT RIC Control Panel'); @@ -77,4 +91,31 @@ describe('AppComponent', () => { expect(ele).toBeTruthy(); })); }); + + describe('#darkMode', () => { + it('when dark mode value yes from cookie at start should set mode to dark', () => { + uiService.darkModeState.next(false); // Set internal state to light mode. + cookieServiceSpy.get.and.returnValue('yes'); // Cookie shall return dark mode used. + + app.ngOnInit(); + + expect(uiService.getDarkMode()).toBeTruthy(); + expect(app.darkMode).toBeTruthy(); + }); + + it('should toggle dark mode when selector is clicked', () => { + const darkModeSelector = fixture.debugElement.nativeElement.querySelector('#darkModeSwitch'); + + // Toggle to light mode + darkModeSelector.click(); + expect(uiService.getDarkMode()).toBeFalsy(); + expect(cookieServiceSpy.put).toHaveBeenCalledWith('darkMode', 'no'); + + + // Toggle to dark mode + darkModeSelector.click(); + expect(uiService.getDarkMode()).toBeTruthy(); + expect(cookieServiceSpy.put).toHaveBeenCalledWith('darkMode', 'yes'); + }); + }); }); diff --git a/webapp-frontend/src/app/app.component.ts b/webapp-frontend/src/app/app.component.ts index 544f0c4..9bbfba5 100644 --- a/webapp-frontend/src/app/app.component.ts +++ b/webapp-frontend/src/app/app.component.ts @@ -27,7 +27,6 @@ import { CookieService } from 'ngx-cookie'; styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit { - private showMenu = false; darkMode: boolean; private 'DARK_MODE_COOKIE' = 'darkMode'; @@ -45,13 +44,8 @@ export class AppComponent implements OnInit { }); } - toggleMenu() { - this.showMenu = !this.showMenu; - } - modeToggleSwitch() { this.ui.darkModeState.next(!this.darkMode); this.cookieService.put(this.DARK_MODE_COOKIE, this.darkMode ? 'yes' : 'no'); } - } diff --git a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.html b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.html index 79385a7..00ce9ad 100644 --- a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.html +++ b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.html @@ -29,59 +29,113 @@ limitations under the License.

Producers

-
- -
+
- - - - - - - - - - - -
Producer IDProducer typeProducer status
- {{eiProducer.ei_producer_id}} - - {{this.getEIProducerTypes(eiProducer)}} - - {{this.getEIProducerStatus(eiProducer)}} -
+ + + + +
+ + + Producer ID + +
+
+ {{eiProducer.ei_producer_id}} +
+ + + +
+
+ + + Producer types + +
+
+ {{this.getEIProducerTypes(eiProducer)}} +
+ + + +
+
+ + + Producer status + +
+
+ {{this.getEIProducerStatus(eiProducer)}} +
+ + + + + + + No data matching the filter "{{input.value}}" + +

Jobs

+
- + - - + +
+
+ + + Job ID + + +
+ {{this.getDisplayName(eiJob)}} - - - + +
+
+ + + Type ID + + +
+ {{this.getEITypeId(eiJob)}} + - - + +
+
+ + + Owner + + +
+ {{eiJob.owner}} - - + +
+
+ + + Target URI + + +
+ {{this.getTargetUri(eiJob)}} - - -
Job ID {{this.getDisplayName(eiJob)}} Type ID {{this.getEITypeId(eiJob)}} Owner {{eiJob.owner}} Target URI {{this.getTargetUri(eiJob)}}
+ + +
\ No newline at end of file diff --git a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.scss b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.scss index 759f2a8..955ca31 100644 --- a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.scss +++ b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.scss @@ -39,11 +39,6 @@ background-color: #2d2d3d; } -.action-cell { - display: flex; - justify-content: flex-end; -} - .display-none { display: none; } @@ -62,4 +57,9 @@ .filter-form { width: 200px; -} \ No newline at end of file +} + +.mat-form-field { + font-size: 14px; + width: 100%; +} 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 3e0fbf5..f1518ce 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 @@ -23,8 +23,6 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; import { MatIconModule, MatTableModule } from '@angular/material'; -import { of } from 'rxjs'; - import { EICoordinatorComponent } from './ei-coordinator.component'; import { EIJobDataSource } from './ei-job.datasource'; import { EIProducerDataSource } from './ei-producer.datasource'; @@ -35,14 +33,12 @@ describe('EICoordinatorComponent', () => { let fixture: ComponentFixture; beforeEach(async(() => { - const jobDataSourceSpy = jasmine.createSpyObj('EIJobDataSource', [ 'connect', 'getJobs', 'disconnect' ]); - const producerDataSourceSpy = jasmine.createSpyObj('EIProducerDataSource', [ 'connect', 'loadTable', 'loadProducers', 'disconnect' ]); + const jobDataSourceSpy = jasmine.createSpyObj('EIJobDataSource', [ 'loadJobs', 'eiJobs' ]); + const producerDataSourceSpy = jasmine.createSpyObj('EIProducerDataSource', [ 'loadProducers', 'eiProducers' ]); + + jobDataSourceSpy.eiJobs.and.returnValue([]); - jobDataSourceSpy.connect.and.returnValue(of([])); - jobDataSourceSpy.disconnect(); - producerDataSourceSpy.connect.and.returnValue(of([])); - producerDataSourceSpy.loadProducers.and.returnValue(of([])); - producerDataSourceSpy.disconnect(); + producerDataSourceSpy.eiProducers.and.returnValue([]); TestBed.configureTestingModule({ imports: [ 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 2789114..fbd0be6 100644 --- a/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.ts +++ b/webapp-frontend/src/app/ei-coordinator/ei-coordinator.component.ts @@ -20,11 +20,10 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { MatSort } from '@angular/material/sort'; import { animate, state, style, transition, trigger } from '@angular/animations'; -import { FormBuilder, FormGroup } from '@angular/forms'; -import { MatTableDataSource } from '@angular/material'; +import { FormBuilder, FormGroup, AbstractControl } from '@angular/forms'; +import { MatTableDataSource, MatTable } from '@angular/material'; -import { defer, BehaviorSubject, Observable } from 'rxjs'; -import { map, withLatestFrom, startWith } from 'rxjs/operators'; +import { BehaviorSubject, Observable } from 'rxjs'; import { EIJob, EIProducer } from '../interfaces/ei.types'; import { EIJobDataSource } from './ei-job.datasource'; @@ -52,15 +51,18 @@ class EIJobInfo { }) export class EICoordinatorComponent implements OnInit { - producers$: Observable; - filteredProducers$: Observable; @ViewChild(MatSort, { static: true }) sort: MatSort; + @ViewChild('producersTable', { static: true }) table: MatTable; eiJobInfo = new Map(); darkMode: boolean; searchString: string; formGroup: FormGroup; - eiProducersData: MatTableDataSource; + jobsDataSource: MatTableDataSource; + producersDataSource: MatTableDataSource; + + readonly jobsFormControl: AbstractControl; + readonly producersFormControl: AbstractControl; constructor( private eiJobsDataSource: EIJobDataSource, @@ -68,26 +70,57 @@ export class EICoordinatorComponent implements OnInit { private ui: UiService, private formBuilder: FormBuilder) { this.formGroup = formBuilder.group({ filter: [""] }); - } + + this.jobsFormControl = formBuilder.group({ + id: '', + typeId: '', + owner: '', + targetUri:'' + }); + this.producersFormControl = formBuilder.group({ + ei_producer_id: '', + ei_producer_types: '', + status: '' + }); + } ngOnInit() { - this.eiJobsDataSource.getJobs(); - - this.producers$= this.eiProducersDataSource.loadProducers(); - this.filteredProducers$ = defer(() => this.formGroup.get("filter") - .valueChanges.pipe( - startWith(""), - withLatestFrom(this.producers$), - map(([val, producers]) => - !val ? producers : producers.filter((x) => - x.ei_producer_id.toLowerCase().includes(val)))) - ); + this.eiJobsDataSource.loadJobs(); + this.eiProducersDataSource.loadProducers(); + this.jobsDataSource = new MatTableDataSource(this.eiJobsDataSource.eiJobs()); + this.producersDataSource = new MatTableDataSource(this.eiProducersDataSource.eiProducers()); + + this.jobsFormControl.valueChanges.subscribe(value => { + const filter = {...value, id: value.id.trim().toLowerCase()} as string; + this.jobsDataSource.filter = filter; + }); + this.producersFormControl.valueChanges.subscribe(value => { + const filter = {...value, ei_producer_id: value.ei_producer_id.trim().toLowerCase()} as string; + this.producersDataSource.filter = filter; + }); + + this.jobsDataSource.filterPredicate = ((data, filter) => { + return this.isDataIncluding(data.ei_job_identity, filter.id) + && this.isDataIncluding(data.target_uri, filter.target_uri) + && this.isDataIncluding(data.owner, filter.owner) + && this.isDataIncluding(data.ei_type_identity, filter.typeId); + }) as (EIJob, string) => boolean; + + this.producersDataSource.filterPredicate = ((data, filter) => { + return this.isDataIncluding(data.ei_producer_id, filter.ei_producer_id) + && this.isDataIncluding(data.ei_producer_types.join(','), filter.ei_producer_types) + && this.isDataIncluding(data.status, filter.status); + }) as (EIProducer, string) => boolean; this.ui.darkModeState.subscribe((isDark) => { this.darkMode = isDark; }); } + isDataIncluding(data: string, filter: string) : boolean { + return !filter || data.toLowerCase().includes(filter); + } + getEIJobInfo(eiJob: EIJob): EIJobInfo { let info: EIJobInfo = this.eiJobInfo.get(eiJob.ei_job_data); if (!info) { @@ -148,7 +181,7 @@ export class EICoordinatorComponent implements OnInit { } refreshTables() { - this.eiJobsDataSource.getJobs(); + this.eiJobsDataSource.loadJobs(); this.eiProducersDataSource.loadProducers(); } } 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 index e52ae6f..a891d5f 100644 --- a/webapp-frontend/src/app/ei-coordinator/ei-job.datasource.spec.ts +++ b/webapp-frontend/src/app/ei-coordinator/ei-job.datasource.spec.ts @@ -18,7 +18,7 @@ * ========================LICENSE_END=================================== */ import { TestBed } from '@angular/core/testing'; -import { BehaviorSubject, of } from 'rxjs'; +import { of } from 'rxjs'; import { EIJobDataSource } from './ei-job.datasource'; import { EIService } from '../services/ei/ei.service'; @@ -50,10 +50,9 @@ describe('EIJobDataSource', () => { }); it('#getJobs', () => { - dataSource.getJobs(); - const jobsSubject: BehaviorSubject = dataSource.eiJobsSubject; - const value = jobsSubject.getValue(); - expect(value).toEqual([ job, job ]); + 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 index 64c948c..27a70c4 100644 --- a/webapp-frontend/src/app/ei-coordinator/ei-job.datasource.ts +++ b/webapp-frontend/src/app/ei-coordinator/ei-job.datasource.ts @@ -19,7 +19,6 @@ */ import { Injectable } from '@angular/core'; -import { MatTableDataSource } from '@angular/material'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; @@ -30,9 +29,13 @@ import { EIService } from '../services/ei/ei.service'; providedIn: 'root' }) -export class EIJobDataSource extends MatTableDataSource { +export class EIJobDataSource { - eiJobsSubject = new BehaviorSubject([]); + private jobs: Array = []; + + public eiJobs(): EIJob[] { + return this.jobs; + } private loadingSubject = new BehaviorSubject(false); @@ -42,39 +45,24 @@ export class EIJobDataSource extends MatTableDataSource { constructor( private eiSvc: EIService) { - super(); } - getJobs() { + loadJobs() { this.loadingSubject.next(true); + this.jobs = []; this.eiSvc.getProducerIds() .subscribe((producerIds: string[]) => { producerIds.forEach(id => { this.getJobsForProducer(id); }); }); + this.rowCount = this.jobs.length; } private getJobsForProducer(id: string) { console.log('Getting jobs for producer ID: ', id); - this.eiSvc.getJobsForProducer(id).subscribe(jobs => { - this.addJobsToSubject(jobs); - this.rowCount = this.eiJobsSubject.getValue().length; + this.eiSvc.getJobsForProducer(id).subscribe(producerJobs => { + this.jobs = this.jobs.concat(producerJobs); }); } - - private addJobsToSubject(jobs: EIJob[]) { - const currentValue = this.eiJobsSubject.value; - const updatedValue = [...currentValue, ...jobs]; - this.eiJobsSubject.next(updatedValue); - } - - connect(): BehaviorSubject { - return this.eiJobsSubject; - } - - disconnect(): void { - this.eiJobsSubject.complete(); - this.loadingSubject.complete(); - } } 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 index d5ab614..b3b2f4f 100644 --- a/webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.spec.ts +++ b/webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.spec.ts @@ -18,7 +18,7 @@ * ========================LICENSE_END=================================== */ import { TestBed } from '@angular/core/testing'; -import { BehaviorSubject, of } from 'rxjs'; +import { of } from 'rxjs'; import { EIService } from '../services/ei/ei.service'; import { ToastrModule } from 'ngx-toastr'; @@ -74,9 +74,8 @@ describe('EIProducerDataSource', () => { it('#loadProducers', () => { dataSource.loadProducers(); - const jobsSubject: BehaviorSubject = dataSource.producerSubject; - const value = jobsSubject.getValue(); - expect(value).toEqual([ expectedProducer1, expectedProducer2 ]); + 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 index 78ddd4e..8dac859 100644 --- a/webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.ts +++ b/webapp-frontend/src/app/ei-coordinator/ei-producer.datasource.ts @@ -19,11 +19,8 @@ */ import { Injectable } from '@angular/core'; -import { MatTableDataSource } from '@angular/material'; -import { Observable } from 'rxjs/Observable'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; -import { of } from 'rxjs/observable/of'; import { EIProducer } from '../interfaces/ei.types'; import { EIService } from '../services/ei/ei.service'; @@ -32,9 +29,13 @@ import { EIService } from '../services/ei/ei.service'; providedIn: 'root' }) -export class EIProducerDataSource extends MatTableDataSource { +export class EIProducerDataSource { - producerSubject = new BehaviorSubject([]); + private producers: Array = []; + + public eiProducers(): EIProducer[] { + return this.producers; + } private loadingSubject = new BehaviorSubject(false); @@ -44,12 +45,11 @@ export class EIProducerDataSource extends MatTableDataSource { constructor( private eiSvc: EIService) { - super(); } - loadProducers(): Observable { + loadProducers() { this.loadingSubject.next(true); - let producers: Array = []; + this.producers = []; this.eiSvc.getProducerIds() .subscribe((prodIds: string[]) => { console.log("ProducerIds: " + prodIds); @@ -62,26 +62,9 @@ export class EIProducerDataSource extends MatTableDataSource { this.eiSvc.getProducerStatus(id).subscribe(prodStatus => { eiProducer.status = prodStatus.opState.toString(); }); - this.addProducerToSubject(eiProducer); - producers.push(eiProducer); + this.producers.push(eiProducer); }); - this.rowCount = this.producerSubject.value.length; + this.rowCount = this.producers.length; }); - return of(producers); - } - - private addProducerToSubject(producer: EIProducer) { - const currentValue = this.producerSubject.value; - const updatedValue = [...currentValue, producer]; - this.producerSubject.next(updatedValue); - } - - connect(): BehaviorSubject { - return this.producerSubject; - } - - disconnect(): void { - this.producerSubject.complete(); - this.loadingSubject.complete(); } -} +} \ No newline at end of file diff --git a/webapp-frontend/src/app/mock/ei-jobs-producer1.json b/webapp-frontend/src/app/mock/ei-jobs-producer1.json index 488e194..1f79777 100644 --- a/webapp-frontend/src/app/mock/ei-jobs-producer1.json +++ b/webapp-frontend/src/app/mock/ei-jobs-producer1.json @@ -13,7 +13,18 @@ { "ei_job_identity": "job2", "ei_type_identity": "type1", - "owner": "owner1", + "owner": "owner2", + "ei_job_data": { + "jobparam2": "value2_job2", + "jobparam3": "value3_job2", + "jobparam1": "value1_job2" + }, + "target_uri": "https://ricsim_g3_1:8185/datadelivery" + }, + { + "ei_job_identity": "job4", + "ei_type_identity": "type1", + "owner": "owner3", "ei_job_data": { "jobparam2": "value2_job2", "jobparam3": "value3_job2", diff --git a/webapp-frontend/src/app/mock/ei-jobs-producer2.json b/webapp-frontend/src/app/mock/ei-jobs-producer2.json index 07220a9..fd6d2c8 100644 --- a/webapp-frontend/src/app/mock/ei-jobs-producer2.json +++ b/webapp-frontend/src/app/mock/ei-jobs-producer2.json @@ -9,5 +9,16 @@ "jobparam1": "value1_job3" }, "target_uri": "https://ricsim_g3_1:8185/datadelivery" + }, + { + "ei_job_identity": "job5", + "ei_type_identity": "type2", + "owner": "owner5", + "ei_job_data": { + "jobparam2": "value2_job2", + "jobparam3": "value3_job2", + "jobparam1": "value1_job2" + }, + "target_uri": "https://ricsim_g3_1:8185/datadelivery" } ] \ No newline at end of file diff --git a/webapp-frontend/src/app/services/ui/ui.service.ts b/webapp-frontend/src/app/services/ui/ui.service.ts index c475f1d..eea2ce3 100644 --- a/webapp-frontend/src/app/services/ui/ui.service.ts +++ b/webapp-frontend/src/app/services/ui/ui.service.ts @@ -31,4 +31,8 @@ export class UiService { this.darkModeState = new BehaviorSubject(true); this.expanded = new Observable(); } + + getDarkMode(): boolean { + return this.darkModeState.getValue(); + } }