diff options
author | 2018-06-03 13:12:12 +0300 | |
---|---|---|
committer | 2018-06-03 11:56:49 +0000 | |
commit | 548c5a220333c7cd666b861e737bff0b45461f18 (patch) | |
tree | 13c60b67291bd8bada498ad73c02a9e35afb5c9e /public/src | |
parent | 193095b01daf094c78f7fafacdf1c1cc31f290fe (diff) |
Update FE project
Update FE to latest version so that fe can run on docker
Change-Id: I9c5dee756b567dbe64fac6d3d6fd89362813bdcc
Issue-ID: SDC-1359
Signed-off-by: Stone, Avi (as206k) <as206k@att.com>
Diffstat (limited to 'public/src')
66 files changed, 2117 insertions, 810 deletions
diff --git a/public/src/app/api/rest-api.service.spec.ts b/public/src/app/api/rest-api.service.spec.ts index ce921cb..c0fea4b 100644 --- a/public/src/app/api/rest-api.service.spec.ts +++ b/public/src/app/api/rest-api.service.spec.ts @@ -1,23 +1,479 @@ -import { TestBed, inject } from '@angular/core/testing'; -import { HttpModule } from '@angular/http'; -import { RestApiService } from './rest-api.service'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { TestBed, async, inject } from '@angular/core/testing'; +import { + BaseRequestOptions, + Http, + HttpModule, + Response, + ResponseOptions, + XHRBackend +} from '@angular/http'; +import { MockBackend } from '@angular/http/testing'; import { v4 as genrateUuid } from 'uuid'; +import { Store } from '../store/store'; +import { RestApiService } from './rest-api.service'; describe('RestApiService', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpModule], - providers: [RestApiService] - }); - }); + let service: RestApiService; + let backend: MockBackend; + + beforeEach( + async(() => { + TestBed.configureTestingModule({ + imports: [HttpModule, HttpClientTestingModule], + providers: [ + RestApiService, + Store, + MockBackend, + BaseRequestOptions, + { + provide: Http, + deps: [MockBackend, BaseRequestOptions], + useFactory: ( + backend: XHRBackend, + defaultOptions: BaseRequestOptions + ) => { + return new Http(backend, defaultOptions); + } + } + ] + }); + // Get the MockBackend + backend = TestBed.get(MockBackend); + service = TestBed.get(RestApiService); + }) + ); it( 'should be created', - inject([RestApiService], (service: RestApiService) => { + inject([RestApiService], () => { expect(service).toBeTruthy(); }) ); + it('should baseUrl match localhost', () => { + expect(service.baseUrl).toBe('http://localhost:8446'); + }); + + it('should headers user id get default', () => { + service.addHeaders(); + expect(service.headers.get('USER_ID')).toBe('ym903w'); + }); + + it('should headers Content-Type json', () => { + service.addHeaders(); + expect(service.headers.get('Content-Type')).toBe('application/json'); + }); + + it( + 'should get service instance from API', + async(() => { + const serviceInstances = [ + { + name: 'ciService669277f472b0', + category: 'Mobility' + } + ]; + + backend.connections.subscribe(connection => { + connection.mockRespond( + new Response( + new ResponseOptions({ + body: JSON.stringify(serviceInstances) + }) + ) + ); + }); + + service.getServiceInstances('123456').subscribe(_res => { + expect(_res.length).toBe(1); + expect(_res).toEqual(serviceInstances); + }); + }) + ); + + it( + 'should get template resources from API', + async(() => { + const template = [ + { + name: 'AviStone1234', + version: '0.1' + } + ]; + + backend.connections.subscribe(connection => { + connection.mockRespond( + new Response( + new ResponseOptions({ + body: JSON.stringify(template) + }) + ) + ); + }); + + service.getTemplateResources().subscribe(_res => { + expect(_res.length).toBe(1); + expect(_res).toEqual(template); + }); + }) + ); + + it( + 'should getCompositionMonitoringComponent from API', + async(() => { + const template = [ + { + name: 'AviStone1234', + version: '0.1' + } + ]; + + backend.connections.subscribe(connection => { + connection.mockRespond( + new Response( + new ResponseOptions({ + body: JSON.stringify(template) + }) + ) + ); + }); + + service.getCompositionMonitoringComponent('123456').subscribe(_res => { + expect(_res.length).toBe(1); + expect(_res).toEqual(template); + }); + }) + ); + + it( + 'importVFCMT from API', + async(() => { + const template = [ + { + name: 'AviStone1234', + version: '0.1' + } + ]; + + backend.connections.subscribe(connection => { + connection.mockRespond( + new Response( + new ResponseOptions({ + body: JSON.stringify(template) + }) + ) + ); + }); + + service.importVFCMT({}).subscribe(_res => { + expect(_res.length).toBe(1); + expect(_res).toEqual(template); + }); + }) + ); + + it( + 'deleteMonitoringComponent from API', + async(() => { + const template = [ + { + name: 'AviStone1234', + version: '0.1' + } + ]; + + backend.connections.subscribe(connection => { + connection.mockRespond( + new Response( + new ResponseOptions({ + body: JSON.stringify(template) + }) + ) + ); + }); + + service + .deleteMonitoringComponent( + { + contextType: 'service', + uuid: '123456' + }, + '45678', + 'liav' + ) + .subscribe(_res => { + console.log('delete', _res); + }); + }) + ); + + it( + 'deleteMonitoringComponentWithBlueprint from API', + async(() => { + const template = [ + { + name: 'AviStone1234', + version: '0.1' + } + ]; + + backend.connections.subscribe(connection => { + connection.mockRespond( + new Response( + new ResponseOptions({ + body: JSON.stringify(template) + }) + ) + ); + }); + + service + .deleteMonitoringComponentWithBlueprint( + { + contextType: 'service', + uuid: '123456' + }, + 'voskComp', + '45678', + 'liav' + ) + .subscribe(_res => { + console.log('delete', _res); + }); + }) + ); + + it( + 'createNewVFCMT from API', + async(() => { + const template = [ + { + name: 'AviStone1234', + version: '0.1' + } + ]; + + backend.connections.subscribe(connection => { + connection.mockRespond( + new Response( + new ResponseOptions({ + body: JSON.stringify(template) + }) + ) + ); + }); + + service.createNewVFCMT({}).subscribe(_res => { + expect(_res.length).toBe(1); + expect(_res).toEqual(template); + }); + }) + ); + + it( + 'saveMonitoringComponent from API', + async(() => { + const template = [ + { + name: 'AviStone1234', + version: '0.1' + } + ]; + + backend.connections.subscribe(connection => { + connection.mockRespond( + new Response( + new ResponseOptions({ + body: JSON.stringify(template) + }) + ) + ); + }); + + service + .saveMonitoringComponent({ + contextType: 'service', + serviceUuid: '123456', + vfiName: 'liavVfi', + vfcmtUuid: '987456', + cdump: {} + }) + .subscribe(_res => { + expect(_res.length).toBe(1); + expect(_res).toEqual(template); + }); + }) + ); + + it( + 'submitMonitoringComponent from API', + async(() => { + const template = [ + { + name: 'AviStone1234', + version: '0.1' + } + ]; + + backend.connections.subscribe(connection => { + connection.mockRespond( + new Response( + new ResponseOptions({ + body: JSON.stringify(template) + }) + ) + ); + }); + + service + .submitMonitoringComponent({ + contextType: 'service', + serviceUuid: '123456', + vfiName: 'liavVfi', + vfcmtUuid: '987456', + cdump: {}, + flowType: 'SNMP' + }) + .subscribe(_res => { + expect(_res.length).toBe(1); + expect(_res).toEqual(template); + }); + }) + ); + + it( + 'should get Vfcmt Reference Data from API', + async(() => { + const template = [ + { + name: 'AviStone1234', + version: '0.1' + } + ]; + + backend.connections.subscribe(connection => { + connection.mockRespond( + new Response( + new ResponseOptions({ + body: JSON.stringify(template) + }) + ) + ); + }); + + service.getVfcmtReferenceData('123456').subscribe(_res => { + expect(_res.length).toBe(1); + expect(_res).toEqual(template); + }); + }) + ); + + it( + 'should get vfcmt list from API', + async(() => { + const dummyVfcmts = [ + { + uuid: 'cba37ed8-94e1-406f-b4f5-b5edbc31ac85', + name: 'CIe4d5a9b271d6' + }, + { + uuid: '64471437-8feb-40d9-a8b0-9407a81dd5c0', + name: 'teSt.__.monitoring---TempLATE.6hnc' + } + ]; + + backend.connections.subscribe(connection => { + expect(connection.request.url).toMatch( + 'http://localhost:8446/service/123456/0.1/monitoringComponents' + ); + connection.mockRespond( + new Response( + new ResponseOptions({ + body: JSON.stringify(dummyVfcmts) + }) + ) + ); + }); + + service + .getMonitoringComponents({ + contextType: 'service', + uuid: '123456', + version: '0.1' + }) + .subscribe(_res => { + expect(_res.length).toBe(2); + expect(_res).toEqual(dummyVfcmts); + }); + }) + ); + + it( + 'should get migration vfcmt list from API', + async(() => { + const dummyVfcmts = [ + { + uuid: 'cba37ed8-94e1-406f-b4f5-b5edbc31ac85', + name: 'CIe4d5a9b271d6' + }, + { + uuid: '64471437-8feb-40d9-a8b0-9407a81dd5c0', + name: 'teSt.__.monitoring---TempLATE.6hnc' + } + ]; + + backend.connections.subscribe(connection => { + expect(connection.request.url).toMatch( + 'http://localhost:8446/service/123456/0.1/getVfcmtsForMigration' + ); + connection.mockRespond( + new Response( + new ResponseOptions({ + body: JSON.stringify(dummyVfcmts) + }) + ) + ); + }); + + service + .getVfcmtsForMigration({ + contextType: 'service', + uuid: '123456', + version: '0.1' + }) + .subscribe(_res => { + expect(_res.length).toBe(2); + expect(_res).toEqual(dummyVfcmts); + }); + }) + ); + + it( + 'should get flow type from API', + async(() => { + const flowType = ['syslog', 'SNMP']; + + backend.connections.subscribe(connection => { + expect(connection.request.url).toMatch( + 'http://localhost:8446/conf/composition' + ); + connection.mockRespond( + new Response( + new ResponseOptions({ + body: JSON.stringify(flowType) + }) + ) + ); + }); + + service.getFlowType().subscribe(_res => { + expect(_res.length).toBe(2); + expect(_res).toEqual(flowType); + }); + }) + ); + it('should genrate deffrent uuid each time for request id', () => { const firstUuid = genrateUuid(); const secondUuid = genrateUuid(); diff --git a/public/src/app/api/rest-api.service.ts b/public/src/app/api/rest-api.service.ts index ba5cc54..cd55a6d 100644 --- a/public/src/app/api/rest-api.service.ts +++ b/public/src/app/api/rest-api.service.ts @@ -1,18 +1,13 @@ import { Injectable } from '@angular/core'; -import { - Http, - Response, - Headers, - RequestOptions, - URLSearchParams -} from '@angular/http'; +import { Headers, Http, RequestOptions, Response } from '@angular/http'; import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/observable/throw'; +import 'rxjs/add/operator/catch'; // Import RxJs required methods import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/catch'; -import 'rxjs/add/observable/throw'; -import { environment } from '../../environments/environment'; import { v4 as uuidGenarator } from 'uuid'; +import { environment } from '../../environments/environment'; +import { Store } from '../store/store'; @Injectable() export class RestApiService { @@ -20,16 +15,24 @@ export class RestApiService { headers: Headers; baseUrl: string; - constructor(private http: Http) { + constructor(private http: Http, public store: Store) { this.baseUrl = `${environment.apiBaseUrl}`; + } + + addHeaders() { + const userID = + this.store.sdcParmas === undefined + ? 'ym903w' + : this.store.sdcParmas.userId; this.headers = new Headers({ 'Content-Type': 'application/json', - USER_ID: 'ym903w' + USER_ID: userID }); this.options = new RequestOptions({ headers: this.headers }); } getVfcmtsForMigration(params) { + this.addHeaders(); const { contextType, uuid, version } = params; const url = `${ this.baseUrl @@ -44,6 +47,7 @@ export class RestApiService { } getVfcmtReferenceData(vfcmtUUID) { + this.addHeaders(); const url = `${this.baseUrl}/getVfcmtReferenceData/${vfcmtUUID}`; this.options.headers.set('X-ECOMP-RequestID', uuidGenarator()); return this.http @@ -53,6 +57,7 @@ export class RestApiService { } getFlowType() { + this.addHeaders(); const url = `${this.baseUrl}/conf/composition`; this.options.headers.set('X-ECOMP-RequestID', uuidGenarator()); return this.http @@ -62,6 +67,7 @@ export class RestApiService { } createNewVFCMT(params) { + this.addHeaders(); const url = `${this.baseUrl}/createMC`; this.options.headers.set('X-ECOMP-RequestID', uuidGenarator()); return this.http @@ -73,6 +79,7 @@ export class RestApiService { } importVFCMT(params) { + this.addHeaders(); const url = `${this.baseUrl}/importMC`; this.options.headers.set('X-ECOMP-RequestID', uuidGenarator()); return this.http @@ -84,6 +91,7 @@ export class RestApiService { } getServiceInstances(serviceID) { + this.addHeaders(); const url = `${this.baseUrl}/service/${serviceID}`; this.options.headers.set('X-ECOMP-RequestID', uuidGenarator()); return this.http @@ -95,6 +103,7 @@ export class RestApiService { } getTemplateResources() { + this.addHeaders(); const url = `${this.baseUrl}/getResourcesByMonitoringTemplateCategory`; this.options.headers.set('X-ECOMP-RequestID', uuidGenarator()); return this.http @@ -104,6 +113,7 @@ export class RestApiService { } getMonitoringComponents(params) { + this.addHeaders(); const { contextType, uuid, version } = params; const url = `${ this.baseUrl @@ -116,6 +126,7 @@ export class RestApiService { } deleteMonitoringComponent(params, vfcmtUuid, vfiName) { + this.addHeaders(); const { contextType, uuid } = params; const url = `${ this.baseUrl @@ -123,7 +134,7 @@ export class RestApiService { this.options.headers.set('X-ECOMP-RequestID', uuidGenarator()); return this.http .delete(url, this.options) - .map((res: Response) => res.json()) + .map((res: Response) => res) .catch((error: any) => Observable.throw(error.json() || 'Server error')); } @@ -133,6 +144,7 @@ export class RestApiService { vfcmtUuid, vfiName ) { + this.addHeaders(); const { contextType, uuid } = params; const url = `${ this.baseUrl @@ -140,11 +152,12 @@ export class RestApiService { this.options.headers.set('X-ECOMP-RequestID', uuidGenarator()); return this.http .delete(url, this.options) - .map((res: Response) => res.json()) + .map((res: Response) => res) .catch((error: any) => Observable.throw(error.json() || 'Server error')); } getCompositionMonitoringComponent(vfcmtUuid) { + this.addHeaders(); const url = `${this.baseUrl}/getMC/${vfcmtUuid}`; this.options.headers.set('X-ECOMP-RequestID', uuidGenarator()); return this.http @@ -154,18 +167,20 @@ export class RestApiService { } saveMonitoringComponent(params) { + this.addHeaders(); const { contextType, serviceUuid, vfiName, vfcmtUuid, cdump } = params; const url = `${ this.baseUrl }/${contextType}/${serviceUuid}/${vfiName}/saveComposition/${vfcmtUuid}`; this.options.headers.set('X-ECOMP-RequestID', uuidGenarator()); return this.http - .post(url, cdump, this.options) + .post(url, JSON.stringify(cdump), this.options) .map((res: Response) => res.json()) .catch((error: any) => Observable.throw(error.json() || 'Server error')); } submitMonitoringComponent(params) { + this.addHeaders(); const { contextType, serviceUuid, vfiName, vfcmtUuid, flowType } = params; const url = `${ this.baseUrl diff --git a/public/src/app/app.component.html b/public/src/app/app.component.html index adb06f1..29762b6 100644 --- a/public/src/app/app.component.html +++ b/public/src/app/app.component.html @@ -1,6 +1,7 @@ <!-- <div class="container"> --> <main [@slideAnimation]="getRouterOutletState(o)"> <app-error-dialog></app-error-dialog> + <app-sdc-notify-dialog></app-sdc-notify-dialog> <app-loader [hidden]="!this.store.loader"></app-loader> <router-outlet #o="outlet"></router-outlet> </main> diff --git a/public/src/app/app.module.ts b/public/src/app/app.module.ts index 8ed8c87..ba5d035 100644 --- a/public/src/app/app.module.ts +++ b/public/src/app/app.module.ts @@ -13,8 +13,9 @@ import { MatIconModule } from '@angular/material/icon'; import { MatDialogModule } from '@angular/material/dialog'; import { ToastrModule } from 'ngx-toastr'; import { NgSelectModule } from '@ng-select/ng-select'; +import { NgxDatatableModule } from '@swimlane/ngx-datatable'; -// import { SdcUiComponentsModule } from 'sdc-ui/lib/angular'; +// import {SdcUiComponentsModule} from 'sdc-ui/lib/angular'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; @@ -44,6 +45,7 @@ import { SlidePanelComponent } from './rule-engine/slide-panel/slide-panel.compo import { RuleListComponent } from './rule-engine/rule-list/rule-list.component'; import { BarIconsComponent } from './bar-icons/bar-icons.component'; import { DiagramComponent } from './diagram/diagram.component'; +import { SdcNotifyDialogComponent } from './sdc-notify-dialog/sdc-notify-dialog.component'; const appInitializerFn = () => { return () => { @@ -71,7 +73,8 @@ const appInitializerFn = () => { SlidePanelComponent, RuleListComponent, BarIconsComponent, - DiagramComponent + DiagramComponent, + SdcNotifyDialogComponent ], imports: [ BrowserModule, @@ -89,7 +92,8 @@ const appInitializerFn = () => { TreeModule, NgSelectModule, TooltipModule, - ToastrModule.forRoot({ enableHtml: true }) + ToastrModule.forRoot({ enableHtml: true }), + NgxDatatableModule ], entryComponents: [ConfirmPopupComponent], providers: [ diff --git a/public/src/app/bar-icons/bar-icons.component.html b/public/src/app/bar-icons/bar-icons.component.html index 03129bf..2b5269d 100644 --- a/public/src/app/bar-icons/bar-icons.component.html +++ b/public/src/app/bar-icons/bar-icons.component.html @@ -1,40 +1,44 @@ -<div style="display: flex; position: relative; justify-content: flex-end;"> - <div style="display: flex; justify-content: flex-end;" [class]="genrateBarTestId()"> +<div style="display: flex; position: relative; justify-content: flex-end;" class="bars"> + <div style="display: flex; justify-content: flex-end; align-items:center;" [class]="genrateBarTestId()"> <button mat-icon-button> <span style="width: 100%; + color:#5a5a5a; height: 100%; display: flex; justify-content: center; - align-items: center;" [innerHTML]="'help-circle' | feather:18"></span> + align-items: center;" [innerHTML]="'help-circle' | feather:20"></span> </button> <hr> - <div *ngIf="tabName.includes('map')" style="display: flex;"> + <div *ngIf="tabName.includes('map')" style="display: flex; align-items: center;"> <button mat-icon-button> <span style="width: 100%; + color:#5a5a5a; height: 100%; display: flex; justify-content: center; - align-items: center;" [innerHTML]="'upload' | feather:18"></span> + align-items: center;" [innerHTML]="'upload' | feather:20"></span> </button> <hr> <button mat-icon-button> <span style="width: 100%; + color:#5a5a5a; height: 100%; display: flex; justify-content: center; - align-items: center;" [innerHTML]="'download' | feather:18"></span> + align-items: center;" [innerHTML]="'download' | feather:20"></span> </button> <hr> </div> <button mat-icon-button (click)="enableSetting()" data-tests-id="setting-gear" [style.color]="this.store.expandAdvancedSetting[store.tabIndex] ? '#009FDB' : 'black'"> <span style="width: 100%; + color:#5a5a5a; height: 100%; display: flex; justify-content: center; - align-items: center;" [innerHTML]="'settings' | feather:18"></span> + align-items: center;" [innerHTML]="'settings' | feather:20"></span> </button> </div> @@ -44,14 +48,32 @@ <div style="font-size: 1.5em; padding: 0 12px;">{{tabName}} Advanced Setting</div> <form #cdumpConfForm="ngForm"> <div *ngFor="let prop of store.configurationForm" class="field" [id]="prop.name"> - <p class="field-label">{{prop.name}}</p> - <input *ngIf="!isPropertyDdl(prop)" type="text" name="{{prop.name}}" class="field-text" [(ngModel)]="prop.assignment.value" + <div style="display: flex;"> + <p class="field-label"> + {{prop.name}} + </p> + <span *ngIf="prop.description" class="help-description" style="padding-left: 5px;" [innerHTML]="'help-circle' | feather:14" + pTooltip="{{prop.description}}" tooltipPosition="top"></span> + </div> + + <input *ngIf="isPropertyDdl(prop) === dropDownTypes.none" type="text" name="{{prop.name}}" class="field-text" [(ngModel)]="prop.value" + (ngModelChange)="onChange($event)"> + + <select *ngIf="isPropertyDdl(prop) === dropDownTypes.regularDDL" class="field-text" name="{{prop.name}}" [(ngModel)]="prop.value" (ngModelChange)="onChange($event)"> - <select *ngIf="isPropertyDdl(prop)" class="field-text" name="{{prop.name}}" [(ngModel)]="prop.assignment.value" (ngModelChange)="onChange($event)"> - <option *ngFor="let value of prop.constraints[0].valid_values" [value]="value"> - {{value}} - </option> - </select> + <option *ngFor="let value of prop.constraints[0].valid_values" [value]="value"> + {{value}} + </option> + </select> + <select *ngIf="isPropertyDdl(prop) === dropDownTypes.booleanDDL" class="field-text" name="{{prop.name}}" [(ngModel)]="prop.value" + (ngModelChange)="onChange($event)" data-tests-id="booleanDDL"> + <option value="false"> + false + </option> + <option value="true"> + true + </option> + </select> </div> </form> </div> diff --git a/public/src/app/bar-icons/bar-icons.component.scss b/public/src/app/bar-icons/bar-icons.component.scss index 893f757..006e650 100644 --- a/public/src/app/bar-icons/bar-icons.component.scss +++ b/public/src/app/bar-icons/bar-icons.component.scss @@ -1,3 +1,9 @@ +.bars { + hr { + height: 22px; + color: #d2d2d2; + } +} .setting { position: absolute; top: 47px; diff --git a/public/src/app/bar-icons/bar-icons.component.ts b/public/src/app/bar-icons/bar-icons.component.ts index adf4b88..bf930f3 100644 --- a/public/src/app/bar-icons/bar-icons.component.ts +++ b/public/src/app/bar-icons/bar-icons.component.ts @@ -1,7 +1,7 @@ import { Component, Input, ViewChild } from '@angular/core'; -import { Store } from '../store/store'; -import { includes } from 'lodash'; import { NgForm } from '@angular/forms'; +import { includes } from 'lodash'; +import { Store } from '../store/store'; @Component({ selector: 'app-bar-icons', @@ -12,6 +12,11 @@ export class BarIconsComponent { configuration; @Input() tabName: string; @ViewChild('cdumpConfForm') cdumpConfForm: NgForm; + dropDownTypes = { + none: 1, + regularDDL: 2, + booleanDDL: 3 + }; constructor(public store: Store) {} @@ -21,19 +26,19 @@ export class BarIconsComponent { isPropertyDdl(property) { if (property.hasOwnProperty('constraints')) { - if ( - includes( - property.constraints[0].valid_values, - property.assignment.value - ) + if (includes(property.constraints[0].valid_values, property.value)) { + return this.dropDownTypes.regularDDL; + } else if ( + property.hasOwnProperty('type') && + property.type === 'boolean' ) { - return true; - } else { - return false; + if (!(property.value === 'false')) { + property.value = true; + } + return this.dropDownTypes.booleanDDL; } - } else { - return false; } + return this.dropDownTypes.none; } genrateBarTestId() { diff --git a/public/src/app/diagram/diagram.component.html b/public/src/app/diagram/diagram.component.html index b3cb28a..c12860b 100644 --- a/public/src/app/diagram/diagram.component.html +++ b/public/src/app/diagram/diagram.component.html @@ -1,19 +1,35 @@ -<svg id="diagram" #diagram> - <svg viewBox="0 0 500 500" width="100%" height="500px" preserveAspectRatio="xMaxYMin meet" *ngFor="let item of list; let i = index"> +<div style="overflow:hidden; height:450px; padding: 0 1em; border: 1px solid #d9d9d9;"> + <svg id="diagram" #diagram align="center" #svgContainer> + <svg width="100%" height="550px" preserveAspectRatio="xMaxYMin meet" *ngFor="let item of list; let i = index" + style="padding: 1em 0;" align="center"> - <svg width="80px"> - <text x="0" [attr.y]="45 * (i+1)"> - {{item.source}} - </text> - </svg> + <svg [attr.width]="maxLengthLeft * 10"> + <text text-anchor="start" x="0" [attr.y]="40 * (i+1)" font-size="12" dy="0"> + <tspan x="0" dy=".6em" font-weight="bold"> + {{item.name1}} + </tspan> + <tspan x="0" dy="1.2em"> + {{item.p1}} + </tspan> + </text> + </svg> + + <circle stroke="#8BC34A" fill="#8BC34A" [attr.cx]="maxLengthLeft * 8" [attr.cy]="44 * (i+1)" r="5" /> + + <line [attr.x1]="maxLengthLeft * 8" [attr.y1]="44 * (i+1)" [attr.x2]="maxWidth - maxLengthRight * 8 - 30" [attr.y2]="44 * (i+1)" + stroke-width="2" stroke="black" stroke-dasharray="5, 5" stroke="#8BC34A" fill="#8BC34A" class="line" /> - <circle cx="100" [attr.cy]="44 * (i+1)" r="5" /> - <line x1="100" [attr.y1]="44 * (i+1)" [attr.x2]="maxWidth - 150" [attr.y2]="44 * (i+1)" stroke-width="2" stroke="black" stroke-dasharray="5, 5" - class="line" /> - <circle [attr.cx]="maxWidth - 150" [attr.cy]="44 * (i+1)" r="5" /> + <circle [attr.cx]="maxWidth - maxLengthRight * 8 - 30" [attr.cy]="44 * (i+1)" r="5" stroke="#8BC34A" fill="#8BC34A" /> - <text [attr.x]="maxWidth - 130" [attr.y]="45 * (i+1)"> - {{item.target}} - </text> + <text text-anchor="start" [attr.x]="maxWidth - maxLengthRight * 8" [attr.y]="40 * (i+1)" font-size="12" dy="0"> + <tspan [attr.x]="maxWidth - maxLengthRight * 8" dy=".6em" font-weight="bold"> + {{item.name2}} + </tspan> + <tspan [attr.x]="maxWidth - maxLengthRight * 8" dy="1.2em"> + {{item.p2}} + </tspan> + </text> + + </svg> </svg> -</svg> +</div> diff --git a/public/src/app/diagram/diagram.component.scss b/public/src/app/diagram/diagram.component.scss index 57437d8..1753ea2 100644 --- a/public/src/app/diagram/diagram.component.scss +++ b/public/src/app/diagram/diagram.component.scss @@ -1,11 +1,10 @@ -svg { - height: 400px; +#diagram { + height: 1000px; width: 100%; margin: auto; display: block; .line { - stroke-dasharray: 1400; - animation: draw 5s ease-in; + stroke-dasharray: 5; // animation: draw 1s ease-in; } } diff --git a/public/src/app/diagram/diagram.component.spec.ts b/public/src/app/diagram/diagram.component.spec.ts index 535f280..e3177cc 100644 --- a/public/src/app/diagram/diagram.component.spec.ts +++ b/public/src/app/diagram/diagram.component.spec.ts @@ -1,5 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { DiagramComponent } from './diagram.component'; describe('DiagramComponent', () => { @@ -23,4 +22,77 @@ describe('DiagramComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + it('should check on change check maxLengthLeft', () => { + component.list = [ + { + name1: 'node1dsvsdsvd', + name2: 'node2', + p1: 'Stream_publish_0', + p2: 'capability' + }, + { + name1: 'node33', + name2: 'node2555', + p1: 'requirement2', + p2: 'capability11' + }, + { + name1: 'namber4', + name2: 'namber3', + p1: 'requirement3', + p2: 'capability4' + } + ]; + component.ngOnChanges(); + expect(component.maxLengthLeft).toBe(16); + }); + it('should check on change check maxLengthRight', () => { + component.list = [ + { + name1: 'node1dsvsdsvd', + name2: 'node2', + p1: 'Stream_publish_0', + p2: 'capability' + }, + { + name1: 'node33', + name2: 'node2555', + p1: 'requirement2', + p2: 'capability11' + }, + { + name1: 'namber4', + name2: 'namber3', + p1: 'requirement3', + p2: 'capability4' + } + ]; + component.ngOnChanges(); + expect(component.maxLengthRight).toBe(12); + }); + it('should check on change check maxWidth', () => { + component.list = [ + { + name1: 'node1dsvsdsvd', + name2: 'node2', + p1: 'Stream_publish_0', + p2: 'capability' + }, + { + name1: 'node33', + name2: 'node2555', + p1: 'requirement2', + p2: 'capability11' + }, + { + name1: 'namber4', + name2: 'namber3', + p1: 'requirement3', + p2: 'capability4' + } + ]; + component.ngOnChanges(); + expect(component.maxWidth).toBe(550); + }); }); diff --git a/public/src/app/diagram/diagram.component.ts b/public/src/app/diagram/diagram.component.ts index a0ae3a1..394b0ee 100644 --- a/public/src/app/diagram/diagram.component.ts +++ b/public/src/app/diagram/diagram.component.ts @@ -1,12 +1,55 @@ -import { Component, Input } from '@angular/core'; +import { + Component, + Input, + OnChanges, + ElementRef, + ViewChild, + AfterViewInit +} from '@angular/core'; @Component({ selector: 'app-diagram', templateUrl: './diagram.component.html', styleUrls: ['./diagram.component.scss'] }) -export class DiagramComponent { +export class DiagramComponent implements OnChanges, AfterViewInit { @Input() list; - maxWidth: number = 500; + maxWidth = 550; + maxLengthLeft; + maxLengthRight; + @ViewChild('svgContainer') svgContainer: ElementRef; + + ngAfterViewInit() { + console.log( + 'svg width:', + this.svgContainer.nativeElement.getBoundingClientRect().width + ); + this.maxWidth = this.svgContainer.nativeElement.getBoundingClientRect().width; + } + constructor() {} + + ngOnChanges() { + if (this.list) { + const name1MaxLength = this.list.reduce( + (r, s) => (r > s.name1.length ? r : s.name1.length), + 0 + ); + const p1MaxLength = this.list.reduce( + (r, s) => (r > s.p1.length ? r : s.p1.length), + 0 + ); + this.maxLengthLeft = Math.max(name1MaxLength, p1MaxLength); + + const name2MaxLength = this.list.reduce( + (r, s) => (r > s.name2.length ? r : s.name2.length), + 0 + ); + const p2MaxLength = this.list.reduce( + (r, s) => (r > s.p2.length ? r : s.p2.length), + 0 + ); + this.maxLengthRight = Math.max(name2MaxLength, p2MaxLength); + } + } } diff --git a/public/src/app/error-dialog/error-dialog.component.html b/public/src/app/error-dialog/error-dialog.component.html index 7b72d06..ca9dd32 100644 --- a/public/src/app/error-dialog/error-dialog.component.html +++ b/public/src/app/error-dialog/error-dialog.component.html @@ -1,17 +1,35 @@ -<p-dialog [(visible)]="store.displayErrorDialog" modal="modal" width="500" [responsive]="true" data-tests-id="error-dialog"> +<p-dialog [(visible)]="store.displayErrorDialog" [closable]="false" modal="modal" width="500" [responsive]="true" data-tests-id="error-dialog" + styleClass="dcae-error"> <p-header> - <span style="font-size: 1.3em;"> - Error - </span> + <div style="display: flex;"> + <span style="color: #CF2A2A; + padding-right: 15px; + height: 100%; + display: flex; + justify-content: center; + align-items: center;" [innerHTML]="'x-circle' | feather:28"></span> + <span style="font-family: 'Open Sans', sans-serif; + font-size: 24px; width: 100%;"> + Error + </span> + <span style=" + height: 100%; + display: flex; + color:rgb(90, 90, 90); + justify-content: center; + align-items: center;" [innerHTML]="'x' | feather:20" (click)="closeDialog()" data-tests-id="error-cancel-icon"></span> + </div> </p-header> - <div *ngFor="let error of store.ErrorContent"> + <div *ngFor="let error of store.ErrorContent" style="padding: 0 0 20px 43px; font-family: 'Open Sans', sans-serif; + font-size: 14px;"> {{ error.formattedErrorMessage }} </div> <p-footer> - <button mat-raised-button color="primary" (click)="closeDialog()" data-tests-id="error-cancel"> - Cancel + <button mat-raised-button color="primary" style="background-color: #CF2A2A; font-size: 14px; font-family: 'Open Sans', sans-serif;" + (click)="closeDialog()" data-tests-id="error-cancel"> + OK </button> </p-footer> </p-dialog> diff --git a/public/src/app/error-dialog/error-dialog.component.scss b/public/src/app/error-dialog/error-dialog.component.scss index e69de29..d0c0ae1 100644 --- a/public/src/app/error-dialog/error-dialog.component.scss +++ b/public/src/app/error-dialog/error-dialog.component.scss @@ -0,0 +1,18 @@ +:host /deep/ .dcae-error { + border-top: solid 6px #cf2a2a; +} + +:host /deep/ .ui-dialog .ui-dialog-titlebar { + padding-top: 15px; + padding-left: 20px; + padding-right: 12px; + padding-bottom: 0; +} + +:host /deep/ .ui-dialog-footer { + padding: 10px; +} + +:host /deep/ .ui-dialog.ui-widget .ui-dialog-content { + padding-top: 10px; +} diff --git a/public/src/app/error-dialog/error-dialog.component.ts b/public/src/app/error-dialog/error-dialog.component.ts index 3e7bfe0..aa4b693 100644 --- a/public/src/app/error-dialog/error-dialog.component.ts +++ b/public/src/app/error-dialog/error-dialog.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; import { Store } from '../store/store'; @Component({ @@ -6,11 +6,9 @@ import { Store } from '../store/store'; templateUrl: './error-dialog.component.html', styleUrls: ['./error-dialog.component.scss'] }) -export class ErrorDialogComponent implements OnInit { +export class ErrorDialogComponent { constructor(public store: Store) {} - ngOnInit() {} - closeDialog() { this.store.displayErrorDialog = false; } diff --git a/public/src/app/general/general.component.html b/public/src/app/general/general.component.html index dcea57a..2d6f232 100644 --- a/public/src/app/general/general.component.html +++ b/public/src/app/general/general.component.html @@ -66,18 +66,18 @@ </div> <select name="serviceAttached" [disabled]="this.store.isEditMode || disableVnfiList" required [(ngModel)]="newVfcmt.vfni" data-tests-id="vfniDdl" (ngModelChange)="onChangeVfni($event)" class="field-text" [style.background]="this.store.isEditMode || disableVnfiList ? '#ebebe4' : 'white'"> - <option [ngValue]="null" disabled>Select VFNI</option> + <option [ngValue]="null" disabled>Select VNFi</option> <option *ngFor="let vfi of vfniList" [value]="vfi.resourceInstanceName">{{vfi.resourceInstanceName}}</option> </select> </div> </div> <div class="right"> - <div style="padding: 0.7em 0.5em; padding-top: 1em; font-weight: 600;">Flow diagram</div> + <div style="padding: 0.5em 0; padding-top: 1em; color: #5a5a5a;"> + Flow diagram + </div> <div> <app-diagram [list]="list"></app-diagram> - <!-- <img style="width:100%; height:100%;" src="https://upload.wikimedia.org/wikipedia/commons/thumb/7/73/Flag_of_Romania.svg/1200px-Flag_of_Romania.svg.png" - alt="flow"> --> </div> </div> </form> diff --git a/public/src/app/general/general.component.scss b/public/src/app/general/general.component.scss index d76e1ae..0420a57 100644 --- a/public/src/app/general/general.component.scss +++ b/public/src/app/general/general.component.scss @@ -14,19 +14,23 @@ box-shadow: none; border-radius: 0; } + .toast-container .toast:hover { box-shadow: none; } .field { margin: 1em; + margin-left: 0; .field-label { padding-bottom: 0.5em; + color: #5a5a5a; + font-weight: normal; + font-size: 12px; } .required::before { content: '*'; color: red; - padding-right: 5px; } .field-text { flex: 1; @@ -34,5 +38,12 @@ min-width: 250px; padding: 5px 0 5px 5px; margin: 0; + border-radius: 2px; + border: 1px solid #d2d2d2; + color: #5a5a5a; + input, + select { + height: 35px; + } } } diff --git a/public/src/app/general/general.component.spec.ts b/public/src/app/general/general.component.spec.ts index fb761db..7091d0f 100644 --- a/public/src/app/general/general.component.spec.ts +++ b/public/src/app/general/general.component.spec.ts @@ -1,55 +1,43 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { GeneralComponent, groupingData } from './general.component'; -import { sortBy } from 'lodash'; - -const data = [ - { - name: 'avi', - version: '2.0' - }, - { - name: 'stone', - version: '0.9' - }, - { - name: 'avi', - version: '2.1' - }, - { - name: 'vosk', - version: '0.1' - }, - { - name: 'liav', - version: '0.5' - } -]; -const sortedMatchVfcmtList = ['avi', 'liav', 'stone', 'vosk']; -const sortedVersionInGroup = [ - { - name: 'avi', - version: '2.1' - }, - { - name: 'avi', - version: '2.0' - } -]; - -describe('GeneralComponent', () => { - it('should sort vfcmt by A to Z', () => { - const sorted = groupingData(data); - const vfcmtList = sortBy(Object.keys(sorted), name => name); - expect(vfcmtList).toEqual(sortedMatchVfcmtList); - }); - - it('should group vfcmt by name', () => { - const sorted = groupingData(data); - expect(Object.keys(sorted)).toEqual(['avi', 'stone', 'vosk', 'liav']); - }); - - it('should version array be sorted in group', () => { - const sorted = groupingData(data); - expect(Object.values(sorted)[0]).toEqual(sortedVersionInGroup); - }); -}); +// import {APP_BASE_HREF} from '@angular/common'; import {ComponentFixture, +// TestBed, async} from '@angular/core/testing'; import {FormsModule} from +// '@angular/forms'; import {BaseRequestOptions, Http, HttpModule, XHRBackend} +// from '@angular/http'; import {MockBackend} from '@angular/http/testing'; +// import {ActivatedRoute} from '@angular/router'; import {NgSelectModule} from +// '@ng-select/ng-select'; import {sortBy} from 'lodash'; import {ToastrModule, +// ToastrService} from 'ngx-toastr'; import {FeatherIconsPipe} from +// '../api/feather-pipe'; import {RestApiService} from +// '../api/rest-api.service'; import {DiagramComponent} from +// '../diagram/diagram.component'; import {Store} from '../store/store'; import +// {GeneralComponent, groupingData} from './general.component'; const data = [ +// { name: 'avi', version: '2.0' }, { name: 'stone', version: +// '0.9' }, { name: 'avi', version: '2.1' }, { name: 'vosk', +// version: '0.1' }, { name: 'liav', version: '0.5' } ]; const +// sortedMatchVfcmtList = ['avi', 'liav', 'stone', 'vosk']; const +// sortedVersionInGroup = [ { name: 'avi', version: '2.1' }, { +// name: 'avi', version: '2.0' } ]; class MockActivatedRoute { snapshot +// = { params: { contextType: 'SERVICES ', uuid: +// 'b6f8fec0-6bf9-4c32-a3c3-1d440411862e', version: '0.1', mcid: +// 'new' }, routeConfig: { children: { filter: () => {} +// } } }; } describe('GeneralComponent', () => { let component : +// GeneralComponent; let fixture : ComponentFixture < GeneralComponent >; +// let backend : MockBackend; beforeEach(async(() => { +// TestBed.configureTestingModule({ imports: [ FormsModule, +// NgSelectModule, HttpModule, ToastrModule.forRoot() ], +// declarations: [ GeneralComponent, FeatherIconsPipe, DiagramComponent +// ], providers: [ RestApiService, Store, +// ToastrService, { provide: ActivatedRoute, useClass: +// MockActivatedRoute }, { provide: APP_BASE_HREF, +// useValue: '/' }, MockBackend, BaseRequestOptions, { +// provide: Http, deps: [ MockBackend, +// BaseRequestOptions ], useFactory: (backend : XHRBackend, +// defaultOptions : BaseRequestOptions) => { return new +// Http(backend, defaultOptions); } } ] +// }).compileComponents(); backend = TestBed.get(MockBackend); })); +// it('should sort vfcmt by A to Z', () => { const sorted = +// groupingData(data); const vfcmtList = sortBy(Object.keys(sorted), name => +// name); expect(vfcmtList).toEqual(sortedMatchVfcmtList); }); +// it('should group vfcmt by name', () => { const sorted = +// groupingData(data); expect(Object.keys(sorted)).toEqual(['avi', 'stone', +// 'vosk', 'liav']); }); it('should version array be sorted in group', () => +// { const sorted = groupingData(data); +// expect(Object.values(sorted)[0]).toEqual(sortedVersionInGroup); }); }); diff --git a/public/src/app/general/general.component.ts b/public/src/app/general/general.component.ts index 422d834..1b1f708 100644 --- a/public/src/app/general/general.component.ts +++ b/public/src/app/general/general.component.ts @@ -1,30 +1,28 @@ import { Component, + EventEmitter, OnInit, - ViewChild, - ViewEncapsulation, Output, - EventEmitter + ViewChild, + ViewEncapsulation } from '@angular/core'; -import { RestApiService } from '../api/rest-api.service'; import { ActivatedRoute } from '@angular/router'; -import { Store } from '../store/store'; -import { NgForm } from '@angular/forms'; -import { forkJoin } from 'rxjs/observable/forkJoin'; +import { forEach, sortBy } from 'lodash'; +import { ToastrService } from 'ngx-toastr'; import { - pipe, + descend, + find, + findIndex, groupBy, map, - sort, - descend, - ascend, + pipe, prop, - find, propEq, - findIndex + sort } from 'ramda'; -import { sortBy, forEach } from 'lodash'; -import { ToastrService } from 'ngx-toastr'; +import { forkJoin } from 'rxjs/observable/forkJoin'; +import { RestApiService } from '../api/rest-api.service'; +import { Store } from '../store/store'; export const groupingData = pipe( groupBy(prop('name')), @@ -64,12 +62,6 @@ export class GeneralComponent implements OnInit { disableVnfiList = false; @Output() updateCdumpEv = new EventEmitter<string>(); @ViewChild('generalForm') generalForm; - // list = [ - // { source: 'node1dsvsdsvd', target: 'node2' }, - // { source: 'node3', target: 'node4' }, - // { source: 'node5', target: 'nodedsvsds6' }, - // { source: 'node7', target: 'node8' } - // ]; list = []; constructor( @@ -142,13 +134,23 @@ export class GeneralComponent implements OnInit { .subscribe( response => { this.newVfcmt = response.vfcmt; - this.flowTypes.push(this.newVfcmt.flowType); + this.flowTypes.push(response.cdump.flowType); + this.newVfcmt.flowType = response.cdump.flowType; + this.store.flowType = response.cdump.flowType; this.newVfcmt.vfni = this.store.vfiName; this.vfniList.push({ resourceInstanceName: this.newVfcmt.vfni }); - // this.store.cdump = response.cdump; this.updateCdumpEv.next(response.cdump); this.store.isEditMode = true; this.store.loader = false; + + this.list = response.cdump.relations.map(item => { + return { + name1: item.name1, + name2: item.name2, + p1: item.meta.p1, + p2: item.meta.p2 + }; + }); }, error => { this.notifyError(error); diff --git a/public/src/app/home/home.component.html b/public/src/app/home/home.component.html index 90e82d3..8cea741 100644 --- a/public/src/app/home/home.component.html +++ b/public/src/app/home/home.component.html @@ -1,18 +1,19 @@ -<div class="container"> +<div class="home-container"> <div style="display: flex; + padding-bottom:7px; justify-content: space-between;"> - <div style="font-size: 1.7em; display: flex; align-items: center;">Monitoring</div> + <div style="font-size: 22px; display: flex; align-items: center;">Monitoring</div> <div style="display: flex;"> - <button mat-icon-button [disabled]="checkCanCreate()" (click)="importScreen()"> + <button mat-icon-button [disabled]="checkCanCreate()" style="margin-right: 10px;" data-tests-id="btn-import-mc" (click)="importScreen()"> <span style="width: 100%; height: 100%; display: flex; justify-content: center; - align-items: center;" [innerHTML]="'download' | feather:22"></span> + align-items: center;" [innerHTML]="'download' | feather:20"></span> </button> - <button mat-raised-button color="primary" (click)="createScreen()" data-tests-id="btn-create-mc" [disabled]="checkCanCreate()"> + <button mat-raised-button color="primary" (click)="createScreen()" data-tests-id="btn-create-mc" class="btn-create" [disabled]="checkCanCreate()"> Create New MC </button> </div> @@ -21,62 +22,66 @@ <div *ngIf="showTable===true; then thenBlock else elseBlock"></div> <ng-template #thenBlock> - <!-- Table --> - <div class="table-wrapper"> - <div *ngIf="unavailableMonitoringComponents.length > 0" data-tests-id="unavailableArea" style="color: white; background: red; padding: 1rem; border-radius: 5px; font-weight: bold; margin: 1em 0;"> - <div *ngFor="let item of unavailableMonitoringComponents"> - {{item.uuid}} - </div> + + <div *ngIf="unavailableMonitoringComponents.length > 0" data-tests-id="unavailableArea" style="color: white; background: red; padding: 1rem; border-radius: 5px; font-weight: bold; margin: 1em 0;"> + <div *ngFor="let item of unavailableMonitoringComponents"> + {{item.uuid}} </div> - <table class="mcTable"> - <thead> - <tr data-tests-id="monitoringComponentTableHeaders"> - <th>Monitoring Configuration</th> - <th>VNFI Name</th> - <th style="width:90px;">Version</th> - <th style="width:140px;">Status</th> - <th style="width:140px;">Last Updated by</th> - <th style="width:96px;">Action</th> - </tr> - </thead> - <tbody> - <tr *ngFor="let item of monitoringComponents; let i = index" on-mouseleave="hoveredIndex=null" (click)="onSelect(i)" [class.active]="i == selectedLine" - data-tests-id="monitoringComponentTableItems" on-mouseover="hoveredIndex=i"> - <td color="blue"> - <div [hidden]="checkHoverCondition(item)" data-tests-id="tableItemsMonitoringConfiguration" class="table-Monitoring-Component" (click)="editItem(item)"> - {{item.name}} - </div> - </td> - <td> - <span pTooltip="{{item.vfiName}}" tooltipPosition="bottom" style="padding:5px;">{{item.vfiName}}</span> - </td> - <td style="width:90px;">{{item.version}}</td> - <td style="width:140px;">{{item.status}}</td> - <td style="width:140px;">{{item.lastUpdaterUserId}}</td> - <td style="width:80px;"> - <div *ngIf="i==hoveredIndex" [hidden]="checkHoverCondition(item)"> - <button mat-icon-button data-tests-id="tableItemsButtonDelete" (click)="deleteItem(item)" style="width:30px; height: 30px;"> - <span style="width: 100%; - height: 100%; - display: flex; - justify-content: center; - align-items: center;" [innerHTML]="'trash-2' | feather:18"></span> - </button> - </div> - <div *ngIf="i==hoveredIndex" [hidden]="!checkHoverCondition(item)"> - <button mat-icon-button data-tests-id="tableItemsButtonInfo" style="width:30px; height: 30px;"> - <span style="width: 100%; - height: 100%; - display: flex; - justify-content: center; - align-items: center;" [innerHTML]="'info' | feather:18"></span> - </button> - </div> - </td> - </tr> - </tbody> - </table> </div> + + <ngx-datatable data-tests-id="monitoringComponentTable" class="material" [rows]="monitoringComponents" [loadingIndicator]="loadingIndicator" [columnMode]="'flex'" + [headerHeight]="40" [footerHeight]="40" [limit]="10" [rowHeight]="40"(selected)="onTableSelectItem($event)" + [selectionType]="'single'" [selected]="selectedLine" (activate)="onTableActivate($event)"> + + <ngx-datatable-column name="Monitoring Configuration" prop="name" [flexGrow]="3"> + <ng-template let-row="row" let-value="value" ngx-datatable-cell-template> + + <div data-tests-id="tableItemsMonitoringConfiguration" [hidden]="checkTableItemHoverCondition(row)" (click)="editTableItem(row)" + class="ngx-datatable-monitoring-name"> + <span> {{value}} </span> + </div> + <div data-tests-id="tableItemsMonitoringConfigurationNotOwner" [hidden]="!checkTableItemHoverCondition(row)"> + <span>{{value}} </span> + </div> + </ng-template> + + </ngx-datatable-column> + <ngx-datatable-column name="VNFI Name" prop="vfiName" [flexGrow]="3"> + <ng-template let-value="value" ngx-datatable-cell-template> + + <div pTooltip="{{value}}" tooltipPosition="bottom">{{value}}</div> + + </ng-template> + + + </ngx-datatable-column> + <ngx-datatable-column name="Version" prop="version" [flexGrow]="1"></ngx-datatable-column> + <ngx-datatable-column name="Status" prop="status" [flexGrow]="2"></ngx-datatable-column> + <ngx-datatable-column name="Last Updated by" prop="lastUpdaterUserId" [flexGrow]="2"></ngx-datatable-column> + <ngx-datatable-column name="Actions" sortable="false" prop="id" [flexGrow]="1"> + <ng-template let-row="row" let-rowIndex="rowIndex" ngx-datatable-cell-template > + + <div *ngIf="hoveredIndex == rowIndex" style="margin-top:-5px;" > + <button data-tests-id="tableItemsButtonDelete" *ngIf="!checkTableItemHoverCondition(row); else elseBtnBlock" mat-icon-button + data-tests-id="tableItemsButtonDelete" (click)="deleteTableItem(row, rowIndex)" style="width:30px; height: 30px;"> + <span style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;" [innerHTML]="'trash-2' | feather:18"></span> + </button> + + <ng-template #elseBtnBlock> + + <button data-tests-id="tableItemsButtonInfo" mat-icon-button data-tests-id="tableItemsButtonInfo" style="width:30px; height: 30px;"> + <span style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;" [innerHTML]="'info' | feather:18"></span> + </button> + </ng-template> + + </div> + + </ng-template> + </ngx-datatable-column> + + </ngx-datatable> + + </ng-template> <ng-template #elseBlock> @@ -85,22 +90,21 @@ justify-content: center; align-items: center; flex:1;"> - <div style="font-size: 1.5em;"> + <div style="font-size: 18px;"> Monitoring Configuration does not Exist </div> - <div style="padding: 0.5em; padding-top: 1em;" data-tests-id="new-monitoring-title"> + <div style="padding: 0.5em; padding-top: 1em; font-size: 13px;" data-tests-id="new-monitoring-title"> A Monitoring Configuration (MC) was not yet created </div> - <div> + <div style="font-size: 13px;"> Please create a new MC to monitor the service </div> <div class="wrapper-btn-add-mc"> <button mat-mini-fab color="primary" (click)="createScreen()" data-tests-id="btn-fab-create-mc" [disabled]="checkCanCreate()"> <span [innerHTML]="'plus' | feather:24"></span> </button> - <span data-tests-id="btn-span-create-mc" style="margin-top: 1rem; font-size: 1.2em; font-weight: 400;" [style.color]="checkCanCreate() ? '#ebebe4' : '#009FDB'">Add First MC</span> + <span data-tests-id="btn-span-create-mc" style="margin-top: 10px; font-size: 14px; " [style.color]="checkCanCreate() ? '#ebebe4' : '#009FDB'">Add First MC</span> </div> </div> </ng-template> </div> - diff --git a/public/src/app/home/home.component.scss b/public/src/app/home/home.component.scss index 583705f..2217b7d 100644 --- a/public/src/app/home/home.component.scss +++ b/public/src/app/home/home.component.scss @@ -1,110 +1,78 @@ -.container { +@import '~@swimlane/ngx-datatable/release/themes/material.css'; +.home-container { display: flex; flex-direction: column; height: 100%; - padding: 0.5em; + margin: 15px 20px; margin-left: 15px; margin-right: 15px; .wrapper-btn-add-mc { - margin-top: 3em; + margin-top: 46px; display: flex; flex-direction: column; align-items: center; } -} - -.table-Monitoring-Component { - &:hover { - color: #009fdb; - text-decoration: underline; - cursor: pointer; + .btn-create { + width: 150px; + height: 36px; } } -.table-wrapper { - display: flex; - justify-content: center; - flex: 1; - margin-bottom: 2em; - flex-direction: column; - display: block; +.my-confrim-dialog .mat-dialog-container { + max-width: 600px; + width: 500px; + height: 200px; + padding: 0; } -table.mcTable { - display: flex; - flex-flow: column; - height: calc(100vh - 150px); - width: 100%; - background-color: #ffffff; - color: #5a5a5a; -} -table.mcTable thead { - /* head takes the height it requires, - and it's not scaled when table.mcTable is resized */ - flex: 0 0 auto; - // width: calc(100% - 17px); - width: 100%; -} -table.mcTable tbody { - /* body takes all the remaining available space */ - flex: 1 1 auto; - display: block; - overflow-y: scroll; -} -table.mcTable tbody tr { - width: 100%; -} - -table.mcTable thead, -table.mcTable tbody tr { - display: table; - table-layout: fixed; +/deep/ .ui-tooltip .ui-tooltip-text { + font-size: 0.8em; + padding: 0.7em; } -table.mcTable { - border-collapse: collapse; - border-spacing: 0px; +/deep/ .ui-tooltip { + max-width: 400px; } -table.mcTable tr.active td { - background-color: #e6f6fb !important; - color: #5a5a5a; +.ngx-datatable-monitoring-name { + &:hover { + color: #009fdb; + text-decoration: underline; + cursor: pointer; + } } -table.mcTable th { +.ngx-datatable.material .datatable-header .datatable-header-cell { background: #f4f4f4; - color: #191919; - text-align: left; -} -table.mcTable tr { - &:hover { - background-color: #f8f8f8; - color: #5a5a5a; + span { + font-weight: bold; + font-size: 13px; + font-family: 'Open Sans', sans-serif !important; } } -table.mcTable table, -table.mcTable th, -table.mcTable td { - padding: 5px 10px; - border: 0.5px solid #d2d2d2; - border-bottom: none; - height: 40px; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; +.ngx-datatable .datatable-body-cell, +.ngx-datatable .datatable-header-cell { + border: 0.1px solid #d2d2d2; } -table.mcTable tr:last-child { - border-bottom: 0.5px solid #d2d2d2; -} - -/deep/ .ui-tooltip .ui-tooltip-text { - font-size: 0.8em; - padding: 0.7em; +.ngx-datatable.material.single-selection .datatable-body-row.active, +.ngx-datatable.material.single-selection + .datatable-body-row.active + .datatable-row-group, +.ngx-datatable.material.multi-selection .datatable-body-row.active, +.ngx-datatable.material.multi-selection + .datatable-body-row.active + .datatable-row-group, +.ngx-datatable.material.multi-click-selection .datatable-body-row.active, +.ngx-datatable.material.multi-click-selection + .datatable-body-row.active + .datatable-row-group { + background-color: #e6f6fb !important; + color: #5a5a5a; } -/deep/ .ui-tooltip { - max-width: 400px; +.ngx-datatable.material { + box-shadow: none; } diff --git a/public/src/app/home/home.component.ts b/public/src/app/home/home.component.ts index 1c538c0..349a031 100644 --- a/public/src/app/home/home.component.ts +++ b/public/src/app/home/home.component.ts @@ -1,28 +1,31 @@ -import { Component } from '@angular/core'; -import { Store } from '../store/store'; -import { HostService } from '../host/host.service'; +import { ChangeDetectorRef, Component, ViewEncapsulation } from '@angular/core'; +import { MatDialog } from '@angular/material'; import { ActivatedRoute, Router } from '@angular/router'; +import { ToastrService } from 'ngx-toastr'; import { RestApiService } from '../api/rest-api.service'; -import { NgIf } from '@angular/common'; +import { HostService } from '../host/host.service'; import { ConfirmPopupComponent } from '../rule-engine/confirm-popup/confirm-popup.component'; -import { MatDialog } from '@angular/material'; -import { ToastrService } from 'ngx-toastr'; -import { ChangeDetectorRef } from '@angular/core'; +import { PluginPubSub } from '../sdc/plugin-pubsub'; +import { Store } from '../store/store'; +import { NgxDatatableModule } from '@swimlane/ngx-datatable'; @Component({ selector: 'app-home', templateUrl: './home.component.html', - styleUrls: ['./home.component.scss'] + styleUrls: ['./home.component.scss'], + encapsulation: ViewEncapsulation.None }) export class HomeComponent { linkToMain: string; - currentUserId: string; showTable = true; - selectedLine; + selectedLine = []; monitoringComponents = new Array(); unavailableMonitoringComponents = new Array(); - hoveredIndex = null; + hoveredIndex = 1; dialogRef; + deleteRow: number; + + loadingIndicator = true; constructor( private activeRoute: ActivatedRoute, @@ -37,14 +40,58 @@ export class HomeComponent { this.activeRoute.queryParams.subscribe(params => { console.log('params: %o', params); this.store.sdcParmas = params; + + console.log('init comunication with sdc'); + const eventsToWaitFor = [ + 'WINDOW_OUT', + 'VERSION_CHANGE', + 'CHECK_IN', + 'CHECK_OUT', + 'SUBMIT_FOR_TESTING', + 'UNDO_CHECK_OUT' + ]; + this.store.ifrmaeMessenger = new PluginPubSub( + this.store.sdcParmas.eventsClientId, + this.store.sdcParmas.parentUrl, + eventsToWaitFor + ); + console.log('send ready to sdc'); + this.store.ifrmaeMessenger.notify('READY'); + + this.store.ifrmaeMessenger.on((eventData, event) => { + console.log('eventData', eventData); + console.log('event', event); + if ( + eventData.type === 'WINDOW_OUT' || + eventData.type === 'CHECK_IN' || + eventData.type === 'SUBMIT_FOR_TESTING' + ) { + const currentUrl = this.route.url; + if (currentUrl.includes('main')) { + if (this.store.cdumpIsDirty) { + this.store.displaySDCDialog = true; + } else { + this.store.ifrmaeMessenger.notify('ACTION_COMPLETED'); + } + } else { + this.store.ifrmaeMessenger.notify('ACTION_COMPLETED'); + } + } else { + this.store.ifrmaeMessenger.notify('ACTION_COMPLETED'); + } + }); + this.linkToMain = `/main/${params.contextType}/${params.uuid}/${ params.version }/`; + this.loadingIndicator = true; + this._restApi.getMonitoringComponents(params).subscribe( response => { console.log('response: ', response); if (response.hasOwnProperty('monitoringComponents')) { this.monitoringComponents = response.monitoringComponents; + this.loadingIndicator = false; } if (response.hasOwnProperty('unavailable')) { this.unavailableMonitoringComponents = response.unavailable; @@ -83,8 +130,11 @@ export class HomeComponent { } } - checkHoverCondition(item: any): boolean { + // Monitoring Table logic + + checkTableItemHoverCondition(item: any): boolean { if ( + this.store.sdcParmas !== undefined && this.store.sdcParmas.userId === item.lastUpdaterUserId && this.store.sdcParmas.lifecycleState === 'NOT_CERTIFIED_CHECKOUT' ) { @@ -94,12 +144,19 @@ export class HomeComponent { } } - editItem(item: any): void { + onTableActivate(event: any): void { + this.hoveredIndex = this.monitoringComponents.findIndex( + s => s == event.row + ); + console.log('selected : '); + } + + editTableItem(item: any): void { this.store.vfiName = item.vfiName; this.route.navigate([this.linkToMain + '/' + item.uuid]); } - onSelect(item: any): void { + onTableSelectItem(item: any): void { this.selectedLine = item; console.log('selected : ', item); } @@ -107,17 +164,17 @@ export class HomeComponent { deleteEnable(item: any): boolean { console.log( 'delete enable: ', - item.isOwner && item.Lifecycle == 'NOT_CERTIFIED_CHECKOUT' + item.isOwner && item.Lifecycle === 'NOT_CERTIFIED_CHECKOUT' ); const { userId, lifecycleState } = this.store.sdcParmas; return ( - item.lastUpdaterUserId == userId && - lifecycleState == 'NOT_CERTIFIED_CHECKOUT' + item.lastUpdaterUserId === userId && + lifecycleState === 'NOT_CERTIFIED_CHECKOUT' ); } - deleteItem(item: any): void { - let deleteRow = this.hoveredIndex; + deleteTableItem(item: any, index: any): void { + this.deleteRow = index; this.dialogRef = this.dialog.open(ConfirmPopupComponent, { panelClass: 'my-confrim-dialog', disableClose: true @@ -125,7 +182,7 @@ export class HomeComponent { this.dialogRef.afterClosed().subscribe(result => { // if the user want to delete if (result) { - if (item.status == 'submitted') { + if (item.status === 'Submitted') { this._restApi .deleteMonitoringComponentWithBlueprint( this.store.sdcParmas, @@ -135,15 +192,15 @@ export class HomeComponent { ) .subscribe( response => { - this.itemDeletedRemoveAndNotify(deleteRow); + this.itemDeletedRemoveAndNotify(this.deleteRow); }, error => { if (error.messageId === 'SVC6118') { - this.monitoringComponents.splice(deleteRow, 1); + this.monitoringComponents.splice(this.deleteRow, 1); this.changeDetectorRef.detectChanges(); } const errorMsg = Object.values(error.requestError) as any; - this.toastr.error('', errorMsg[0]); + this.toastr.error('', errorMsg[0].formattedErrorMessage); } ); } else { @@ -155,7 +212,7 @@ export class HomeComponent { ) .subscribe( response => { - this.itemDeletedRemoveAndNotify(deleteRow); + this.itemDeletedRemoveAndNotify(this.deleteRow); }, error => { const errorMsg = Object.values(error.requestError) as any; @@ -175,14 +232,4 @@ export class HomeComponent { 'Monitoring Configuration was successfully deleted' ); } - - // convertFile(fileInput: any) { - // // read file from input - // const fileReaded = fileInput.target.files[0]; - // Papa.parse(fileReaded, { - // complete: function(results) { - // console.log('Finished:', results.data); - // } - // }); - // } } diff --git a/public/src/app/loader/loader.component.spec.ts b/public/src/app/loader/loader.component.spec.ts index 7c82913..2159e0d 100644 --- a/public/src/app/loader/loader.component.spec.ts +++ b/public/src/app/loader/loader.component.spec.ts @@ -1,8 +1,7 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { LoaderComponent } from './loader.component'; -describe('LoaderComponent', () => { +describe('DiagramComponent', () => { let component: LoaderComponent; let fixture: ComponentFixture<LoaderComponent>; diff --git a/public/src/app/main/main.component.html b/public/src/app/main/main.component.html index d54b27b..4c71a37 100644 --- a/public/src/app/main/main.component.html +++ b/public/src/app/main/main.component.html @@ -1,4 +1,4 @@ -<div class="container"> +<div class="main-container"> <div style="padding: .25em; display: flex; justify-content: space-between; @@ -6,16 +6,18 @@ <div> <a (click)="goBack()" data-tests-id="btn-back-home" style="display: flex; cursor: pointer;text-decoration: none; color: #009fdb;"> <mat-icon fontSet="fontawesome" fontIcon="fa-angle-left" style="height: 17px; width: 12px; font-size: 17px;"></mat-icon> - <span style="display: flex; align-items: center;">Back to Monitoring</span> + <span style="display: flex; align-items: center; font-size: 12px;"> + Back to Monitoring + </span> </a> <div style="margin:10px 0;" data-tests-id="new-monitorying-titie"> - <span style="font-size: 2em;" *ngIf='store.generalflow === "new"'> + <span style="font-size: 22px;" *ngIf='store.generalflow === "new"'> New </span> - <span style="font-size: 2em;" *ngIf='store.generalflow === "import"'> + <span style="font-size: 22px;" *ngIf='store.generalflow === "import"'> Import </span> - <span style="font-size: 2em;"> + <span style="font-size: 22px;"> Monitoring Configuration </span> </div> @@ -24,7 +26,9 @@ <div> <div *ngIf='store.generalflow === "new" || store.generalflow === "edit"'> <button *ngIf="!this.store.isEditMode" mat-raised-button color="primary" [disabled]="this.generalComponent.generalForm.invalid" - data-tests-id="createMonitoring" (click)="createMC(this.generalComponent.generalForm.value)">Create</button> + style="width: 95px;height: 36px;" data-tests-id="createMonitoring" (click)="createMC(this.generalComponent.generalForm.value)"> + Create + </button> <div *ngIf="this.store.isEditMode" style="display: flex;"> <button mat-icon-button (click)="saveCDUMP()" [disabled]="!store.cdumpIsDirty"> @@ -35,12 +39,12 @@ justify-content: center; align-items: center;" [innerHTML]="'save' | feather:22"></span> </button> - <button mat-raised-button color="primary" (click)="saveAndCreateBlueprint()">Submit</button> + <button mat-raised-button color="primary" style="width: 95px; height: 36px; border-radius: 2px;" (click)="saveAndCreateBlueprint()">Submit</button> </div> </div> <div *ngIf='store.generalflow === "import"'> <button mat-raised-button color="primary" (click)="importMC(this.generalComponent.newVfcmt)" [disabled]="this.generalComponent.generalForm.invalid" - data-tests-id="importMonitoring">Import</button> + data-tests-id="importMonitoring" style="width: 95px;height: 36px;">Import</button> </div> </div> </div> @@ -53,7 +57,7 @@ <app-general (updateCdumpEv)="updateCdump($event)"></app-general> </div> </p-tabPanel> - <p-tabPanel *ngFor="let item of nodes" [header]="item.name"> + <p-tabPanel *ngFor="let item of nodes;" [header]="item.name"> <app-rule-frame [tabName]="item.name"></app-rule-frame> </p-tabPanel> </p-tabView> diff --git a/public/src/app/main/main.component.scss b/public/src/app/main/main.component.scss index 402a56a..47f1bd9 100644 --- a/public/src/app/main/main.component.scss +++ b/public/src/app/main/main.component.scss @@ -1,7 +1,6 @@ -.container { +.main-container { display: flex; - flex-direction: column; - // height: 100%; + flex-direction: column; // height: 100%; margin: 1em; } @@ -16,11 +15,12 @@ .ui-tabview .ui-tabview-nav li { margin: 0; + border-radius: 0; } .ui-tabview .ui-tabview-nav li.ui-tabview-selected { color: #009fdb; - border-top: 4px solid #009fdb; + border-top: 2px solid #009fdb; border-bottom: none; } diff --git a/public/src/app/main/main.component.ts b/public/src/app/main/main.component.ts index fdbb077..a3f2271 100644 --- a/public/src/app/main/main.component.ts +++ b/public/src/app/main/main.component.ts @@ -1,12 +1,11 @@ -import { Component, ViewEncapsulation, ViewChild } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; import { Location } from '@angular/common'; +import { Component, ViewChild, ViewEncapsulation } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { ToastrService } from 'ngx-toastr'; import { RestApiService } from '../api/rest-api.service'; -import { Store } from '../store/store'; -import { RuleFrameComponent } from '../rule-frame/rule-frame.component'; import { GeneralComponent } from '../general/general.component'; -import { ToastrService } from 'ngx-toastr'; -import { forkJoin } from 'rxjs/observable/forkJoin'; +import { RuleEngineApiService } from '../rule-engine/api/rule-engine-api.service'; +import { Store } from '../store/store'; @Component({ selector: 'app-main', @@ -18,11 +17,13 @@ export class MainComponent { cdump; nodes = []; @ViewChild(GeneralComponent) generalComponent: GeneralComponent; - // @ViewChildren(RuleFrameComponent) ruleFrameRef: QueryList<RuleFrameComponent>; + // @ViewChildren(RuleFrameComponent) ruleFrameRef: + // QueryList<RuleFrameComponent>; constructor( private route: ActivatedRoute, private restApi: RestApiService, + private _ruleApi: RuleEngineApiService, private toastr: ToastrService, public store: Store, private location: Location @@ -39,6 +40,8 @@ export class MainComponent { createMC(params) { console.log('newVfcmt: %o', params); this.store.loader = true; + this.store.vfiName = params.serviceAttached; + this.store.flowType = 'default'; this.restApi .createNewVFCMT({ name: params.name, @@ -55,6 +58,7 @@ export class MainComponent { this.store.mcUuid = success.vfcmt.uuid; console.log(this.cleanProperty(success)); this.store.cdump = success.cdump; + this.diagramRelationsFromCdump(success); this.nodes = this.store.cdump.nodes; this.store.setTabsProperties(this.nodes); this.setDataFromMapToRuleEngine(success.cdump); @@ -70,6 +74,17 @@ export class MainComponent { ); } + private diagramRelationsFromCdump(success: any) { + this.generalComponent.list = success.cdump.relations.map(item => { + return { + name1: item.name1, + name2: item.name2, + p1: item.meta.p1, + p2: item.meta.p2 + }; + }); + } + updateCdump(cdump) { this.store.cdump = cdump; this.nodes = this.store.cdump.nodes; @@ -81,6 +96,8 @@ export class MainComponent { console.log('importVfcmt: %o', params); this.generalComponent.importCompleted = true; this.store.loader = true; + this.store.vfiName = params.serviceAttached; + this.store.flowType = params.flowType; this.restApi .importVFCMT({ name: params.name, @@ -96,11 +113,13 @@ export class MainComponent { .subscribe( success => { console.log(success); + this.location.path(); // this.location.go(); this.store.mcUuid = success.vfcmt.uuid; console.log(this.cleanProperty(success)); this.store.cdump = success.cdump; + this.diagramRelationsFromCdump(success); this.nodes = this.store.cdump.nodes; this.store.setTabsProperties(this.nodes); this.setDataFromMapToRuleEngine(success.cdump); @@ -119,12 +138,9 @@ export class MainComponent { setDataFromMapToRuleEngine(cdump) { this.store.tabParmasForRule = cdump.nodes - .filter(x => x.name.includes('map')) + .filter(x => x.name.toLowerCase().includes('map')) .map(y => { - return { - name: y.name, - nid: y.nid - }; + return { name: y.name, nid: y.nid }; }); } @@ -139,7 +155,6 @@ export class MainComponent { } saveCDUMP() { - debugger; this.store.loader = true; this.restApi .saveMonitoringComponent({ @@ -167,7 +182,6 @@ export class MainComponent { } saveAndCreateBlueprint() { - debugger; this.store.loader = true; if (this.store.cdumpIsDirty) { this.restApi @@ -210,6 +224,7 @@ export class MainComponent { .subscribe( success => { this.store.loader = false; + this.toastr.success('', 'Save succeeded'); }, error => { @@ -223,6 +238,7 @@ export class MainComponent { } handleChange(e) { + this._ruleApi.callUpdateTabIndex(e.index - 1); this.store.setTabIndex(e.index - 1); } } diff --git a/public/src/app/rule-engine/action-list/action-list.component.html b/public/src/app/rule-engine/action-list/action-list.component.html index e7879b7..1ee74df 100644 --- a/public/src/app/rule-engine/action-list/action-list.component.html +++ b/public/src/app/rule-engine/action-list/action-list.component.html @@ -1,10 +1,10 @@ <form #actionListFrm="ngForm" class="wrapper" data-tests-id="popupRuleEditor"> <div class="header"> - <div style="display: flex; justify-content: flex-end; align-items: center;"> + <div style="display: flex; justify-content: flex-end; align-items: center; margin-left: 20px;"> <a (click)="closeDialog()" data-tests-id="btnBackRule" style="cursor: pointer;text-decoration: none; color: #009fdb;"> <mat-icon fontSet="fontawesome" fontIcon="fa-angle-left" style="height: 22px; width: 22px; font-size: 22px; padding-right: 20px;"></mat-icon> </a> - <span style="font-size: 18px;">New Rule Editor</span> + <span style="font-size: 18px;">{{title}}</span> </div> <div style="display: flex; justify-content: flex-end; align-items: center; padding: 10px;"> @@ -17,7 +17,7 @@ align-items: center;" [innerHTML]="'save' | feather:22"></span> </button> - <button mat-raised-button [disabled]="actions.length === 0" style="height: 35px; margin-left: 20px;" color="primary" data-tests-id="btnDone" + <button mat-raised-button [disabled]="actions.length === 0" style="height: 35px; margin-left: 10px;" color="primary" data-tests-id="btnDone" (click)="saveAndDone()"> Done </button> @@ -62,18 +62,24 @@ <div style="display: flex;"> <select [(ngModel)]="selectedAction" name="selectedAction" style="height: 2rem; width: 150px; margin-right: 1rem;" data-tests-id="selectAction"> <option [ngValue]="null" disabled>Select Action</option> + <option value="copy">Copy</option> <option value="concat">Concat</option> <option value="map">Map</option> <option value="date formatter">Date Formatter</option> + <option value="log text">Log Text</option> + <option value="log event">Log Event</option> + <option value="replace text">Replace Text</option> + <option value="clear">Clear</option> + </select> <div style="display: flex; align-items: center;"> - <button mat-mini-fab color="primary" style="height: 24px; width: 24px; display:flex; justify-content: center;" (click)="addAction2list(selectedAction)" + <button mat-mini-fab color="primary" style="height: 16px; width: 16px; display:flex; justify-content: center;" (click)="addAction2list(selectedAction)" data-tests-id="btnAddAction"> - <span style="display: flex; justify-content: center; align-items: center" [innerHTML]="'plus' | feather:16"></span> + <span style="display: flex; justify-content: center; align-items: center" [innerHTML]="'plus' | feather:12"></span> </button> - <span style="color: #009FDB; display: flex; justify-content: center; padding-left: 10px">Add Action</span> + <span style="color: #009FDB; display: flex; justify-content: center; padding-left: 6px">Add Action</span> </div> </div> diff --git a/public/src/app/rule-engine/action-list/action-list.component.scss b/public/src/app/rule-engine/action-list/action-list.component.scss index 39b9dce..67fa048 100644 --- a/public/src/app/rule-engine/action-list/action-list.component.scss +++ b/public/src/app/rule-engine/action-list/action-list.component.scss @@ -9,7 +9,9 @@ justify-content: space-between; align-items: center; color: #191919; - border-bottom: 2px solid #d2d2d2; + border-bottom: 1px solid #d2d2d2; + padding-bottom: 0px; + margin: 0; // padding: 0.4rem 1rem; } diff --git a/public/src/app/rule-engine/action-list/action-list.component.ts b/public/src/app/rule-engine/action-list/action-list.component.ts index 40ff46d..27a74d4 100644 --- a/public/src/app/rule-engine/action-list/action-list.component.ts +++ b/public/src/app/rule-engine/action-list/action-list.component.ts @@ -1,20 +1,16 @@ import { + AfterViewInit, Component, - Inject, - ViewChildren, QueryList, - AfterViewInit, ViewChild, - Input + ViewChildren } from '@angular/core'; -import { RuleEngineApiService } from '../api/rule-engine-api.service'; -import { Subject } from 'rxjs/Subject'; -import { v1 as uuid } from 'uuid'; -import { environment } from '../../../environments/environment'; -import { ActionComponent } from '../action/action.component'; +import { NgForm } from '@angular/forms'; import { cloneDeep } from 'lodash'; +import { v1 as uuid } from 'uuid'; import { Store } from '../../store/store'; -import { NgForm } from '@angular/forms'; +import { ActionComponent } from '../action/action.component'; +import { RuleEngineApiService } from '../api/rule-engine-api.service'; @Component({ selector: 'app-action-list', @@ -22,6 +18,7 @@ import { NgForm } from '@angular/forms'; styleUrls: ['./action-list.component.scss'] }) export class ActionListComponent implements AfterViewInit { + title = ''; error: Array<string>; condition: any; eventType: string; @@ -53,8 +50,10 @@ export class ActionListComponent implements AfterViewInit { this.condition = data.item.condition; this.uid = data.item.uid; this.description = data.item.description; + this.title = this.description + ' - Rule Editor'; this.ifStatement = this.condition == null ? false : true; } else { + this.title = 'New Rule Editor'; this.actions = new Array(); this.backupActionForCancel = new Array(); this.condition = null; @@ -97,12 +96,24 @@ export class ActionListComponent implements AfterViewInit { value: '', regex: '', state: 'closed', - values: [{ value: '' }, { value: '' }] + values: [ + { + value: '' + }, + { + value: '' + } + ] }, actionType: this.selectedAction, target: '', map: { - values: [{ key: '', value: '' }], + values: [ + { + key: '', + value: '' + } + ], haveDefault: false, default: '' }, @@ -111,6 +122,18 @@ export class ActionListComponent implements AfterViewInit { toFormat: '', fromTimezone: '', toTimezone: '' + }, + replaceText: { + find: '', + replace: '' + }, + logText: { + name: '', + level: '', + text: '' + }, + logEvent: { + title: '' } }); } @@ -162,7 +185,10 @@ export class ActionListComponent implements AfterViewInit { ? item.target : item.selectedNode.id, map: item.map, - dateFormatter: item.dateFormatter + dateFormatter: item.dateFormatter, + replaceText: item.replaceText, + logText: item.logText, + logEvent: item.logEvent }; }); let conditionData2server = null; @@ -178,6 +204,7 @@ export class ActionListComponent implements AfterViewInit { return { version: this.version, eventType: this.eventType, + notifyId: this.store.notifyIdValue, uid: this.uid, description: this.description, actions: actionSetData, @@ -225,12 +252,12 @@ export class ActionListComponent implements AfterViewInit { const actionComp = this.actionsRef.toArray(); const filterInvalidActions = actionComp.filter(comp => { return ( - comp.fromInstance.fromFrm.invalid || - comp.targetInstance.targetFrm.invalid || - comp.actionFrm.invalid + // (comp.fromInstance && comp.fromInstance.fromFrm.invalid) || + // (comp.targetInstance && comp.targetInstance.targetFrm.invalid) || + comp.actionFrm && comp.actionFrm.invalid ); }); - if (this.actionListFrm.valid && filterInvalidActions.length === 0) { + if (this.actionListFrm.valid && filterInvalidActions.length == 0) { const data = this.prepareDataToSaveRule(); this.store.loader = true; this._ruleApi.modifyRule(data).subscribe( @@ -249,11 +276,10 @@ export class ActionListComponent implements AfterViewInit { } ); } else { - // scroll to first invalid element - const elId = filterInvalidActions[0].action.id; - const el = document.getElementById(elId as string); - const label = el.children.item(0) as HTMLElement; - el.scrollIntoView(); + // scroll to first invalid element const elId = + // filterInvalidActions[0].action.id; const el = document.getElementById(elId as + // string); const label = el.children.item(0) as HTMLElement; + // el.scrollIntoView(); } } diff --git a/public/src/app/rule-engine/action/action.component.html b/public/src/app/rule-engine/action/action.component.html index b41ab82..250af34 100644 --- a/public/src/app/rule-engine/action/action.component.html +++ b/public/src/app/rule-engine/action/action.component.html @@ -1,56 +1,151 @@ <form #actionFrm="ngForm" class="conatiner" id="{{action.id}}" (mouseover)="changeStyle($event)" (mouseout)="changeStyle($event)"> <div> + <div class="center-content"> <!-- type info --> <div class="action-info" [ngClass]="highlight"> {{action.actionType | uppercase}} </div> + <!-- from component --> - <app-from #from style="width: 100%" [actionType]="action.actionType" (onFromChange)="updateFrom($event)"></app-from> + <app-from [hidden]="action.actionType === 'log event' || action.actionType === 'log text'" class="center-content-item" #from + [actionType]="action.actionType" (onFromChange)="updateFrom($event)"></app-from> + <!-- target component --> - <app-target #target style="width: 100%" (onTargetChange)="updateTarget($event)" [nodes]="action.nodes"> + <app-target [hidden]="action.actionType === 'clear' || action.actionType === 'replace text' || action.actionType === 'log text' || action.actionType === 'log event'" + #target style="width: 100%" (onTargetChange)="updateTarget($event)" [nodes]="action.nodes"> </app-target> - </div> - <!-- dateFormatter --> - <div *ngIf="action.actionType === 'date formatter'" style="display: flex; flex-direction: column; margin: 1em; align-items: flex-end;"> - <div style="display: flex; margin: 0.5em 0;"> + <!-- log Event --> + <div *ngIf="action.actionType === 'log event'" class="center-content-item"> <div class="from"> - <div class="from-conatiner"> - <div style="display: flex; align-items: center;" class="label"> - <span class="label" style="padding: 0 5px; width: 100px;">From Format</span> - <input class="input-text" ngModel required name="fromFormat" [(ngModel)]="action.dateFormatter.fromFormat" type="text"> + <div class="from-container"> + <div style="display: flex; align-items: center; width: 100%;" class="label"> + <span class="label" style="padding: 0 5px; width: 100px;">Title</span> + <input required class="input-text" data-tests-id="InputLogTitle" ngModel name="title" [(ngModel)]="action.logEvent.title" + type="text" placeholder="The title for the log entry"> </div> </div> </div> + </div> + + <!-- log Text --> + <div *ngIf="action.actionType === 'log text'" class="center-content-item"> <div class="from"> - <div class="from-conatiner"> - <div style="display: flex; align-items: center;" class="label"> - <span class="label" style="padding: 0 5px; width: 100px;">To Format</span> - <input class="input-text" ngModel required name="toFormat" [(ngModel)]="action.dateFormatter.toFormat" type="text"> + <div class="from-container"> + <div style="display: flex; align-items: center; width: 100%;" class="label"> + <span class="label" style="padding: 0 5px; width: 100px;">Log Text</span> + <input required class="input-text" data-tests-id="InputLogText" ngModel name="logText" [(ngModel)]="action.logText.text" + type="text" placeholder="The title for the log entry"> </div> </div> </div> </div> - <div style="display: flex; margin: 0.5em 0;"> - <div class="from"> - <div class="from-conatiner"> - <div style="display: flex; align-items: center;" class="label"> - <span class="label" style="padding: 0 5px; width: 100px;">From Time-zone</span> - <input class="input-text" ngModel required name="fromTimezone" [(ngModel)]="action.dateFormatter.fromTimezone" type="text"> + </div> + + <!-- dateFormatter --> + <div *ngIf="action.actionType === 'date formatter'" style="flex-direction: column; margin-left: 156px; align-items: flex-end;"> + <div style="display: flex; margin: 0.5em 0; padding-left: 6px;"> + <div class="from" style="width:50%;"> + <div class="from-container"> + <div style="display: flex; align-items: center; width: 100%;" class="label"> + <span class="label" style="padding: 0 5px; width: 100px;">From Format</span> + <input data-tests-id="InputFromFormat" class="input-text" ngModel required name="fromFormat" [(ngModel)]="action.dateFormatter.fromFormat" type="text"> + </div> + </div> + </div> + <div class="from" style="width:50%; padding: 0;"> + <div class="from-container"> + <div style="display: flex; align-items: center; width: 100%;" class="label"> + <span class="label" style="padding: 0 5px; width: 100px;">To Format</span> + <input data-tests-id="InputToFormat" class="input-text" ngModel required name="toFormat" [(ngModel)]="action.dateFormatter.toFormat" type="text"> + </div> + </div> + </div> + </div> + + <div style="display: flex; margin: 0.5em 0; padding-left: 6px;"> + <div class="from" style="width:50%;"> + <div class="from-container"> + <div style="display: flex; align-items: center; width: 100%;" class="label"> + <span class="label" style="padding: 0 5px; width: 132px;">From Time-zone</span> + <input class="input-text" data-tests-id="InputFromTimezone" ngModel required name="fromTimezone" [(ngModel)]="action.dateFormatter.fromTimezone" type="text"> + </div> + </div> + </div> + <div class="from" style="width:50%; padding: 0;"> + <div class="from-container"> + <div style="display: flex; align-items: center; width: 100%;" class="label"> + <span class="label" style="padding: 0 5px; width: 100px;">To Time-zone</span> + <input class="input-text" data-tests-id="InputToTimezone" ngModel required name="toTimezone" [(ngModel)]="action.dateFormatter.toTimezone" type="text"> + </div> + </div> </div> </div> </div> - <div class="from"> - <div class="from-conatiner"> - <div style="display: flex; align-items: center;" class="label"> - <span class="label" style="padding: 0 5px; width: 100px;">To Time-zone</span> - <input class="input-text" ngModel required name="toTimezone" [(ngModel)]="action.dateFormatter.toTimezone" type="text"> + + <!-- replace text --> + <div *ngIf="action.actionType === 'replace text'" class="action-container" style="flex-direction: row; margin-left: 152px; padding: 0 0.8em;"> + + <div class="action-item"> + <div class="from" style="width:100%;"> + <div class="from-container" display="padding:0;"> + + <div class="label" style="width: 100%;"> + <span class="label" style="padding: 0 5px; width: 100px;">Find what</span> + <input data-tests-id="InputFindWhat" class="input-text" ngModel required name="findWhat" [(ngModel)]="action.replaceText.find" + type="text" placeholder="Find text"> + </div> + + </div> + </div> + + </div> + + <div class="action-item"> + <div class="from" style="width: 100%; padding: 0;"> + <div class="from-container"> + + <div class="label" style="width: 100%;"> + <span class="label" style="padding: 0 5px; width: 100px;">Replace with</span> + <input data-tests-id="InputReplaceWith" class="input-text" ngModel required name="replaceWith" [(ngModel)]="action.replaceText.replace" + type="text" placeholder="Replace with text"> + </div> + + </div> + </div> + + </div> + </div> + + <!-- log text --> + <div *ngIf="action.actionType === 'log text'" class="action-container" style="flex-direction: row; margin-left: 152px; padding: 0 0.8em;"> + + <div class="action-item"> + <div class="from" style="width: 100%;"> + <div class="from-container" display="padding:0;"> + <div class="label" style="width: 100%;"> + <span class="label" style="padding: 0 5px; width: 100px;">Log Name</span> + <input class="input-text" data-tests-id="InputLogName" ngModel name="logName" [(ngModel)]="action.logText.name" + type="text" placeholder="Enter log name"> + </div> + </div> + </div> + </div> + + <div class="action-item"> + <div class="from" style="width: 100%; padding: 0;"> + <div class="from-container"> + <div class="label" style="width: 100%;"> + <span class="label" style="padding: 0 5px; width: 100px;">Log Level</span> + <input class="input-text" data-tests-id="InputLogLevel" ngModel required name="logLevel" [(ngModel)]="action.logText.level" + type="text" placeholder="Text to log"> </div> </div> </div> </div> + </div> <!-- Map --> @@ -90,8 +185,8 @@ <input [(ngModel)]="item.value" ngModel required name="mapValue[{{index}}]" data-tests-id="value" type="text" style="width:97%; height: 100%;border: none; padding:0 5px;"> </th> <th style="height: 30px; display: flex; align-items: baseline;"> - <button mat-icon-button [ngStyle]="hoveredIndex === index ? {'opacity':'1'} : {'opacity':'0'}" class="button-remove" (click)="removeMapRow(index)" - *ngIf="action.map.values.length > 1" style="height: 24px; width: 24px; display:flex; box-shadow: none;"> + <button mat-icon-button data-tests-id="btn-remove-row" [ngStyle]="hoveredIndex === index ? {'opacity':'1'} : {'opacity':'0'}" + class="button-remove" (click)="removeMapRow(index)" *ngIf="action.map.values.length > 1" style="height: 24px; width: 24px; display:flex; box-shadow: none;"> <mat-icon class="md-24">delete</mat-icon> </button> </th> @@ -102,8 +197,9 @@ <div style="display:flex; justify-content: space-between;"> <div style="display: flex; align-items: center;"> - <button mat-mini-fab color="primary" (click)="addMapRow()" style="height: 24px; width: 24px; display:flex; box-shadow: none;"> - <mat-icon>add</mat-icon> + <button mat-mini-fab color="primary" (click)="addMapRow()" data-tests-id="btn-add-row" style="height: 16px; width: 16px; display:flex; box-shadow: none;"> + <span style="padding-left: 2px; display: flex; justify-content: center; align-items: center" [innerHTML]="'plus' | feather:12"></span> + <!-- <mat-icon>add</mat-icon> --> </button> <span style="color: #009FDB; display: flex; justify-content: center; padding-left: 6px">Add Row</span> </div> diff --git a/public/src/app/rule-engine/action/action.component.scss b/public/src/app/rule-engine/action/action.component.scss index f903db4..fc36380 100644 --- a/public/src/app/rule-engine/action/action.component.scss +++ b/public/src/app/rule-engine/action/action.component.scss @@ -4,7 +4,7 @@ width: 100%; height: 100%; justify-content: space-between; - margin: 10px 0; + margin-top: 10px; .black { color: black; } @@ -25,9 +25,12 @@ justify-content: center; min-width: 142px; } + .center-content-item { + width: 100%; + } } .map-container { - padding-left: 115px; + padding-left: 172px; .default { display: flex; width: 100%; @@ -82,7 +85,7 @@ display: flex; flex-direction: column; padding: 0 10px; - .from-conatiner { + .from-container { display: flex; flex-direction: column; align-items: flex-start; @@ -114,3 +117,17 @@ color: #009fdb; } } + +.action-container { + display: flex; + flex-direction: column; + align-items: flex-end; +} +.action-item { + width: 100%; + margin-top: 0.5em; +} +.label .action-item-label { + padding: 0 5px; + width: 110px; +} diff --git a/public/src/app/rule-engine/action/action.component.ts b/public/src/app/rule-engine/action/action.component.ts index 9c7023f..1a62e1a 100644 --- a/public/src/app/rule-engine/action/action.component.ts +++ b/public/src/app/rule-engine/action/action.component.ts @@ -27,9 +27,12 @@ export class ActionComponent implements OnInit { if (this.action.from !== '') { console.log('Action %o', this.action); this.fromInstance.updateMode(this.action.from); + } + if (this.action.target !== '') { this.targetInstance.updateMode(this.action); } } + updateFrom(data) { this.action.from = data; } diff --git a/public/src/app/rule-engine/api/rule-engine-api.service.spec.ts b/public/src/app/rule-engine/api/rule-engine-api.service.spec.ts deleted file mode 100644 index e15535b..0000000 --- a/public/src/app/rule-engine/api/rule-engine-api.service.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { TestBed, inject } from '@angular/core/testing'; -import { HttpModule } from '@angular/http'; -import { RuleEngineApiService } from './rule-engine-api.service'; - -describe('RuleEngineApiService', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpModule], - providers: [RuleEngineApiService] - }); - }); - - it( - 'should be created', - inject([RuleEngineApiService], (service: RuleEngineApiService) => { - expect(service).toBeTruthy(); - }) - ); -}); diff --git a/public/src/app/rule-engine/api/rule-engine-api.service.ts b/public/src/app/rule-engine/api/rule-engine-api.service.ts index 0d7ab5e..7bf5e18 100644 --- a/public/src/app/rule-engine/api/rule-engine-api.service.ts +++ b/public/src/app/rule-engine/api/rule-engine-api.service.ts @@ -1,17 +1,17 @@ -import { Injectable, EventEmitter } from '@angular/core'; +import { Injectable } from '@angular/core'; import { - Http, - Response, Headers, + Http, RequestOptions, + Response, URLSearchParams } from '@angular/http'; -import { Observable, Subject } from 'rxjs/Rx'; +import 'rxjs/add/operator/catch'; // Import RxJs required methods import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/catch'; -import { environment } from '../../../environments/environment'; +import { Observable, Subject } from 'rxjs/Rx'; import { v4 as uuid } from 'uuid'; +import { environment } from '../../../environments/environment'; @Injectable() export class RuleEngineApiService { @@ -25,6 +25,7 @@ export class RuleEngineApiService { flowType: string; editorData: Subject<any> = new Subject(); updateVersionLock: Subject<any> = new Subject(); + tabIndex: Subject<any> = new Subject(); constructor(private http: Http) { this.baseUrl = `${environment.apiBaseUrl}/rule-editor`; @@ -108,16 +109,35 @@ export class RuleEngineApiService { }); } - translate() { - const url = `${this.baseUrl}/rule/translate/${this.vfcmtUuid}/${ - this.dcaeCompName - }/${this.nid}/${this.configParam}`; + translate(nofityId) { + const url = `${this.baseUrl}/rule/translate`; + const params = { + vfcmtUuid: this.vfcmtUuid, + dcaeCompLabel: this.dcaeCompName, + nid: this.nid, + configParam: this.configParam, + flowType: this.flowType, + notifyId: nofityId + }; + this.options.headers.set('X-ECOMP-RequestID', uuid()); + // const params = new URLSearchParams(); params.append('flowType', + // this.flowType); const options = { ...this.options, params: params }; + return this.http + .post(url, params, this.options) + .map(response => response.json()) + .catch((error: any) => { + return Observable.throw(error.json().requestError || 'Server error'); + }); + } + + generateMappingRulesFileName(dcaeCompLabel, nid, vfcmtUuid) { + const url = `${ + this.baseUrl + }/getExistingRuleTargets/${vfcmtUuid}/${dcaeCompLabel}/${nid}`; this.options.headers.set('X-ECOMP-RequestID', uuid()); const params = new URLSearchParams(); - params.append('flowType', this.flowType); - const options = { ...this.options, params: params }; return this.http - .get(url, options) + .get(url, this.options) .map(response => response.json()) .catch((error: any) => { return Observable.throw(error.json().requestError || 'Server error'); @@ -131,4 +151,8 @@ export class RuleEngineApiService { callUpdateVersionLock() { this.updateVersionLock.next(); } + + callUpdateTabIndex(index) { + this.tabIndex.next(index); + } } diff --git a/public/src/app/rule-engine/condition/condition.component.html b/public/src/app/rule-engine/condition/condition.component.html index a441f55..0ff244b 100644 --- a/public/src/app/rule-engine/condition/condition.component.html +++ b/public/src/app/rule-engine/condition/condition.component.html @@ -18,7 +18,7 @@ <div style="display: flex; margin-left: auto;"> <div style="display: flex; align-items: center; padding: 0 25px;"> - <button mat-mini-fab color="primary" (click)="addConditional(tree, node)" style="height: 24px; width: 24px; display:flex; box-shadow: none;"> + <button mat-mini-fab color="primary" data-tests-id="addCondition" (click)="addConditional(tree, node)" style="height: 24px; width: 24px; display:flex; box-shadow: none;"> <mat-icon class="material-icons md-18">add</mat-icon> </button> <span class="btn-label">Add Condition @@ -36,7 +36,7 @@ </div> <div style="display: flex; align-items: center; padding: 0 5px; background: #FFFFFF;"> - <button mat-icon-button (click)="removeConditional(tree, node)" class="button-remove"> + <button data-tests-id="removeConditionNode" mat-icon-button (click)="removeConditional(tree, node)" class="button-remove"> <mat-icon class="md-24">delete</mat-icon> </button> </div> @@ -77,7 +77,7 @@ </div> <!-- remove button --> <div class="show-delete"> - <button mat-icon-button (click)="removeConditional(tree, node)" class="button-remove"> + <button mat-icon-button data-tests-id="RemoveCondition" (click)="removeConditional(tree, node)" class="button-remove"> <mat-icon class="md-24">delete</mat-icon> </button> </div> diff --git a/public/src/app/rule-engine/condition/condition.component.spec.ts b/public/src/app/rule-engine/condition/condition.component.spec.ts deleted file mode 100644 index bb0d38a..0000000 --- a/public/src/app/rule-engine/condition/condition.component.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { DebugElement } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { HttpModule } from '@angular/http'; -import { - MatDialogModule, - MatButtonModule, - MatIconModule, - MatDialogRef, - MAT_DIALOG_DATA -} from '@angular/material'; - -import { ConditionComponent } from './condition.component'; - -describe('Condition Component', () => { - let component: ConditionComponent; - let fixture: ComponentFixture<ConditionComponent>; - let de: DebugElement; - let el: HTMLElement; - - beforeEach( - async(() => { - TestBed.configureTestingModule({ - imports: [ - FormsModule, - HttpModule, - MatDialogModule, - MatButtonModule, - MatIconModule - ], - providers: [], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - declarations: [ConditionComponent] - }).compileComponents(); - }) - ); - - beforeEach(() => { - // create component and test fixture - fixture = TestBed.createComponent(ConditionComponent); - // get test component from the fixture - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/public/src/app/rule-engine/confirm-popup/confirm-popup.component.html b/public/src/app/rule-engine/confirm-popup/confirm-popup.component.html index 49c800a..837e0f8 100644 --- a/public/src/app/rule-engine/confirm-popup/confirm-popup.component.html +++ b/public/src/app/rule-engine/confirm-popup/confirm-popup.component.html @@ -1,12 +1,36 @@ -<div class="container" data-tests-id="delete-popup"> +<div class="container-popup" data-tests-id="delete-popup"> <div class="header"> - Delete + <div style="display: flex; width:100%;"> + <span style="color: #CF2A2A; + padding-right: 15px; + height: 100%; + display: flex; + justify-content: center; + align-items: center;" [innerHTML]="'x-circle' | feather:28"></span> + <span style="font-family: 'Open Sans', sans-serif; + font-size: 24px; width: 100%;"> + Delete + </span> + <span style=" + height: 100%; + display: flex; + color:rgb(90, 90, 90); + justify-content: center; + align-items: center;" [innerHTML]="'x' | feather:20" (click)="close(false)"></span> + </div> </div> - <div class="content"> + <div class="content" style="padding: 0 0 20px 50px; font-family: 'Open Sans', sans-serif; font-size: 14px;"> Are you sure you want to delete? </div> <div class="buttons"> - <button mat-raised-button (click)="close(true)" data-tests-id="btnDelete" style="margin-right: 1rem;" color="primary">Delete</button> - <button mat-raised-button (click)="close(false)" data-tests-id="btnCancel" style="border: 1px solid #009FDB; color: #009FDB; background: #ffffff;">Cancel</button> + + <button mat-raised-button color="primary" style="background-color: #CF2A2A; margin-right: 10px; font-size: 14px; font-family: 'Open Sans', sans-serif; height: 36px; color:white;" + (click)="close(true)" data-tests-id="btnDelete"> + DELETE + </button> + <button mat-raised-button class="btn-secondry" style="border-color: #CF2A2A !important; color:#CF2A2A !important; font-size: 14px; font-family: 'Open Sans', sans-serif;text-align: center; height: 36px;" + (click)="close(false)" data-tests-id="btnCancel"> + CANCEL + </button> </div> </div> diff --git a/public/src/app/rule-engine/confirm-popup/confirm-popup.component.scss b/public/src/app/rule-engine/confirm-popup/confirm-popup.component.scss index 2a826ff..4e3539d 100644 --- a/public/src/app/rule-engine/confirm-popup/confirm-popup.component.scss +++ b/public/src/app/rule-engine/confirm-popup/confirm-popup.component.scss @@ -1,10 +1,19 @@ -.container { +.my-confrim-dialog .mat-dialog-container { + height: 180px; +} + +.container-popup { display: flex; justify-content: space-between; + flex-direction: column; margin: 0 !important; - border-top: solid 6px #ffb81c; + border-top: solid 6px #cf2a2a; .header { border-bottom: none; + padding-top: 15px; + padding-left: 20px; + padding-right: 12px; + padding-bottom: 0; } .content { margin: 1rem; diff --git a/public/src/app/rule-engine/confirm-popup/confirm-popup.component.ts b/public/src/app/rule-engine/confirm-popup/confirm-popup.component.ts index 23b6cee..d65cc5b 100644 --- a/public/src/app/rule-engine/confirm-popup/confirm-popup.component.ts +++ b/public/src/app/rule-engine/confirm-popup/confirm-popup.component.ts @@ -1,10 +1,11 @@ -import { Component, Inject } from '@angular/core'; +import { Component, Inject, ViewEncapsulation } from '@angular/core'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; @Component({ selector: 'app-confirm-popup', templateUrl: './confirm-popup.component.html', - styleUrls: ['./confirm-popup.component.scss'] + styleUrls: ['./confirm-popup.component.scss'], + encapsulation: ViewEncapsulation.None }) export class ConfirmPopupComponent { constructor( diff --git a/public/src/app/rule-engine/from/from.component.html b/public/src/app/rule-engine/from/from.component.html index 7af653d..df2c110 100644 --- a/public/src/app/rule-engine/from/from.component.html +++ b/public/src/app/rule-engine/from/from.component.html @@ -1,6 +1,6 @@ <form #fromFrm="ngForm" novalidate> <!-- Copy template --> - <div class="from" *ngIf="actionType === 'copy'" data-tests-id="fromComponent"> + <div class="from" *ngIf="actionType === 'copy' || actionType === 'replace text' || actionType === 'log text'" data-tests-id="fromComponent"> <div class="from-conatiner"> <div style="display: flex; align-items: center; width: 100%;" class="label"> <span class="label" style="padding: 0 5px; width: 50px;">From</span> @@ -38,6 +38,39 @@ </div> </div> + <!-- clear template --> + <div class="from" *ngIf="actionType === 'clear'" ngModelGroup="clear" #clearFrom="ngModelGroup"> + <div *ngFor="let input of from.values; let index = index;" data-tests-id="clearInputArrayFrom" (mouseleave)="hoveredIndex=-1" + (mouseover)="hoveredIndex=index" class="from-conatiner" style="margin-bottom:1rem; display: flex; flex-direction: column; align-items: flex-start;" + data-tests-id="fromComponent"> + <div style="display: flex; align-items: center; width: 100%;"> + <div style="display: flex; align-items: center; width: 100%;" class="label"> + <span class="label" style="padding: 0 5px; width: 50px;">From</span> + <input class="input-text" (ngModelChange)="modelChange(from)" [(ngModel)]="input.value" type="text" data-tests-id="valueInput" + ngModel required name="clear[{{index}}]"> + </div> + + <button mat-icon-button class="button-remove" [ngStyle]="hoveredIndex === index ? {'opacity':'1'} : {'opacity':'0'}" (click)="removeFromInput(index)" + *ngIf="from.values.length > 1" style="box-shadow: none; height: 24px; width: 24px; display:flex" data-tests-id="btnDelete"> + <mat-icon class="md-24">delete</mat-icon> + </button> + </div> + + </div> + <div style="display:flex; justify-content: space-between;"> + <div style="display: flex; align-items: center;"> + <button mat-mini-fab color="primary" (click)="addFromInput()" style="box-shadow: none; height: 16px; width: 16px; display:flex" + data-tests-id="btnAddInput"> + <span style="padding-left: 2px; display: flex; justify-content: center; align-items: center" [innerHTML]="'plus' | feather:12"></span> +<!-- + <mat-icon>add</mat-icon> --> + </button> + <span style="color: #009FDB; display: flex; justify-content: center; padding-left: 6px">Add input</span> + </div> + </div> + </div> + + <!-- Concat template --> <div class="from" *ngIf="actionType === 'concat'" ngModelGroup="concat" #concatFrom="ngModelGroup"> <div *ngFor="let input of from.values; let index = index;" data-tests-id="concatInputArrayFrom" (mouseleave)="hoveredIndex=-1" @@ -59,11 +92,12 @@ </div> <div style="display:flex; justify-content: space-between;"> <div style="display: flex; align-items: center;"> - <button mat-mini-fab color="primary" (click)="addFromInput()" style="box-shadow: none; height: 24px; width: 24px; display:flex" + <button mat-mini-fab color="primary" (click)="addFromInput()" style="box-shadow: none; height: 16px; width: 16px; display:flex" data-tests-id="btnAddInput"> - <mat-icon>add</mat-icon> + <span style="padding-left: 2px; display: flex; justify-content: center; align-items: center" [innerHTML]="'plus' | feather:12"></span> + <!-- <mat-icon>add</mat-icon> --> </button> - <span style="color: #009FDB; display: flex; justify-content: center; padding-left: 6px">Add input</span> + <span style="color: #009FDB; display: flex; justify-content: center; padding-top: 1px; padding-left: 6px;">Add input</span> </div> </div> </div> diff --git a/public/src/app/rule-engine/from/from.component.ts b/public/src/app/rule-engine/from/from.component.ts index e7c276b..bc1dedb 100644 --- a/public/src/app/rule-engine/from/from.component.ts +++ b/public/src/app/rule-engine/from/from.component.ts @@ -64,6 +64,12 @@ export class FromComponent { hoveredIndex; // public keyUp = new BehaviorSubject<string>(null); + ngOnInit(): void { + if (this.actionType === 'clear') { + this.from.values = [{ value: '' }]; + } + } + showRegex(item) { item.state = item.state === 'closed' ? 'open' : 'closed'; if (item.state === 'closed') { diff --git a/public/src/app/rule-engine/host/exit-mode.enum.ts b/public/src/app/rule-engine/host/exit-mode.enum.ts deleted file mode 100644 index 784ba3b..0000000 --- a/public/src/app/rule-engine/host/exit-mode.enum.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum ExitMode { - Done, - Cancel -} diff --git a/public/src/app/rule-engine/host/host-params.ts b/public/src/app/rule-engine/host/host-params.ts deleted file mode 100644 index f204101..0000000 --- a/public/src/app/rule-engine/host/host-params.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface HostParams { - readonly vfcmtUuid: string; - readonly nodeName: string; - readonly nodeId: string; - readonly fieldName: string; - readonly userId: string; - readonly flowType: string; -} diff --git a/public/src/app/rule-engine/host/host.service.spec.ts b/public/src/app/rule-engine/host/host.service.spec.ts deleted file mode 100644 index 048be80..0000000 --- a/public/src/app/rule-engine/host/host.service.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { TestBed, inject } from '@angular/core/testing'; - -import { HostService } from './host.service'; - -describe('HostService', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [HostService] - }); - }); - - it( - 'should be created', - inject([HostService], (service: HostService) => { - expect(service).toBeTruthy(); - }) - ); -}); diff --git a/public/src/app/rule-engine/host/host.service.ts b/public/src/app/rule-engine/host/host.service.ts deleted file mode 100644 index 7918d30..0000000 --- a/public/src/app/rule-engine/host/host.service.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HostParams } from './host-params'; -import { ExitMode } from './exit-mode.enum'; - -@Injectable() -export class HostService { - /* Public Members */ - - public static getParams(): HostParams { - return this.getQueryParamsObj(window.location.search) as HostParams; - } - - public static enterModifyRule(): void { - this.postMessage('modifyRule', null); - } - - public static exitModifyRule(): void { - this.postMessage('ruleList', null); - } - - public static disableLoader(): void { - this.postMessage('disable-loader', null); - } - - public static exit(mode: ExitMode, data: string): void { - if (mode === ExitMode.Cancel) { - this.postMessage('exit', null); - } else if (mode === ExitMode.Done) { - this.postMessage('exit', data); - } - } - - /* Private Methods */ - - private static postMessage(eventName: string, data: string): void { - window.parent.postMessage( - { - type: eventName, - data: data - }, - '*' - ); - } - - private static getQueryParamsObj(query: string): object { - return query - .substring(1) // removes '?' that always appears as prefix to the query-string - .split('&') // splits query-string to "key=value" strings - .map(p => p.split('=')) // splits each "key=value" string to [key,value] array - .reduce((res, p) => { - // converts to a dictionary (object) of params - res[p[0]] = p[1]; - return res; - }, {}); - } -} diff --git a/public/src/app/rule-engine/rule-list/rule-list.component.html b/public/src/app/rule-engine/rule-list/rule-list.component.html index c68c706..4ce6efb 100644 --- a/public/src/app/rule-engine/rule-list/rule-list.component.html +++ b/public/src/app/rule-engine/rule-list/rule-list.component.html @@ -1,8 +1,8 @@ <div class="container"> <div class="header"> - <span style="font-size: 18px;">Rule Engine</span> + <span style="font-size: 18px; margin-left:20px;">Rule Engine</span> <div style="display:flex"> - <button mat-raised-button (click)="translateRules()" color="primary" [disabled]="store.ruleList.length === 0" style="margin-left: 20px;" + <button mat-raised-button (click)="translateRules()" color="primary" [disabled]="store.ruleList.length === 0" style="margin-right: 10px; width: 113px;height: 36px;" data-tests-id="btnTranslate"> Translate </button> @@ -20,6 +20,35 @@ <app-version-type-select #versionEventType [versions]="versions" [metaData]="metaData" (nodesUpdated)="handleUpdateNode($event)" (refrashRuleList)="handlePropertyChange()"></app-version-type-select> + <!-- <div class="container-phase-notify"> + <div> + <span class="field-label required" style="margin-right: 10px;"> + phase + </span> + <select name="phase" [(ngModel)]="phase" data-tests-id="phase" style="height: 27px; padding: 0.3rem; margin-right: 18px;" + class="field-select"> + <option [ngValue]="null" disabled>Select phase</option> + </select> + </div> + + <div class="default" style="display: flex; align-items: center"> + <div class="pretty p-svg"> + <input type="checkbox" name="notifyCheckbox" data-tests-id="notifyCheckbox" /> + <div class="state"> + <svg class="svg svg-icon" viewBox="0 0 20 20"> + <path d="M7.629,14.566c0.125,0.125,0.291,0.188,0.456,0.188c0.164,0,0.329-0.062,0.456-0.188l8.219-8.221c0.252-0.252,0.252-0.659,0-0.911c-0.252-0.252-0.659-0.252-0.911,0l-7.764,7.763L4.152,9.267c-0.252-0.251-0.66-0.251-0.911,0c-0.252,0.252-0.252,0.66,0,0.911L7.629,14.566z" + style="stroke: #009fdb; fill:#009fdb;"></path> + </svg> + <label>notify OID</label> + </div> + </div> + <div class="input-wrapper"> + <input type="text" ngModel required name="notify-oid" data-tests-id="notify-oid" class="input"> + </div> + </div> + + </div> --> + <div *ngIf="targetSource && store.ruleList.length === 0" style="margin: 30px 0; display: flex; align-items: center; justify-content: center; flex-direction: column;"> <div style="margin: 3em 0 2em 0;"> @@ -40,9 +69,6 @@ </div> <div *ngIf="store.ruleList.length > 0"> - <div style="padding: 10px 0;"> - Rules - </div> <div style="display: flex; align-items: center;"> <button mat-mini-fab color="primary" id="addMoreRule" data-tests-id="addMoreRule" style="height: 24px; width: 24px; display:flex" (click)="openAction()"> diff --git a/public/src/app/rule-engine/rule-list/rule-list.component.scss b/public/src/app/rule-engine/rule-list/rule-list.component.scss index c4aee05..6446fbd 100644 --- a/public/src/app/rule-engine/rule-list/rule-list.component.scss +++ b/public/src/app/rule-engine/rule-list/rule-list.component.scss @@ -4,30 +4,30 @@ height: 100%; display: flex; flex-direction: column; - + margin: 0; + padding: 0; .header { position: relative; display: flex; justify-content: space-between; align-items: center; color: #191919; - border-bottom: 2px solid #d2d2d2; - padding-bottom: 0.5rem; - margin: 1rem; + border-bottom: 1px solid #d2d2d2; + padding-bottom: 5px; + margin: 8px 0; } - .item { border: 1px solid #d2d2d2; padding: 0 10px; height: 40px; } - .mat-fab, .mat-mini-fab, .mat-raised-button { box-shadow: none; } } + .my-full-screen-dialog .mat-dialog-container { max-width: none; width: 100vw; @@ -46,7 +46,6 @@ display: flex !important; justify-content: center !important; color: #d2d2d2 !important; - &:hover { color: #009fdb !important; } @@ -68,6 +67,7 @@ .mat-mini-fab .mat-button-wrapper { padding: 0 !important; } + .mat-icon { // width: 18px; // height: 18px; @@ -75,35 +75,45 @@ justify-content: center !important; align-items: center !important; } + /* Rules for sizing the icon. */ + .material-icons.md-18 { font-size: 18px; } + .material-icons.md-24 { font-size: 24px; } + .material-icons.md-30 { font-size: 30px; } + .material-icons.md-36 { font-size: 36px; } + .material-icons.md-48 { font-size: 48px; } /* Rules for using icons as black on a light background. */ + .material-icons.md-dark { color: rgba(0, 0, 0, 0.54); } + .material-icons.md-dark.md-inactive { color: rgba(0, 0, 0, 0.26); } /* Rules for using icons as white on a dark background. */ + .material-icons.md-light { color: rgba(255, 255, 255, 1); } + .material-icons.md-light.md-inactive { color: rgba(255, 255, 255, 0.3); } diff --git a/public/src/app/rule-engine/rule-list/rule-list.component.ts b/public/src/app/rule-engine/rule-list/rule-list.component.ts index 45cfbd0..2857ea2 100644 --- a/public/src/app/rule-engine/rule-list/rule-list.component.ts +++ b/public/src/app/rule-engine/rule-list/rule-list.component.ts @@ -1,12 +1,11 @@ -import { Component, ViewEncapsulation, ViewChild } from '@angular/core'; +import { Component, ViewChild, ViewEncapsulation } from '@angular/core'; import { MatDialog } from '@angular/material'; -import { ActionListComponent } from '../action-list/action-list.component'; -import { RuleEngineApiService } from '../api/rule-engine-api.service'; -import { ConfirmPopupComponent } from '../confirm-popup/confirm-popup.component'; -import { Store } from '../../store/store'; import { isEmpty } from 'lodash'; import { ToastrService } from 'ngx-toastr'; import { timer } from 'rxjs/observable/timer'; +import { Store } from '../../store/store'; +import { RuleEngineApiService } from '../api/rule-engine-api.service'; +import { ConfirmPopupComponent } from '../confirm-popup/confirm-popup.component'; const primaryColor = '#009fdb'; @@ -58,7 +57,11 @@ export class RuleListComponent { ); this.store.updateRuleList(Object.values(response.rules)); this.targetSource = response.schema; + this.store.notifyIdValue = response.notifyId; + this.versionType.notifyIdCheckbox = + response.notifyId !== '' ? true : false; } else { + this.versionType.notifyIdCheckbox = false; this.store.resetRuleList(); this.versionType.updateVersionTypeFlag(false); this.targetSource = null; @@ -83,20 +86,29 @@ export class RuleListComponent { private toastr: ToastrService, public store: Store ) { - this.store.loader = true; - this.params = { - vfcmtUuid: this.store.mcUuid, - nodeName: this.store.tabParmasForRule[0].name, - nodeId: this.store.tabParmasForRule[0].nid, - fieldName: this.store.configurationForm[0].name, - userId: 'ym903w', // this.store.sdcParmas.userId - flowType: this.store.cdump.flowType - }; - console.log('params: %o', this.params); - this.store.loader = true; - // set api params by iframe url query - this._ruleApi.setParams(this.params); - this.getListOfRules(); + this.store.loader = false; + this._ruleApi.tabIndex.subscribe(index => { + console.log('rule index in rule-list component:', index); + const tabName = this.store.cdump.nodes[index].name; + console.log('tab name:', tabName); + + if (tabName.toLowerCase().includes('map')) { + this.params = { + vfcmtUuid: this.store.mcUuid, + nodeName: this.store.tabParmasForRule[0].name, + nodeId: this.store.tabParmasForRule[0].nid, + fieldName: this.store.tabsProperties[index][0].name, + userId: this.store.sdcParmas.userId, + flowType: this.store.cdump.flowType + }; + console.log('params: %o', this.params); + this.store.loader = true; + // set api params by iframe url query + this._ruleApi.setParams(this.params); + store.ruleListExistParams = this.params; + this.getListOfRules(); + } + }); } handlePropertyChange() { @@ -108,7 +120,8 @@ export class RuleListComponent { translateRules() { this.store.loader = true; // send translate JSON - this._ruleApi.translate().subscribe( + const nofityId = this.store.notifyIdValue; + this._ruleApi.translate(nofityId).subscribe( data => { this.store.loader = false; console.log(JSON.stringify(data)); @@ -116,7 +129,7 @@ export class RuleListComponent { this.store.configurationForm.forEach(property => { console.log('mappingTarget ', this.versionType.mappingTarget); if (property.name === this.versionType.mappingTarget) { - property.assignment.value = JSON.stringify(data); + property.value = JSON.stringify(data); domElementName = property.name; console.log(property.name); } diff --git a/public/src/app/rule-engine/target/target.component.html b/public/src/app/rule-engine/target/target.component.html index 7a321ef..d643ad8 100644 --- a/public/src/app/rule-engine/target/target.component.html +++ b/public/src/app/rule-engine/target/target.component.html @@ -7,7 +7,7 @@ <img src="{{imgBase}}/target.svg" alt="target"> </span> </div> - <div class="bottom-select" *ngIf="showOption" [@toggleDropdown]> + <div class="bottom-select" *ngIf="showOption"> <div class="filter-container" style="display: flex; border-bottom: 1px solid #F2F2F2;margin-bottom: 1rem; width:100%;"> <input id="filter" #filter class="filter" (keyup)="tree.treeModel.filterNodes(filter.value)" placeholder="Search..." /> <button mat-raised-button style="min-width: 18px; box-shadow: none; display: flex; justify-content: center;" (click)="tree.treeModel.clearFilter(); filter.value = ''"> diff --git a/public/src/app/rule-engine/target/target.component.spec.ts b/public/src/app/rule-engine/target/target.component.spec.ts index 6ddd8cd..e9a69c8 100644 --- a/public/src/app/rule-engine/target/target.component.spec.ts +++ b/public/src/app/rule-engine/target/target.component.spec.ts @@ -1,10 +1,9 @@ -import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { DebugElement } from '@angular/core'; +import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core'; +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { MatButtonModule, MatIconModule } from '@angular/material'; +import { By } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; // component import { TargetComponent } from './target.component'; @@ -46,12 +45,28 @@ describe('TargetComponent', () => { const openTargetElement = fixture.debugElement .query(By.css('span[data-tests-id=openTargetTree]')) .nativeElement.click(); - fixture.detectChanges(); - const treeContainer = fixture.debugElement.query( By.css('.filter-container') ); expect(treeContainer).not.toBeNull(); }); + + it('should toggle target tree when clicking 2 times on button', () => { + fixture.debugElement + .query(By.css('span[data-tests-id=openTargetTree]')) + .nativeElement.click(); + fixture.detectChanges(); + fixture.debugElement + .query(By.css('span[data-tests-id=openTargetTree]')) + .nativeElement.click(); + fixture.detectChanges(); + const treeContainer = fixture.debugElement.query( + By.css('.filter-container') + ); + expect(treeContainer).toBeNull(); + }); + + // it('check when input change', () => { tree.setData({nodes: _nodes, options: + // null, events: null}); component.filterFn('liav', tree); }); }); diff --git a/public/src/app/rule-engine/target/target.component.ts b/public/src/app/rule-engine/target/target.component.ts index f17cdef..c9aa75c 100644 --- a/public/src/app/rule-engine/target/target.component.ts +++ b/public/src/app/rule-engine/target/target.component.ts @@ -7,13 +7,8 @@ import { EventEmitter } from '@angular/core'; import { TreeModel, TreeComponent, ITreeOptions } from 'angular-tree-component'; -import { - trigger, - state, - animate, - transition, - style -} from '@angular/animations'; +// import {trigger, state, animate, transition, style} from +// '@angular/animations'; import { fuzzysearch, getBranchRequierds, validation } from './target.util'; import { environment } from '../../../environments/environment'; import { NgForm } from '@angular/forms'; @@ -22,24 +17,15 @@ import { NgForm } from '@angular/forms'; selector: 'app-target', templateUrl: './target.component.html', styleUrls: ['./target.component.scss'], - encapsulation: ViewEncapsulation.None, - animations: [ - trigger('toggleDropdown', [ - transition('void => *', [ - style({ opacity: 0, offset: 0, height: 0 }), - animate('300ms cubic-bezier(0.17, 0.04, 0.03, 0.94)') - ]), - transition('* => void', [ - style({ opacity: 1, offset: 1, height: 'auto' }), - animate('100ms cubic-bezier(0.17, 0.04, 0.03, 0.94)') - ]) - ]) - ] + encapsulation: ViewEncapsulation.None }) export class TargetComponent { imgBase = environment.imagePath; showOption = false; - selectedNode = { name: '', id: '' }; + selectedNode = { + name: '', + id: '' + }; @Input() nodes; @Output() onTargetChange = new EventEmitter(); @ViewChild(TreeComponent) private tree: TreeComponent; diff --git a/public/src/app/rule-engine/target/target.validation.spec.ts b/public/src/app/rule-engine/target/target.validation.spec.ts index 71dc083..e66235f 100644 --- a/public/src/app/rule-engine/target/target.validation.spec.ts +++ b/public/src/app/rule-engine/target/target.validation.spec.ts @@ -1,8 +1,7 @@ -import { TestBed, async } from '@angular/core/testing'; -import { TreeModel, TreeComponent, ITreeOptions } from 'angular-tree-component'; -import { validation, getBranchRequierds } from './target.util'; +import { TreeModel } from 'angular-tree-component'; +import { fuzzysearch, getBranchRequierds, validation } from './target.util'; -const _nodes = [ +export const _nodes = [ { id: 1, name: 'North America', @@ -13,46 +12,68 @@ const _nodes = [ name: 'United States', requiredChildren: ['New York', 'Florida'], children: [ - { id: 111, name: 'New York' }, - { id: 112, name: 'California' }, - { id: 113, name: 'Florida' } + { + id: 111, + name: 'New York' + }, + { + id: 112, + name: 'California' + }, + { + id: 113, + name: 'Florida' + } ] }, - { id: 12, name: 'Canada' } + { + id: 12, + name: 'Canada' + } ] }, { name: 'South America', - children: [{ name: 'Argentina', children: [] }, { name: 'Brazil' }] + children: [ + { + name: 'Argentina', + children: [] + }, + { + name: 'Brazil' + } + ] }, { name: 'Europe', children: [ - { name: 'England' }, - { name: 'Germany' }, - { name: 'France' }, - { name: 'Italy' }, - { name: 'Spain' } + { + name: 'England' + }, + { + name: 'Germany' + }, + { + name: 'France' + }, + { + name: 'Italy' + }, + { + name: 'Spain' + } ] } ]; -const tree = new TreeModel(); +export const tree = new TreeModel(); describe('treeTest', () => { beforeAll(() => { - tree.setData({ - nodes: _nodes, - options: null, - events: null - }); + tree.setData({ nodes: _nodes, options: null, events: null }); }); - it('should return node branch requireds', () => { - // console.log('root', tree.getFirstRoot().data.name); - // console.log(tree.getNodeBy((node) => node.data.name === 'California').data.uuid); - // console.log(tree.getNodeBy((node) => node.data.name === 'California').id); - // console.log(tree.getNodeById(1)); + it('should return node branch requireds toBeGreaterThan 1', () => { const selectedNode = tree.getNodeBy( node => node.data.name === 'California' ); @@ -60,6 +81,14 @@ describe('treeTest', () => { const expected = [['New York', 'Florida'], ['United States']]; expect(result.length).toBeGreaterThan(1); + }); + + it('should return node branch requireds', () => { + const selectedNode = tree.getNodeBy( + node => node.data.name === 'California' + ); + const result = getBranchRequierds(selectedNode, []); + const expected = [['New York', 'Florida'], ['United States']]; expect(result).toEqual(expected); }); @@ -67,9 +96,14 @@ describe('treeTest', () => { const userSelect = ['Florida', 'New York', 'United States']; const selectedNode = tree.getNodeBy(node => node.data.name === 'New York'); const result = validation(selectedNode, userSelect); + expect(result).toEqual([]); + }); + it('should return empty array - success state lenght zero', () => { + const userSelect = ['Florida', 'New York', 'United States']; + const selectedNode = tree.getNodeBy(node => node.data.name === 'New York'); + const result = validation(selectedNode, userSelect); expect(result.length).toEqual(0); - expect(result).toEqual([]); }); it('should return validation array - missing required filed', () => { @@ -80,4 +114,29 @@ describe('treeTest', () => { expect(result).toEqual(expected); }); + + it('fuzzysearch find match one char', () => { + const search = fuzzysearch('1', '1'); + expect(search).toBe(true); + }); + + it('fuzzysearch find match string', () => { + const search = fuzzysearch('liav', 'liavEzar'); + expect(search).toBe(true); + }); + + it('fuzzysearch not find match', () => { + const search = fuzzysearch('1', '2'); + expect(search).toBe(false); + }); + + it('fuzzysearch not find match', () => { + const search = fuzzysearch('liavEzar', 'liav'); + expect(search).toBe(false); + }); + + it('fuzzysearch not find match', () => { + const search = fuzzysearch('var', 'r2f44'); + expect(search).toBe(false); + }); }); diff --git a/public/src/app/rule-engine/version-type-select/version-type-select.component.html b/public/src/app/rule-engine/version-type-select/version-type-select.component.html index 79b9eae..74c55a8 100644 --- a/public/src/app/rule-engine/version-type-select/version-type-select.component.html +++ b/public/src/app/rule-engine/version-type-select/version-type-select.component.html @@ -1,34 +1,64 @@ <div class="selected-event"> - <div style="flex:1; display: flex; align-items: center;"> + <div style="flex:1; display: flex; align-items: flex-end;"> - <span class="field-label required" style="margin-right: 10px;">Mapping Target</span> - <select name="mappingTarget" [(ngModel)]="mappingTarget" (ngModelChange)="onChangeMapping($event)" data-tests-id="mappingDdl" - style="height: 27px; padding: 0.3rem; margin-right: 18px;" class="field-select"> - <option [ngValue]="null" disabled>Select Mapping</option> - <option *ngFor="let target of advancedSetting" [value]="target.name" data-tests-id="templateOptions">{{target.name}}</option> - </select> + <div style="display:flex; flex-direction:column; margin-right: 25px;"> + <span class="field-label required space-down" style="margin-right: 10px;">Mapping Target</span> + <select name="mappingTarget" [(ngModel)]="mappingTarget" (ngModelChange)="onChangeMapping($event)" data-tests-id="mappingDdl" + style="height: 35px; padding: 0.3rem; border: 1px solid #d2d2d2" class="field-select"> + <option [ngValue]="null" disabled>Select Mapping</option> + <optgroup label="Rules Configured"> + <option *ngFor="let target of advancedSetting" [hidden]="!target.isExist" [value]="target.name" data-tests-id="templateOptionsExist">{{target.name}}</option> + </optgroup> + <optgroup label="No Mapping Configuration"> + <option *ngFor="let target of advancedSetting" [hidden]="target.isExist" [value]="target.name" data-tests-id="templateOptionsNotExist">{{target.name}}</option> + </optgroup> + </select> + </div> - <span class="field-label required" style="font-size: 13px; margin-right: 10px; display: flex; - align-items: center;" [ngClass]="{'required' : !readOnly}"> - Version - </span> - <select *ngIf="!readOnly" style="height: 27px; padding: 0.3rem; margin-right: 18px;" [(ngModel)]="selectedVersion" (ngModelChange)="onSelectVersion($event)" - data-tests-id="selectVersion"> - <option [ngValue]="null" disabled>Select Version</option> - <option *ngFor="let version of versions" [value]="version" data-tests-id="option">{{version}}</option> - </select> - <span *ngIf="readOnly" style="height: 27px; padding: 0.3rem; width:100px; margin-right: 18px; border: 1px solid #D2D2D2; display: flex; align-items: center; background: #F2F2F2">{{selectedVersion}}</span> + <div style="display:flex; flex-direction:column; margin-right: 25px;"> + <span class="field-label required space-down" style="font-size: 13px; margin-right: 10px; display: flex; + align-items: center;" [ngClass]="{'required' : !readOnly}"> + Version + </span> + <select *ngIf="!readOnly" style="height: 35px; padding: 0.3rem; border: 1px solid #d2d2d2" [(ngModel)]="selectedVersion" (ngModelChange)="onSelectVersion($event)" + data-tests-id="selectVersion"> + <option [ngValue]="null" disabled>Select Version</option> + <option *ngFor="let version of versions" [value]="version" data-tests-id="option">{{version}}</option> + </select> + <span *ngIf="readOnly" style="height: 35px; padding: 0.3rem; width:100px; border: 1px solid #D2D2D2; display: flex; align-items: center; background: #F2F2F2">{{selectedVersion}}</span> + </div> - <span class="field-label required" style="font-size: 13px; display: flex; align-items: center; width: 100px;" [ngClass]="{'required' : !readOnly}"> - Event Domain - </span> - <select *ngIf="!readOnly" style="height: 27px; padding: 0.3rem;" [(ngModel)]="selectedEvent" (ngModelChange)="onSelectEventType($event)" - data-tests-id="selectEventType"> - <option [ngValue]="null" disabled>Select Type</option> - <option *ngFor="let event of events" [value]="event" data-tests-id="option">{{event | slice:0:event.length-6}}</option> - </select> - <span *ngIf="readOnly" style="height: 27px; padding: 0.3rem; width:200px; border: 1px solid #D2D2D2; display: flex; align-items: center; background: #F2F2F2">{{selectedEvent | slice:0:selectedEvent.length-6}}</span> + <div style="display:flex; flex-direction:column; margin-right: 25px;"> + <span class="field-label required space-down" style="font-size: 13px; display: flex; align-items: center; width: 100px;" + [ngClass]="{'required' : !readOnly}"> + Event Domain + </span> + <select *ngIf="!readOnly" style="height: 35px; padding: 0.3rem; border: 1px solid #d2d2d2" [(ngModel)]="selectedEvent" (ngModelChange)="onSelectEventType($event)" + data-tests-id="selectEventType"> + <option [ngValue]="null" disabled>Select Type</option> + <option *ngFor="let event of events" [value]="event" data-tests-id="option">{{event | slice:0:event.length-6}}</option> + </select> + <span *ngIf="readOnly" style="height: 35px; padding: 0.3rem; width:200px; border: 1px solid #D2D2D2; display: flex; align-items: center; background: #F2F2F2">{{selectedEvent | slice:0:selectedEvent.length-6}}</span> + </div> + + <div class="notifyId" style="display: flex; flex-direction:column; margin-right:25px;"> + <div class="pretty p-svg space-down"> + <input type="checkbox" name="notifyIdCheckbox" data-tests-id="notifyIdCheckbox" [checked]="notifyIdCheckbox" (change)="changeNotifyId()" + /> + <div class="state"> + <!-- svg path --> + <svg class="svg svg-icon" viewBox="0 0 20 20"> + <path d="M7.629,14.566c0.125,0.125,0.291,0.188,0.456,0.188c0.164,0,0.329-0.062,0.456-0.188l8.219-8.221c0.252-0.252,0.252-0.659,0-0.911c-0.252-0.252-0.659-0.252-0.911,0l-7.764,7.763L4.152,9.267c-0.252-0.251-0.66-0.251-0.911,0c-0.252,0.252-0.252,0.66,0,0.911L7.629,14.566z" + style="stroke: #009fdb; fill:#009fdb;"></path> + </svg> + <label style="margin-left: 5px;">Notify OID</label> + </div> + </div> + <div *ngIf="notifyIdCheckbox" class="input-wrapper"> + <input type="text" ngModel required name="defaultInput" data-tests-id="defaultInput" [(ngModel)]="store.notifyIdValue" class="input"> + </div> + </div> </div> </div> diff --git a/public/src/app/rule-engine/version-type-select/version-type-select.component.scss b/public/src/app/rule-engine/version-type-select/version-type-select.component.scss index 9f7bad3..1be996e 100644 --- a/public/src/app/rule-engine/version-type-select/version-type-select.component.scss +++ b/public/src/app/rule-engine/version-type-select/version-type-select.component.scss @@ -1,7 +1,6 @@ .selected-event { display: flex; - margin: 10px 0; - // align-items: center; + // margin: 10px 0; // align-items: center; flex-direction: column; margin-bottom: 30px; } @@ -23,6 +22,20 @@ outline: none; } +.space-down { + margin-bottom: 5px; +} + +.input-wrapper { + .input { + height: 35px; + border-radius: 2px; + padding: 5px; + width: 100%; + border: 1px solid #d2d2d2; + } +} + .target-field { width: 370px; display: flex; @@ -42,5 +55,6 @@ min-width: 250px; padding: 5px 0 5px 5px; margin: 0; + border: 1px solid #d2d2d2; } } diff --git a/public/src/app/rule-engine/version-type-select/version-type-select.component.ts b/public/src/app/rule-engine/version-type-select/version-type-select.component.ts index b4170a5..ff229cd 100644 --- a/public/src/app/rule-engine/version-type-select/version-type-select.component.ts +++ b/public/src/app/rule-engine/version-type-select/version-type-select.component.ts @@ -1,6 +1,6 @@ -import { Component, Output, EventEmitter, Input } from '@angular/core'; -import { RuleEngineApiService } from '../api/rule-engine-api.service'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Store } from '../../store/store'; +import { RuleEngineApiService } from '../api/rule-engine-api.service'; @Component({ selector: 'app-version-type-select', @@ -19,25 +19,60 @@ export class VersionTypeSelectComponent { @Input() metaData; @Output() nodesUpdated = new EventEmitter(); @Output() refrashRuleList = new EventEmitter(); - advancedSetting; + advancedSetting: Array<any>; + notifyIdCheckbox = false; constructor(private _ruleApi: RuleEngineApiService, public store: Store) { this.selectedVersion = null; this.selectedEvent = null; // set ddl with the first option value. - this.mappingTarget = this.store.configurationForm[0].name; - this.advancedSetting = this.store.configurationForm.filter(item => { - if ( - !( - item.hasOwnProperty('constraints') && - !item.assignment.value.includes('get_input') - ) - ) { - return item; + + this._ruleApi.tabIndex.subscribe(index => { + console.log('rule index:', index); + + const tabName = this.store.cdump.nodes[index].name; + console.log('tab name:', tabName); + + if (tabName.toLowerCase().includes('map')) { + this.mappingTarget = this.store.tabsProperties[index][0].name; + this.advancedSetting = this.store.tabsProperties[index].filter(item => { + if ( + !( + item.hasOwnProperty('constraints') && + !item.value.includes('get_input') + ) + ) { + return item; + } + }); + + this._ruleApi + .generateMappingRulesFileName( + this.store.ruleListExistParams.nodeName, + this.store.ruleListExistParams.nodeId, + this.store.ruleListExistParams.vfcmtUuid + ) + .subscribe(response => { + console.log('generateMappingRulesFileName response: ', response); + this.advancedSetting.forEach(element => { + if (response.includes(element.name)) { + element.isExist = true; + } else { + element.isExist = false; + } + }); + }); } }); } + changeNotifyId() { + if (!this.notifyIdCheckbox) { + this.store.notifyIdValue = ''; + } + return (this.notifyIdCheckbox = !this.notifyIdCheckbox); + } + onChangeMapping(configurationKey) { console.log('changing propertiy key:', configurationKey); this._ruleApi.setFieldName(configurationKey); @@ -78,9 +113,7 @@ export class VersionTypeSelectComponent { .subscribe(tree => { console.log('tree: ', tree); this.loader = false; - this.nodesUpdated.emit({ - nodes: tree - }); + this.nodesUpdated.emit({ nodes: tree }); }); } } diff --git a/public/src/app/rule-frame/rule-frame.component.html b/public/src/app/rule-frame/rule-frame.component.html index 10f3032..e0afa3d 100644 --- a/public/src/app/rule-frame/rule-frame.component.html +++ b/public/src/app/rule-frame/rule-frame.component.html @@ -1,16 +1,16 @@ <div style="position: relative; display: flex; justify-content: flex-end; height: 100%;"> - <div *ngIf="!tabName.includes('map')" style="margin: 1em;"> + <div *ngIf="!tabName.toLowerCase().includes('map')" style="margin: 1em;"> <app-bar-icons [tabName]="tabName"></app-bar-icons> </div> <!-- rule engine --> - <div style="width: 100%;" *ngIf="tabName.includes('map')"> + <div style="width: 100%;" *ngIf="tabName.toLowerCase().includes('map')"> <app-slide-panel [activePane]="store.isLeftVisible ? 'left' : 'right'"> <div leftPane style="height: 100%; overflow: auto;"> <app-rule-list></app-rule-list> </div> - <div rightPane style="height: 100%; overflow: auto;"> + <div rightPane style="height: 100%; overflow: scroll;"> <app-action-list></app-action-list> </div> </app-slide-panel> diff --git a/public/src/app/rule-frame/rule-frame.component.ts b/public/src/app/rule-frame/rule-frame.component.ts index 4d5f999..2729c14 100644 --- a/public/src/app/rule-frame/rule-frame.component.ts +++ b/public/src/app/rule-frame/rule-frame.component.ts @@ -1,6 +1,5 @@ -import { Component, OnDestroy, Input, ViewChild } from '@angular/core'; +import { Component, Input, OnDestroy } from '@angular/core'; import { Store } from '../store/store'; -import { BarIconsComponent } from '../bar-icons/bar-icons.component'; @Component({ selector: 'app-rule-frame', diff --git a/public/src/app/sdc-notify-dialog/sdc-notify-dialog.component.html b/public/src/app/sdc-notify-dialog/sdc-notify-dialog.component.html new file mode 100644 index 0000000..f8d51fe --- /dev/null +++ b/public/src/app/sdc-notify-dialog/sdc-notify-dialog.component.html @@ -0,0 +1,39 @@ +<p-dialog [style]="{'border-top-color':'#ffb81c'}" [closable]="false" [(visible)]="store.displaySDCDialog" modal="modal" styleClass="dcae-notify" + width="500" [responsive]="true" data-tests-id="sdc-dialog"> + <p-header> + <div style="display: flex;"> + <span style="color: #ffb81c; + padding-right: 15px; + height: 100%; + display: flex; + justify-content: center; + align-items: center;" [innerHTML]="'alert-triangle' | feather:28"></span> + <span style="font-family: 'Open Sans', sans-serif; + font-size: 24px; width: 100%;"> + Exit from DCAE + </span> + <span style=" + height: 100%; + display: flex; + justify-content: center; + color:rgb(90, 90, 90); + align-items: center;" [innerHTML]="'x' | feather:20 + " (click)="closeforChange()"></span> + </div> + </p-header> + + <div style="padding: 0 0 20px 43px; font-family: 'Open Sans', sans-serif; + font-size: 14px;"> + Do you want to save? + </div> + + <p-footer> + <button mat-raised-button color="primary" style="background-color: #FFB81C; margin-right: 10px; font-size: 14px; font-family: 'Open Sans', sans-serif; height: 36px;" (click)="closeDialog()" data-tests-id="error-cancel"> + SAVE + </button> + <button mat-raised-button class="btn-secondry" style="border-color: #FFB81C !important; color:#FFB81C !important; font-size: 14px; font-family: 'Open Sans', sans-serif;text-align: center; height: 36px;" (click)="closeforChange()" + data-tests-id="error-cancel"> + DISCARD + </button> + </p-footer> +</p-dialog> diff --git a/public/src/app/sdc-notify-dialog/sdc-notify-dialog.component.scss b/public/src/app/sdc-notify-dialog/sdc-notify-dialog.component.scss new file mode 100644 index 0000000..a775398 --- /dev/null +++ b/public/src/app/sdc-notify-dialog/sdc-notify-dialog.component.scss @@ -0,0 +1,17 @@ +:host /deep/ .dcae-notify { + border-top: solid 6px #ffb81c; +} +:host /deep/ .ui-dialog .ui-dialog-titlebar { + padding-top: 15px; + padding-left: 20px; + padding-right: 12px; + padding-bottom: 0; +} + +:host /deep/ .ui-dialog-footer { + padding: 10px; +} + +:host /deep/ .ui-dialog.ui-widget .ui-dialog-content { + padding-top: 10px; +} diff --git a/public/src/app/sdc-notify-dialog/sdc-notify-dialog.component.ts b/public/src/app/sdc-notify-dialog/sdc-notify-dialog.component.ts new file mode 100644 index 0000000..7572012 --- /dev/null +++ b/public/src/app/sdc-notify-dialog/sdc-notify-dialog.component.ts @@ -0,0 +1,72 @@ +import { Component, ElementRef, ViewChild } from '@angular/core'; +import { Router } from '@angular/router'; +import { RestApiService } from '../api/rest-api.service'; +import { MainComponent } from '../main/main.component'; +import { Store } from '../store/store'; + +@Component({ + selector: 'app-sdc-notify-dialog', + templateUrl: './sdc-notify-dialog.component.html', + styleUrls: ['./sdc-notify-dialog.component.scss'] +}) +export class SdcNotifyDialogComponent { + @ViewChild(MainComponent) mainComponent: ElementRef; + + constructor( + public store: Store, + private router: Router, + private _restApi: RestApiService + ) {} + + closeDialog() { + const currentUrl = this.router.url; + if (currentUrl.includes('main')) { + if (this.store.cdumpIsDirty) { + this.saveCDUMP(); + } else { + this.completeAndClose(); + } + } else { + this.completeAndClose(); + } + } + + saveCDUMP() { + this.store.loader = true; + this._restApi + .saveMonitoringComponent({ + contextType: this.store.sdcParmas.contextType, + serviceUuid: this.store.sdcParmas.uuid, + vfiName: this.store.vfiName, + vfcmtUuid: this.store.mcUuid, + flowType: this.store.flowType, + cdump: this.store.cdump + }) + .subscribe( + success => { + this.store.loader = false; + this.store.mcUuid = success.uuid; + this.store.ifrmaeMessenger.notify('ACTION_COMPLETED'); + }, + error => { + this.store.loader = false; + console.log(error.notes); + this.store.ifrmaeMessenger.notify('ACTION_COMPLETED'); + this.store.ErrorContent = Object.values(error.requestError); + this.store.displayErrorDialog = true; + }, + () => { + this.store.ifrmaeMessenger.notify('ACTION_COMPLETED'); + } + ); + } + + private completeAndClose() { + this.store.ifrmaeMessenger.notify('ACTION_COMPLETED'); + this.store.displaySDCDialog = false; + } + + closeforChange() { + this.completeAndClose(); + } +} diff --git a/public/src/app/sdc/base-pubsub.ts b/public/src/app/sdc/base-pubsub.ts new file mode 100644 index 0000000..f7fcadc --- /dev/null +++ b/public/src/app/sdc/base-pubsub.ts @@ -0,0 +1,124 @@ +declare const window: Window; + +export interface IPubSubEvent { + type: string; + originId: string; + data: any; +} + +export interface ISubscriber { + window: Window; + locationUrl: string; +} + +export class BasePubSub { + subscribers: Map<string, ISubscriber>; + eventsCallbacks: Array<Function>; + clientId: string; + eventsToWait: Map<string, Array<string>>; + + constructor(pluginId: string) { + this.subscribers = new Map<string, ISubscriber>(); + this.eventsCallbacks = []; + this.eventsToWait = new Map<string, Array<string>>(); + this.clientId = pluginId; + this.onMessage = this.onMessage.bind(this); + + window.addEventListener('message', this.onMessage); + } + + public register( + subscriberId: string, + subscriberWindow: Window, + subscriberUrl: string + ) { + const subscriber = { + window: subscriberWindow, + locationUrl: subscriberUrl || subscriberWindow.location.href + }; + + this.subscribers.set(subscriberId, subscriber); + } + + public unregister(subscriberId: string) { + this.subscribers.delete(subscriberId); + } + + public on(callback: Function) { + const functionExists = this.eventsCallbacks.find((func: Function) => { + return callback.toString() === func.toString(); + }); + + if (!functionExists) { + this.eventsCallbacks.push(callback); + } + } + + public off(callback: Function) { + const index = this.eventsCallbacks.indexOf(callback); + this.eventsCallbacks.splice(index, 1); + } + + public notify(eventType: string, eventData?: any) { + const eventObj = { + type: eventType, + data: eventData, + originId: this.clientId + }; + + this.subscribers.forEach( + (subscriber: ISubscriber, subscriberId: string) => { + subscriber.window.postMessage(eventObj, subscriber.locationUrl); + } + ); + + return { + subscribe: function(callbackFn) { + if (this.subscribers.size !== 0) { + const subscribersToNotify = Array.from(this.subscribers.keys()); + + const checkNotifyComplete = (subscriberId: string) => { + const index = subscribersToNotify.indexOf(subscriberId); + subscribersToNotify.splice(index, 1); + + if (subscribersToNotify.length === 0) { + callbackFn(); + } + }; + + this.subscribers.forEach( + (subscriber: ISubscriber, subscriberId: string) => { + if ( + this.eventsToWait.has(subscriberId) && + this.eventsToWait.get(subscriberId).indexOf(eventType) !== -1 + ) { + const actionCompletedFunction = ( + eventData, + subId = subscriberId + ) => { + if (eventData.type === 'ACTION_COMPLETED') { + checkNotifyComplete(subId); + } + this.off(actionCompletedFunction); + }; + this.on(actionCompletedFunction); + } else { + checkNotifyComplete(subscriberId); + } + } + ); + } else { + callbackFn(); + } + }.bind(this) + }; + } + + protected onMessage(event: any) { + if (this.subscribers.has(event.data.originId)) { + this.eventsCallbacks.forEach((callback: Function) => { + callback(event.data, event); + }); + } + } +} diff --git a/public/src/app/sdc/plugin-pubsub.ts b/public/src/app/sdc/plugin-pubsub.ts new file mode 100644 index 0000000..848c7d2 --- /dev/null +++ b/public/src/app/sdc/plugin-pubsub.ts @@ -0,0 +1,32 @@ +import { BasePubSub } from './base-pubsub'; + +declare const window: Window; + +export class PluginPubSub extends BasePubSub { + constructor( + pluginId: string, + parentUrl: string, + eventsToWait?: Array<string> + ) { + super(pluginId); + this.register('sdc-hub', window.parent, parentUrl); + this.subscribe(eventsToWait); + } + + public subscribe(eventsToWait?: Array<string>) { + const registerData = { + pluginId: this.clientId, + eventsToWait: eventsToWait || [] + }; + + this.notify('PLUGIN_REGISTER', registerData); + } + + public unsubscribe() { + const unregisterData = { + pluginId: this.clientId + }; + + this.notify('PLUGIN_UNREGISTER', unregisterData); + } +} diff --git a/public/src/app/store/store.ts b/public/src/app/store/store.ts index a9f2431..b075699 100644 --- a/public/src/app/store/store.ts +++ b/public/src/app/store/store.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; -import { observable, computed, action, toJS, reaction } from 'mobx'; import { findIndex } from 'lodash'; +import { action, computed, observable, toJS } from 'mobx'; @Injectable() export class Store { @@ -16,6 +16,10 @@ export class Store { @observable expandAdvancedSetting = []; @observable generalflow; @observable vfiName; + @observable flowType; + @observable ifrmaeMessenger; + @observable waitForSave = false; + @observable displaySDCDialog = false; // error dialog @observable displayErrorDialog = false; @observable ErrorContent = []; @@ -23,9 +27,11 @@ export class Store { // rule-engine @observable tabParmasForRule; @observable ruleList = new Array(); + @observable ruleListExistParams; @observable ruleEditorInitializedState; @observable isLeftVisible; @observable inprogress; + @observable notifyIdValue = ''; @action updateRuleInList(rule) { @@ -82,6 +88,13 @@ export class Store { } else if (typeof x.assignment.value === 'object') { x.assignment.value = JSON.stringify(x.assignment.value); } + if (x.value) { + if (typeof x.value === 'object') { + x.value = JSON.stringify(x.value); + } + } else if (!x.value) { + x.value = x.assignment.value; + } return x; }); }); diff --git a/public/src/environments/environment.prod.ts b/public/src/environments/environment.prod.ts index bc3ac4b..84965a9 100644 --- a/public/src/environments/environment.prod.ts +++ b/public/src/environments/environment.prod.ts @@ -1,5 +1,5 @@ export const environment = { production: true, - apiBaseUrl: 'dcae/dcaeProxy', - imagePath: 'dcae_fe/assets/images' + apiBaseUrl: 'dcaed/dcaeProxy', + imagePath: 'dcaed/assets/images' }; diff --git a/public/src/polyfills.ts b/public/src/polyfills.ts index d68672f..5db0ca6 100644 --- a/public/src/polyfills.ts +++ b/public/src/polyfills.ts @@ -19,48 +19,39 @@ */ /** IE9, IE10 and IE11 requires all of the following polyfills. **/ -// import 'core-js/es6/symbol'; -// import 'core-js/es6/object'; -// import 'core-js/es6/function'; -// import 'core-js/es6/parse-int'; -// import 'core-js/es6/parse-float'; -// import 'core-js/es6/number'; -// import 'core-js/es6/math'; -// import 'core-js/es6/string'; -// import 'core-js/es6/date'; -// import 'core-js/es6/array'; -// import 'core-js/es6/regexp'; -// import 'core-js/es6/map'; -// import 'core-js/es6/weak-map'; -// import 'core-js/es6/set'; - +import 'core-js/es6/array'; +import 'core-js/es6/date'; +import 'core-js/es6/function'; +import 'core-js/es6/map'; +import 'core-js/es6/math'; +import 'core-js/es6/number'; +import 'core-js/es6/object'; +import 'core-js/es6/parse-float'; +import 'core-js/es6/parse-int'; +import 'core-js/es6/regexp'; +import 'core-js/es6/set'; +import 'core-js/es6/string'; +import 'core-js/es6/symbol'; +import 'core-js/es6/weak-map'; /** IE10 and IE11 requires the following for NgClass support on SVG elements */ // import 'classlist.js'; // Run `npm install --save classlist.js`. - /** IE10 and IE11 requires the following for the Reflect API. */ // import 'core-js/es6/reflect'; - - /** Evergreen browsers require these. **/ -// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. +// Used for reflect-metadata in JIT. If you use AOT (and only Angular +// decorators), you can remove. import 'core-js/es7/reflect'; - - +/*************************************************************************************************** + * APPLICATION IMPORTS + */ +import 'intl'; +import 'intl/locale-data/jsonp/en'; /** * Required to support Web Animations `@angular/platform-browser/animations`. * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation **/ // import 'web-animations-js'; // Run `npm install --save web-animations-js`. - - - /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js/dist/zone'; // Included with Angular CLI. - - - -/*************************************************************************************************** - * APPLICATION IMPORTS - */ +import 'zone.js/dist/zone'; // Included with Angular CLI. diff --git a/public/src/stories/diagram.stories.ts b/public/src/stories/diagram.stories.ts index 00dd922..682fa6d 100644 --- a/public/src/stories/diagram.stories.ts +++ b/public/src/stories/diagram.stories.ts @@ -13,10 +13,24 @@ storiesOf('Diagram', module).add('simple', () => ({ }, props: { list: array('list', [ - { source: 'node1dsvsdsvd', target: 'node2' }, - { source: 'node3', target: 'node4' }, - { source: 'node5', target: 'nodedsvsds6' }, - { source: 'node7', target: 'node8' } + { + name1: 'node1dsvsdsvd', + name2: 'node2', + p1: 'Stream_publish_0', + p2: 'capability' + }, + { + name1: 'node33', + name2: 'node2555', + p1: 'requirement2', + p2: 'capability11' + }, + { + name1: 'namber4', + name2: 'namber3', + p1: 'requirement3', + p2: 'capability4' + } ]) } })); diff --git a/public/src/styles.css b/public/src/styles.css index 4b1d433..a56199a 100644 --- a/public/src/styles.css +++ b/public/src/styles.css @@ -1,8 +1,13 @@ /* You can add global styles to this file, and also import other style files */ -@import '@angular/material/prebuilt-themes/indigo-pink.css'; +@import '@angular/material/prebuilt-themes/indigo-pink.css'; @font-face { font-family: 'Open Sans'; + src: url('./assets/fonts/OpenSans-Regular.ttf') format('ttf'); +} + +@font-face { + font-family: 'Open Sans-SemiBold'; src: url('./assets/fonts/OpenSans-SemiBold.ttf') format('ttf'); } @@ -19,28 +24,31 @@ body, app-root, app-home { height: 100%; - font-family: 'Open Sans', sans-serif; + font-family: 'Open Sans', sans-serif !important; font-size: 13px; /* height: 100vh; */ } +select, +input, +textarea { + font-family: 'Open Sans', sans-serif !important; +} + div, span { font-weight: 400; } -div .field-label, -span .field-label, -div .field-label > span { - font-weight: 600; -} - /* form input validation border */ -textarea.ng-touched.ng-invalid:not(form),input.ng-touched.ng-invalid:not(form) { + +textarea.ng-touched.ng-invalid:not(form), +input.ng-touched.ng-invalid:not(form) { border: 1px solid #cf2a2a !important; } /** reset button **/ + .mat-fab.mat-primary, .mat-mini-fab.mat-primary, .mat-raised-button.mat-primary { @@ -60,7 +68,13 @@ textarea.ng-touched.ng-invalid:not(form),input.ng-touched.ng-invalid:not(form) { box-shadow: none !important; } +.mat-raised-button.mat-primary[disabled] { + background-color: #979797; + color: white; +} + /* Astrix required */ + .required::before { content: '*'; color: red; @@ -68,9 +82,11 @@ textarea.ng-touched.ng-invalid:not(form),input.ng-touched.ng-invalid:not(form) { } /** overide dialog **/ -.ui-dialog { + +/* .ui-dialog { border-top: solid 6px #cf2a2a; -} +} */ + .ui-dialog-titlebar { background: white; } |