diff options
author | 2018-04-12 16:36:39 +0300 | |
---|---|---|
committer | 2018-04-12 16:36:39 +0300 | |
commit | 9b2ceb347a3371819fcad6bbe2268203afecaf4e (patch) | |
tree | fbb5ea2c147d71dfeeec0882b215423e7b7206b4 /public/src/app/general | |
parent | 72dc8e3298d3e4315cdd9717b778671cb0b625bc (diff) |
DCAE-D fe initial commit
DCAE-D fe initial commit
Change-Id: Ica8ccb7c7ef769c969664d1e168d205eb9fc67f2
Issue-ID: SDC-1218
Signed-off-by: Stone, Avi (as206k) <as206k@att.com>
Diffstat (limited to 'public/src/app/general')
-rw-r--r-- | public/src/app/general/general.component.html | 83 | ||||
-rw-r--r-- | public/src/app/general/general.component.scss | 38 | ||||
-rw-r--r-- | public/src/app/general/general.component.spec.ts | 55 | ||||
-rw-r--r-- | public/src/app/general/general.component.ts | 323 |
4 files changed, 499 insertions, 0 deletions
diff --git a/public/src/app/general/general.component.html b/public/src/app/general/general.component.html new file mode 100644 index 0000000..dcea57a --- /dev/null +++ b/public/src/app/general/general.component.html @@ -0,0 +1,83 @@ +<form #generalForm="ngForm" novalidate style="display: flex; margin: 1em;"> + <div class="left"> + + <div class="import-wrapper" style="display: flex" *ngIf="store.generalflow === 'import' && !importCompleted"> + <div class="field" style="width:70%"> + <div class="field-label required" style="display: flex;"> + <span>Select existing VFCMT</span> + </div> + <ng-select name="vfcmt" [items]="vfcmts" required [virtualScroll]="true" placeholder="Select VFCMT" [(ngModel)]="selectedVfcmt" + class="vfcmt-list" (change)="vfcmtChange($event)"> + </ng-select> + </div> + + <div class="field" style="width:30%"> + <div class="field-label required" style="display: flex;"> + <span>Select version</span> + </div> + <select name="version" required data-tests-id="vfcmtVersion" [(ngModel)]="selectedVersion" [style.background]="versions.length == 0 ? '#ebebe4' : 'white'" + (ngModelChange)="versionChange($event)" [disabled]="versions.length == 0" style="width: 100%; height: 30px;"> + <option [ngValue]="null" disabled>Select version</option> + <option *ngFor="let item of versions" [value]="item.version">{{item.version}}</option> + </select> + </div> + </div> + + <div class="field"> + <div class="field-label required">Name</div> + <input type="text" name="name" ngModel required [(ngModel)]="newVfcmt.name" class="field-text" [disabled]="this.store.isEditMode || disableName" + data-tests-id="nameMc" /> + </div> + + <div class="field"> + <div class="field-label required">Description</div> + <textarea required name="description" ngModel [(ngModel)]="newVfcmt.description" style="resize: none;" cols="30" rows="10" + class="field-text" data-tests-id="descMc" [disabled]="this.store.isEditMode || disableDescription"></textarea> + </div> + + <div class="field" *ngIf="store.generalflow === 'new'"> + <div class="field-label required" style="display: flex;"> + <span>Template</span> + <span style="padding-left: 5px;" [innerHTML]="'help-circle' | feather:14"></span> + </div> + <select name="template" [disabled]="this.store.isEditMode" required [(ngModel)]="newVfcmt.template" (ngModelChange)="onChangeTemplate($event)" + data-tests-id="templateDdl" class="field-text" [style.background]="this.store.isEditMode ? '#ebebe4' : 'white'"> + <option [ngValue]="null" disabled>Select template</option> + <option *ngFor="let template of templates" [value]="template.uuid" data-tests-id="templateOptions">{{template.name}}</option> + </select> + </div> + + <div class="field" *ngIf="store.generalflow === 'import' || store.generalflow === 'edit'"> + <div class="field-label required" style="display: flex;"> + <span>Flow type</span> + <span style="padding-left: 5px;" [innerHTML]="'help-circle' | feather:14"></span> + </div> + <select name="flowType" [disabled]="this.store.isEditMode || disableFlowType" required [(ngModel)]="newVfcmt.flowType" data-tests-id="flowTypeDdl" + class="field-text" [style.background]="this.store.isEditMode || disableFlowType ? '#ebebe4' : 'white'"> + <option [ngValue]="null" disabled>Select Flow Type</option> + <option *ngFor="let flowType of flowTypes" [value]="flowType" data-tests-id="flowTypeOptions">{{flowType}}</option> + </select> + </div> + + <div class="field"> + <div class="field-label required" style="display: flex;"> + <span>Attached to</span> + <span style="padding-left: 5px;" [innerHTML]="'help-circle' | feather:14"></span> + </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 *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> + <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 new file mode 100644 index 0000000..d76e1ae --- /dev/null +++ b/public/src/app/general/general.component.scss @@ -0,0 +1,38 @@ +.left, +.right { + width: 50%; +} + +.ng-select.ng-single .ng-control { + border-radius: 0; + height: 30px; + min-height: 30px; +} + +.toast-container .toast { + width: 400px !important; + box-shadow: none; + border-radius: 0; +} +.toast-container .toast:hover { + box-shadow: none; +} + +.field { + margin: 1em; + .field-label { + padding-bottom: 0.5em; + } + .required::before { + content: '*'; + color: red; + padding-right: 5px; + } + .field-text { + flex: 1; + width: 100%; + min-width: 250px; + padding: 5px 0 5px 5px; + margin: 0; + } +} diff --git a/public/src/app/general/general.component.spec.ts b/public/src/app/general/general.component.spec.ts new file mode 100644 index 0000000..fb761db --- /dev/null +++ b/public/src/app/general/general.component.spec.ts @@ -0,0 +1,55 @@ +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); + }); +}); diff --git a/public/src/app/general/general.component.ts b/public/src/app/general/general.component.ts new file mode 100644 index 0000000..422d834 --- /dev/null +++ b/public/src/app/general/general.component.ts @@ -0,0 +1,323 @@ +import { + Component, + OnInit, + ViewChild, + ViewEncapsulation, + Output, + EventEmitter +} 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 { + pipe, + groupBy, + map, + sort, + descend, + ascend, + prop, + find, + propEq, + findIndex +} from 'ramda'; +import { sortBy, forEach } from 'lodash'; +import { ToastrService } from 'ngx-toastr'; + +export const groupingData = pipe( + groupBy(prop('name')), + map(sort(descend(prop('version')))) +); + +@Component({ + selector: 'app-general', + encapsulation: ViewEncapsulation.None, + templateUrl: './general.component.html', + styleUrls: ['./general.component.scss'] +}) +export class GeneralComponent implements OnInit { + newVfcmt = { + name: null, + description: null, + template: null, + flowType: null, + vfni: null, + isCloneVFCMT: false, + isUpdateFlowType: false + }; + isLatestVersion = true; + vfniList = []; + templates = []; + serviceUUID: string; + vfcmts = new Array(); + versions = new Array(); + result = new Array(); + flowTypes = new Array(); + selectedVfcmt; + selectedVersion = null; + importCompleted = false; + disableName = false; + disableDescription = false; + disableFlowType = false; + 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( + private restApi: RestApiService, + public store: Store, + private toastr: ToastrService, + private route: ActivatedRoute + ) { + console.log('route mcid: ', this.route.snapshot.params.mcid); + if ( + this.route.snapshot.params.mcid === 'import' || + this.route.snapshot.params.mcid === 'new' + ) { + this.store.generalflow = this.route.snapshot.params.mcid; + } else { + this.store.generalflow = 'edit'; + this.store.mcUuid = this.route.snapshot.params.mcid; + } + this.serviceUUID = this.route.snapshot.params.uuid; + } + + onChangeTemplate(template) { + console.log('flow template', template); + } + onChangeVfni(vfni) { + console.log('vfni', vfni); + } + vfcmtChange(vfcmtName) { + vfcmtName !== undefined + ? (this.versions = this.result[vfcmtName]) + : ((this.versions = []), this.restForm()); + this.store.isEditMode = true; + this.selectedVersion = null; + } + versionChange(version) { + const versionIndex = findIndex(propEq('version', version))(this.versions); + this.isLatestVersion = versionIndex === 0 ? true : false; + const selectedVfcmtByVersion = find( + propEq('version', version), + this.result[this.selectedVfcmt] + ); + this.newVfcmt.template = selectedVfcmtByVersion.uuid; + this.restApi.getVfcmtReferenceData(selectedVfcmtByVersion.uuid).subscribe( + success => { + this.store.loader = false; + console.log('vfcmt ref data:', success); + this.store.isEditMode = false; + this.getServiceRef(success); + }, + error => { + this.notifyError(error); + }, + () => { + this.store.loader = false; + } + ); + } + private notifyError(error: any) { + this.store.loader = false; + console.log(error.notes); + this.store.ErrorContent = Object.values(error.requestError); + this.store.displayErrorDialog = true; + } + + ngOnInit() { + if (this.store.generalflow === 'edit') { + this.store.loader = true; + this.restApi + .getCompositionMonitoringComponent(this.store.mcUuid) + .subscribe( + response => { + this.newVfcmt = response.vfcmt; + this.flowTypes.push(this.newVfcmt.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; + }, + error => { + this.notifyError(error); + } + ); + } else if (this.store.generalflow === 'import') { + this.store.loader = true; + this.store.isEditMode = true; + this.restApi + .getVfcmtsForMigration({ + contextType: this.route.snapshot.params.contextType, + uuid: this.route.snapshot.params.uuid, + version: this.route.snapshot.params.version + }) + .subscribe( + success => { + this.store.loader = false; + this.result = groupingData(success); + this.vfcmts = sortBy(Object.keys(this.result), name => name); + }, + error => { + this.notifyError(error); + }, + () => { + this.store.loader = false; + } + ); + } else if (this.route.snapshot.params.mcid === 'new') { + // get template data for ddl + const template$ = this.restApi.getTemplateResources(); + // get service vfi list for ddl '08ff91f1-9b57-4918-998b-4d2c98832815' + const vfniList$ = this.restApi.getServiceInstances(this.serviceUUID); + this.store.loader = true; + forkJoin(template$, vfniList$).subscribe( + success => { + console.log('all', success); + this.templates = success[0]; + this.vfniList = success[1].resources; + }, + error => { + this.notifyError(error); + }, + () => { + this.store.loader = false; + } + ); + } + } + + private restForm() { + this.newVfcmt = { + name: null, + description: null, + template: null, + flowType: null, + vfni: null, + isCloneVFCMT: false, + isUpdateFlowType: false + }; + const controls = this.generalForm.controls; + forEach(controls, control => { + control.markAsUntouched(); + }); + } + + private getServiceRef(data) { + if (data.flowType !== undefined) { + if (data.serviceUuid === this.serviceUUID) { + this.newVfcmt.name = data.name; + this.newVfcmt.description = data.description; + this.disableName = true; + this.disableDescription = true; + this.setFlowType(data); // true + this.setVfni(data); + this.newVfcmt.isCloneVFCMT = false; + } else { + this.isCloneVfcmtToast(); + this.setFlowType(data); // true + this.setVfni(data); + this.newVfcmt.isCloneVFCMT = true; + } + } else { + if (data.serviceUuid === this.serviceUUID && this.isLatestVersion) { + this.newVfcmt.name = data.name; + this.newVfcmt.description = data.description; + this.disableName = true; + this.disableDescription = true; + this.newVfcmt.isCloneVFCMT = false; + this.setFlowType(data); // true + this.setVfni(data); + } else { + this.isCloneVfcmtToast(); + this.setFlowType(data); // true + this.setVfni(data); + this.newVfcmt.isCloneVFCMT = true; + } + } + } + + private isCloneVfcmtToast() { + this.toastr.warning( + `<h3>The monitoring configuration is copied.</h3> + <div> + The selected VFCMT is assigned to a different + </div> + <div> + service or has a newer version. + </div> + `, + '', + { + enableHtml: true, + // disableTimeOut: true + timeOut: 10000 + } + ); + } + + private setVfni(data: any) { + if (data.serviceUuid !== this.serviceUUID) { + this.getVfniList(); + this.disableVnfiList = false; + } else { + this.disableVnfiList = true; + this.vfniList.push({ resourceInstanceName: data.vfiName }); + this.newVfcmt.vfni = data.vfiName; + } + } + + private setFlowType(data: any) { + if (data.flowType === undefined) { + this.newVfcmt.isUpdateFlowType = true; + this.disableFlowType = false; + this.getFlowTypeList(); + } else { + this.newVfcmt.isUpdateFlowType = false; + this.disableFlowType = true; + this.flowTypes.push(data.flowType); + this.newVfcmt.flowType = data.flowType; + } + } + + private getFlowTypeList() { + this.restApi.getFlowType().subscribe( + success => { + console.log('flow types', success.flowTypes); + this.flowTypes = success.flowTypes; + }, + error => { + this.notifyError(error); + }, + () => { + this.store.loader = false; + } + ); + } + private getVfniList() { + this.restApi.getServiceInstances(this.serviceUUID).subscribe( + success => { + console.log('vfni List', success); + this.vfniList = success.resources; + }, + error => { + this.notifyError(error); + return null; + }, + () => { + this.store.loader = false; + } + ); + } +} |