diff options
author | Yoav Schneiderman <yoav.schneiderman@intl.att.com> | 2019-12-03 12:55:39 +0200 |
---|---|---|
committer | Ittay Stern <ittay.stern@att.com> | 2019-12-04 17:24:17 +0200 |
commit | 2603481cc6487b0932458ebc7eb4e53202d3f24e (patch) | |
tree | ebd3d1b6178adfddaf53e6d10f3237768062ce75 | |
parent | ce1a30dd1159eb31c2662cf93daee52c90d272d9 (diff) |
Adding Template button to new service instance + cypress test + filter
Issue-ID: VID-724
Change-Id: Ie69a32dd6b74de57fd747a92935c1ce5edb86351
Signed-off-by: Yoav Schneiderman <yoav.schneiderman@intl.att.com>
Signed-off-by: Ittay Stern <ittay.stern@att.com>
15 files changed, 855 insertions, 80 deletions
diff --git a/vid-webpack-master/cypress/integration/iFrames/instantiation.templates.modal.e2e.ts b/vid-webpack-master/cypress/integration/iFrames/instantiation.templates.modal.e2e.ts new file mode 100644 index 000000000..b862e568d --- /dev/null +++ b/vid-webpack-master/cypress/integration/iFrames/instantiation.templates.modal.e2e.ts @@ -0,0 +1,110 @@ +///<reference path="../../../node_modules/cypress/types/index.d.ts"/> +describe('Template', () => { + + beforeEach(() => { + cy.clearSessionStorage(); + cy.setReduxState(); + cy.preventErrorsOnLoading(); + cy.initAAIMock(); + cy.initVidMock(); + cy.login(); + }); + + afterEach(() => { + cy.screenshot(); + }); + + it('when open service popup should show template button', function () { + cy.readFile('cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json').then((flags) => { + cy.server() + .route({ + method: 'GET', + delay: 0, + status: 200, + url: Cypress.config('baseUrl') + "/flags**", + response: { + "FLAG_VF_MODULE_RESUME_STATUS_CREATE": false, + "FLAG_2004_INSTANTIATION_TEMPLATES_POPUP": true + } + }).as('initFlags'); + }); + + const asyncInstantiation = [ + { + "id": 8, + "created": 1525075968000, + "modified": 1525075971000, + "action": "INSTANTIATE", + "createdId": null, + "modifiedId": null, + "rowNum": null, + "auditUserId": null, + "auditTrail": null, + "jobId": "5c2cd8e5-27d0-42e3-85a1-85db5eaba459", + "templateId": "d42ba7c8-9e19-4e34-ae2c-d8af3f24498e", + "userId": "16807000", + "aLaCarte": false, + "msoRequestId": "c0011670-0e1a-4b74-945d-8bf5aede1d9c", + "jobStatus": "FAILED", + "statusModifiedDate": 1525075968000, + "hidden": false, + "pause": false, + "owningEntityId": "d61e6f2d-12fa-4cc2-91df-7c244011d6fc", + "owningEntityName": "WayneHolland", + "project": "WATKINS", + "aicZoneId": "NFT1", + "aicZoneName": "NFTJSSSS-NFT1", + "tenantId": "bae71557c5bb4d5aac6743a4e5f1d054", + "tenantName": "AIN Web Tool-15-D-testalexandria", + "regionId": "hvf6", + "regionName": null, + "serviceType": "TYLER SILVIA", + "subscriberName": "e433710f-9217-458d-a79d-1c7aff376d89", + "serviceInstanceId": null, + "serviceInstanceName": "nWUfl instance name_002", + "serviceModelId": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0", + "serviceModelName": "action-data", + "serviceModelVersion": "1.0", + "createdBulkDate": 1525075968000, + "isRetryEnabled": true + } + ]; + + cy.route(Cypress.config('baseUrl') + "/asyncInstantiation**", asyncInstantiation); + + cy.openIframe('/app/ui/#/servicePopup?serviceModelId=2f80c596-27e5-4ca9-b5bb-e03a7fd4c0fd&isCreate=true'); + cy.getElementByDataTestsId('templateButton').contains('Template') + .getElementByDataTestsId('templateButton').click({force: true}) // Open template Modal + .getElementByDataTestsId('template-modal-title').contains('Templates') // Check Modal header + .getElementByDataTestsId('description-part-1').contains('The following list presents previous instantiations done for this model in this version.') + .getElementByDataTestsId('description-part-2').contains('You may use one of them as a baseline for your instantiation or start from scratch.') + .getElementByDataTestsId('description-part-3').contains('Once you selecting one allows you to change the data before start instantiating.') + + + //check table headers + cy.get(`#header-userId`).contains('User ID'); + cy.get(`#header-createDate`).contains('Date'); + cy.get(`#header-instanceName`).contains('Instance Name'); + cy.get(`#header-instantiationStatus`).contains('Instantiation Status'); + cy.get(`#header-region`).contains('Region'); + cy.get(`#header-tenant`).contains('Tenant'); + cy.get(`#header-aicZone`).contains('AIC Zone'); + + // check table body row + cy.getElementByDataTestsId(`userId-${asyncInstantiation[0].jobId}`).contains('16807000'); + cy.getElementByDataTestsId(`createDate-${asyncInstantiation[0].jobId}`).contains('2018-04-30 11:12:48'); + cy.getElementByDataTestsId(`instanceName-${asyncInstantiation[0].jobId}`).contains('nWUfl instance name_002'); + cy.getElementByDataTestsId(`instantiationStatus-${asyncInstantiation[0].jobId}`).contains('FAILED'); + cy.getElementByDataTestsId(`region-${asyncInstantiation[0].jobId}`).contains('hvf6 (WAYNEHOLLAND)'); + cy.getElementByDataTestsId(`tenant-${asyncInstantiation[0].jobId}`).contains('AIN Web Tool-15-D-testalexandria'); + cy.getElementByDataTestsId(`aicZone-${asyncInstantiation[0].jobId}`).contains('NFTJSSSS-NFT1'); + + + //check load button is disabled + cy.getElementByDataTestsId('LoadTemplateButton').should('be.disabled') + cy.getElementByDataTestsId('row-5c2cd8e5-27d0-42e3-85a1-85db5eaba459').click(); + cy.getElementByDataTestsId('LoadTemplateButton').should('not.be.disabled') + + }); +}); + diff --git a/vid-webpack-master/cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json b/vid-webpack-master/cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json index b829361af..0f5e15298 100644 --- a/vid-webpack-master/cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json +++ b/vid-webpack-master/cypress/support/jsonBuilders/mocks/jsons/flags.cypress.json @@ -19,5 +19,6 @@ "FLAG_1911_INSTANTIATION_ORDER_BUTTON_IN_ASYNC_ALACARTE": false, "FLAG_2002_VNF_PLATFORM_MULTI_SELECT" : false, "FLAG_2002_VFM_UPGRADE_ADDITIONAL_OPTIONS": true, - "FLAG_2004_INSTANTIATION_STATUS_FILTER": true + "FLAG_2004_INSTANTIATION_STATUS_FILTER": true, + "FLAG_2004_INSTANTIATION_TEMPLATES_POPUP" : false } diff --git a/vid-webpack-master/package.json b/vid-webpack-master/package.json index f76ab8745..f2f913612 100644 --- a/vid-webpack-master/package.json +++ b/vid-webpack-master/package.json @@ -56,6 +56,7 @@ "install": "0.12.2", "jest-image-snapshot": "2.8.1", "jest-preset-angular": "6.0.2", + "moment": "^2.24.0", "ng-multiselect-dropdown": "0.1.3", "ng2-bootstrap-modal": "1.0.1", "ngx-bootstrap": "^2.0.2", diff --git a/vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts b/vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts index 07f4d481b..a7b8ac744 100644 --- a/vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts +++ b/vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts @@ -3,18 +3,20 @@ import {HighlightPipe} from "../../pipes/highlight/highlight-filter.pipe"; import * as _ from 'lodash'; @Component({ - selector : 'custom-ellipsis', + selector: 'custom-ellipsis', template: ` <span - sdc-tooltip - class="ellipsis" - id="{{id}}" - [innerHtml]="displayValue | safe : 'html'" - [ngClass]="{'breakWord' : breakWord == true}" - [tooltip-text]="value"> + sdc-tooltip + class="ellipsis" + [attr.data-tests-id]="dataTestId" + id="{{id}}" + [innerHtml]="displayValue | safe : 'html'" + [ngStyle]="{'white-space' : showDots ? 'nowrap' : 'initial'}" + [ngClass]="{'breakWord' : breakWord == true}" + [tooltip-text]="value"> </span>`, - styles : [ - ` + styles: [ + ` .ellipsis { white-space: nowrap; overflow: hidden; @@ -23,30 +25,33 @@ import * as _ from 'lodash'; width: 99%; text-align: left; } - + .breakWord { word-wrap: break-word; white-space: normal; } ` ], - providers : [HighlightPipe] + providers: [HighlightPipe] }) -export class EllipsisComponent implements OnChanges{ - @Input() value : string; - @Input() id : string; - @Input() hightlight : string; - @Input() breakWord : boolean = false; +export class EllipsisComponent implements OnChanges { + @Input() value: string; + @Input() id: string; + @Input() hightlight: string; + @Input() breakWord: boolean = false; + @Input() dataTestId: string; + @Input() showDots: boolean = false; + + displayValue: string; - displayValue : string; - constructor(private _highlightPipe : HighlightPipe){ + constructor(private _highlightPipe: HighlightPipe) { this.displayValue = this.value; } ngOnChanges(changes: SimpleChanges): void { this.displayValue = this.value; - if(!_.isNil(this.hightlight)){ - this.displayValue = this._highlightPipe.transform(this.value ,this.hightlight ? this.hightlight : ''); + if (!_.isNil(this.hightlight)) { + this.displayValue = this._highlightPipe.transform(this.value, this.hightlight ? this.hightlight : ''); } } } diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.html b/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.html index 57064f658..5b8dfa9c9 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.html +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.html @@ -3,14 +3,13 @@ <div class="modal-header"> <button type="button" class="close" - (click)="formPopupDetails?.onCancel(formPopupDetails.that,dynamicForm)" >× + (click)="formPopupDetails?.onCancel(formPopupDetails.that,dynamicForm)">× </button> <span [attr.data-tests-id]="'create-modal-title'" class="modal-title">{{formPopupDetails?.title}} </span> </div> <div class="modal-body popup-content"> - <div class="header-left"> <div>MODEL: <span>"{{formPopupDetails?.leftSubTitle}}"</span></div> </div> @@ -36,12 +35,14 @@ <model-information [modelInformationItems]="formPopupDetails?.modelInformationItems"></model-information> </div> - <div class="instance-form"> + <div class="instance-form"> <div style="position: relative;height: 100%;overflow: auto;"> - <label id="notification-area" *ngIf="shouldShowNotification() == true" style="color: #959595;font-size: 12px;left: 30px;margin-left: 30px;">Data entered will apply to all service instances</label> - <generic-form [formControls]="formPopupDetails?.formControlList" - [dynamicInputs]="formPopupDetails?.dynamicInputsControlList" - (onFormChanged)="dynamicForm = $event" ></generic-form> + <label id="notification-area" *ngIf="shouldShowNotification() == true" + style="color: #959595;font-size: 12px;left: 30px;margin-left: 30px;">Data entered will apply to all + service instances</label> + <generic-form [formControls]="formPopupDetails?.formControlList" + [dynamicInputs]="formPopupDetails?.dynamicInputsControlList" + (onFormChanged)="dynamicForm = $event"></generic-form> </div> </div> @@ -54,6 +55,12 @@ </div> <div class="col-md-6" style="padding: 15px;padding-right: 35px;"> <button + *ngIf="showTemplateBtn" + [attr.data-tests-id]="'templateButton'" + type="button" class="btn btn-success submit" + (click)="openTemplateModal()" + ><span>Template</span></button> + <button [attr.data-tests-id]="'cancelButton'" type="button" class="btn btn-default cancel" (click)="formPopupDetails.onCancel(formPopupDetails.that, dynamicForm)"><span>Cancel</span></button> diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.ts index d0e2d4b85..cadce7ddb 100644 --- a/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.ts +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/generic-form-popup.component.ts @@ -13,16 +13,17 @@ import {AaiService} from "../../services/aaiService/aai.service"; import {GenericFormPopupService} from "./generic-form-popup.service"; import {FormControlModel} from "../../models/formControlModels/formControl.model"; import {FormGeneralErrorsService} from "../formGeneralErrors/formGeneralErrors.service"; +import {InstantiationTemplatesModalComponent} from "./instantiationTemplatesModal/instantiation.templates.modal.component"; export interface PopupModel { - type : PopupType; - uuidData : UUIDData; - node : ITreeNode; - isUpdateMode : boolean; + type: PopupType; + uuidData: UUIDData; + node: ITreeNode; + isUpdateMode: boolean; } -export enum PopupType{ +export enum PopupType { SERVICE = 'service', VNF = 'vnf', NETWORK = 'network', @@ -33,36 +34,39 @@ export enum PopupType{ @Component({ - selector : 'generic-form-popup', - templateUrl : 'generic-form-popup.component.html', - styleUrls : ['generic-form-popup.component.scss'] + selector: 'generic-form-popup', + templateUrl: 'generic-form-popup.component.html', + styleUrls: ['generic-form-popup.component.scss'] }) -export class GenericFormPopupComponent extends DialogComponent<PopupModel, boolean> implements OnInit, OnDestroy{ - formPopupDetails : FormPopupDetails = null; - dynamicForm : FormGroup; - type : PopupType; - uuidData : UUIDData; - isUpdateMode : boolean; - node : ITreeNode = null; - hasGeneralApiError : boolean = false; +export class GenericFormPopupComponent extends DialogComponent<PopupModel, boolean> implements OnInit, OnDestroy { + formPopupDetails: FormPopupDetails = null; + dynamicForm: FormGroup; + type: PopupType; + uuidData: UUIDData; + showTemplateBtn: boolean = false; + isUpdateMode: boolean; + node: ITreeNode = null; + hasGeneralApiError: boolean = false; parentElementClassName = 'content'; errorMsg = 'Page contains errors. Please see details next to the relevant fields.'; servicesQty = 1; quantityOptions = _.range(1, 51) - constructor(dialogService: DialogService , - private _iframeService : IframeService, + + constructor(dialogService: DialogService, + private _iframeService: IframeService, private _store: NgRedux<AppState>, - private _servicePopupService : ServicePopupService, - private _activatedRoute : ActivatedRoute, - private _aaiService : AaiService, + private _servicePopupService: ServicePopupService, + private _activatedRoute: ActivatedRoute, + private _aaiService: AaiService, + private _dialogService: DialogService, private _route: ActivatedRoute, - private _genericFormPopupService : GenericFormPopupService){ + private _genericFormPopupService: GenericFormPopupService) { super(dialogService); } - closeDialog(that) : void{ + closeDialog(that): void { this._iframeService.removeClassCloseModal(that.parentElementClassName); this.dialogService.removeDialog(this); setTimeout(() => { @@ -70,7 +74,7 @@ export class GenericFormPopupComponent extends DialogComponent<PopupModel, boole }, 15); } - shouldShowNotification() : boolean { + shouldShowNotification(): boolean { return this.formPopupDetails && this.formPopupDetails.UUIDData['bulkSize'] > 1 } @@ -79,17 +83,18 @@ export class GenericFormPopupComponent extends DialogComponent<PopupModel, boole .queryParams .subscribe(params => { console.log('changed'); - if(params['serviceModelId'] && params['isCreate']=="true"){ - this._genericFormPopupService.initReduxOnCreateNewService().then((serviceModelId : string)=>{ + if (params['serviceModelId'] && params['isCreate'] == "true") { + this._genericFormPopupService.initReduxOnCreateNewService().then((serviceModelId: string) => { this.uuidData = <any>{ - bulkSize : 1, - isMacro : this._store.getState().service.serviceHierarchy[serviceModelId].service.vidNotions.instantiationType === 'Macro', - type : PopupType.SERVICE, + bulkSize: 1, + isMacro: this._store.getState().service.serviceHierarchy[serviceModelId].service.vidNotions.instantiationType === 'Macro', + type: PopupType.SERVICE, serviceId: serviceModelId, popupService: this._servicePopupService, }; + this.showTemplateBtn = !!this._store.getState().global.flags["FLAG_2004_INSTANTIATION_TEMPLATES_POPUP"]; - this.uuidData.popupService.closeDialogEvent.subscribe((that)=>{ + this.uuidData.popupService.closeDialogEvent.subscribe((that) => { this.closeDialog(that); }); @@ -105,12 +110,12 @@ export class GenericFormPopupComponent extends DialogComponent<PopupModel, boole } }); - FormGeneralErrorsService.checkForErrorTrigger.subscribe(()=>{ + FormGeneralErrorsService.checkForErrorTrigger.subscribe(() => { this.hasSomeError(this.formPopupDetails, this.dynamicForm); }); - - if(!_.isNil(this.uuidData)){ - this.uuidData.popupService.closeDialogEvent.subscribe((that)=>{ + + if (!_.isNil(this.uuidData)) { + this.uuidData.popupService.closeDialogEvent.subscribe((that) => { this.closeDialog(that); }); @@ -119,28 +124,33 @@ export class GenericFormPopupComponent extends DialogComponent<PopupModel, boole } } - hasSomeError(formPopupDetails : FormPopupDetails, form : FormGroup) : boolean{ - if(_.isNil(formPopupDetails)) return false; + hasSomeError(formPopupDetails: FormPopupDetails, form: FormGroup): boolean { + if (_.isNil(formPopupDetails)) return false; else { - for(let controlName in form.controls){ - if(form.controls[controlName].errors){ + for (let controlName in form.controls) { + if (form.controls[controlName].errors) { let error: string[] = Object.keys(form.controls[controlName].errors); - if(error.length === 1 && error[0] === 'required'){ + if (error.length === 1 && error[0] === 'required') { continue; - }else if(Object.keys(form.controls[controlName].errors).length > 0 ){ + } else if (Object.keys(form.controls[controlName].errors).length > 0) { return true; } } } } - return formPopupDetails.formControlList.filter((item : FormControlModel) => item.type === 'DROPDOWN' && item['hasEmptyOptions'] && item.isRequired()).length > 0 + return formPopupDetails.formControlList.filter((item: FormControlModel) => item.type === 'DROPDOWN' && item['hasEmptyOptions'] && item.isRequired()).length > 0 + } + + + openTemplateModal = (): void => { + this._dialogService.addDialog(InstantiationTemplatesModalComponent, {}); } } -export class UUIDData extends Object{ - type : string; - popupService : any; +export class UUIDData extends Object { + type: string; + popupService: any; } diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.html b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.html new file mode 100644 index 000000000..c231c6081 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.html @@ -0,0 +1,161 @@ +<div id="template-popup" class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" + class="close" + (click)="closeModal()">× + </button> + <span [attr.data-tests-id]="'template-modal-title'" + class="modal-title">Templates + </span> + </div> + <div class="modal-body templateModalBody"> + <div class="row description-section"> + <div class="col-md-6"> + <div [attr.data-tests-id]="'description-part-1'">The following list presents previous instantiations done for + this model in this version. + </div> + <div [attr.data-tests-id]="'description-part-2'">You may use one of them as a baseline for your instantiation + or start from scratch. + </div> + <div [attr.data-tests-id]="'description-part-3'">Once you selecting one allows you to change the data before + start instantiating. + </div> + </div> + <div class="col-md-6"> + <input + (keypress)="onFilterKeypress($event)" + class="filter-input form-control input-text" + placeholder="Filter..."> + </div> + + </div> + <div class="row" style="margin-left: 0;margin-right: 0;padding: 20px;"> + <table id="member-table" class="table table-bordered" style="table-layout: fixed"> + <thead class="thead-dark"> + <tr> + <th class="header-title" id="header-userId">User ID</th> + <th class="header-title" id="header-createDate" style="width: 21ch;">Date</th> + <th class="header-title" id="header-instanceName" style="max-width: 50ch;">Instance Name</th> + <th class="header-title" id="header-instantiationStatus">Instantiation Status</th> + <th class="header-title" id="header-summary">Summary</th> + <th class="header-title" id="header-region">Region</th> + <th class="header-title" id="header-tenant">Tenant</th> + <th class="header-title" id="header-aicZone">AIC Zone</th> + </tr> + </thead> + <tbody> + <tr class="member-table-row" + *ngFor="let item of filterTableData;" + (click)="selectedJobId = item.jobId" + [ngClass]="{'selected' : selectedJobId === item.jobId}" + [attr.data-tests-id]="'row-' + item.jobId"> + <td> + <div> + <custom-ellipsis + [dataTestId]="'userId-' + item.jobId" + [id]="item.userId" + [value]="item.userId" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + <td style="width: 21ch;"> + <div> + <custom-ellipsis + [dataTestId]="'createDate-' + item.jobId" + [id]="item.createDate" + [value]="item.createDate" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + <td style="max-width: 50ch;"> + <div> + <custom-ellipsis + [showDots]="true" + [dataTestId]="'instanceName-' + item.jobId" + [id]="item.instanceName" + [value]="item.instanceName" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + <td> + <div> + <custom-ellipsis + [showDots]="true" + [dataTestId]="'instantiationStatus-' + item.jobId" + [id]="item.instantiationStatus" + [value]="item.instantiationStatus" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + <td> + <div> + <custom-ellipsis + [dataTestId]="'summary-' + item.jobId" + [id]="item.summary" + [value]="item.summary" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + <td> + <div> + <custom-ellipsis + [showDots]="true" + [dataTestId]="'region-' + item.jobId" + [id]="item.region" + [value]="item.region" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + <td> + <div> + <custom-ellipsis + [showDots]="true" + [dataTestId]="'tenant-' + item.jobId" + [id]="item.tenant" + [value]="item.tenant" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + <td> + <div> + <custom-ellipsis + [dataTestId]="'aicZone-' + item.jobId" + [id]="item.aicZone" + [value]="item.aicZone" + [breakWord]="true"> + </custom-ellipsis> + </div> + </td> + </tr> + </tbody> + </table> + </div> + + </div> + <div class="modal-footer row" style="padding: 0"> + <div class="col-md-6"> + </div> + <div class="col-md-6" style="padding: 15px;padding-right: 35px;"> + <button + [disabled]="selectedJobId === null" + [attr.data-tests-id]="'LoadTemplateButton'" + type="button" class="btn btn-primary submit" + (click)="loadTemplate()"><span>Load Template</span> + </button> + <button + [attr.data-tests-id]="'startFromScratchButton'" + type="button" class="btn btn-success submit startFromScratchButton" + (click)="closeModal()"><span>Start from Scratch</span> + </button> + </div> + </div> + </div> +</div> diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.scss b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.scss new file mode 100644 index 000000000..23c950c33 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.scss @@ -0,0 +1,192 @@ +$grid-border: 1px #d2d2d2 solid; + +#template-popup { + color: #191919; + + thead { + background: #F8F8F8; + } + .left-panel { + background: #f2f2f2; + border-right: $grid-border; + } + + .header-common { + height: 100%; + align-items: center; + display: flex; + font-family: OpenSans-Semibold; + font-size: 12px; + } + + .header-text { + padding-left: 30px; + @extend .header-common; + } + + .header-left { + grid-area: header-left; + @extend .header-text; + @extend .left-panel; + border-bottom: $grid-border; + + span { + font-family: OpenSans-Regular; + font-size: 14px; + } + ; + } + + .header-right { + grid-area: header-right; + + @extend .header-text; + } + + .quantity-label { + grid-area: quantity-label; + @extend .header-common; + height: 100%; + font-family: OpenSans-Regular; + } + + input[type="number"]:hover::-webkit-inner-spin-button { + height: 20px; + } + + .popup-content { + display: grid; + grid-template-columns: 400px auto 30px 93px; + grid-template-rows: 50px calc(100vh - 180px); + grid-template-areas: "header-left header-right quantity-label quantity" "model-information instance-form instance-form instance-form"; + padding: 0; + } +} + +.modal { + background-color: #191919; + opacity: 0.8; +} + +.modal-dialog { + position: relative; + width: auto; + margin: 0; +} + +@media (min-width: 1150px) { + .popup-content { + grid-template-rows: 30px 680px; + } +} + +.modal-content { + border-radius: 0; + box-shadow: none; + border: none; + min-height: calc(100vh); + +} + +.modal-footer { + padding: 0; + position: absolute; + bottom: 0; + width: 100%; + + .cancel { + width: 120px; + height: 36px; + background: #ffffff; + border: 1px solid #009fdb; + border-radius: 2px; + + span { + font-family: OpenSans-Regular; + font-size: 14px; + color: #009fdb; + line-height: 16px; + } + } + + .startFromScratchButton { + width: 150px !important; + } + + .submit { + width: 120px; + height: 36px; + background: #009fdb; + border-radius: 2px; + border-color: #009fdb; + + + span { + font-family: OpenSans-Regular; + font-size: 14px; + color: #FFFFFF; + line-height: 16px; + } + } +} + +.modal-header { + background-color: #009fdb; + + padding-bottom: 13px; + padding-top: 13px; + padding-left: 29px; + padding-right: 21px; + + .close { + font-size: 32px; + font-weight: 200; + color: #d8d8d8; + text-shadow: none; + filter: none; + opacity: 1; + } + + .modal-title { + font-family: OpenSans-Regular; + font-size: 24px; + color: #fff; + line-height: 34px; + } +} + +.modal-body { + padding: 0; + height: calc(85vh); + + .description-section { + padding: 20px; + font-size: 20px; + } + + .filter-input { + float: right; + width: 25%; + } + + + td.loadTemplateButton { + text-align: center; + vertical-align: middle; + } + + td { + text-align: center; + vertical-align: middle; + padding-left: 5px; + padding-right: 5px; + } + + .member-table-row:hover { + background: #80808033 !important; + } + + .member-table-row.selected { + background: #009fdbb5 !important; + } +} diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.ts new file mode 100644 index 000000000..56abe5b4c --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component.ts @@ -0,0 +1,55 @@ +import {Component, OnDestroy, OnInit} from "@angular/core"; +import {DialogComponent, DialogService} from "ng2-bootstrap-modal"; +import {IframeService} from "../../../utils/iframe.service"; +import {ActivatedRoute} from "@angular/router"; +import {ServiceInfoService} from "../../../server/serviceInfo/serviceInfo.service"; +import {InstantiationTemplatesModalService} from "./instantiation.templates.modal.service"; +import {InstantiationTemplatesRowModel} from "./instantiation.templates.row.model"; + +@Component({ + selector: 'template-modal', + templateUrl: 'instantiation.templates.modal.component.html', + styleUrls: ['instantiation.templates.modal.component.scss'] +}) + +export class InstantiationTemplatesModalComponent extends DialogComponent<string, boolean> implements OnInit, OnDestroy { + + selectedJobId : string = null; + templateModalComponentService: InstantiationTemplatesModalService; + originalTableData: InstantiationTemplatesRowModel[] = []; + filterTableData : InstantiationTemplatesRowModel[] = []; + + constructor(dialogService: DialogService, + private _iframeService: IframeService, + private _serviceInfoService: ServiceInfoService, + private _templateModalComponentService: InstantiationTemplatesModalService, + private _route: ActivatedRoute) { + super(dialogService); + this.templateModalComponentService = _templateModalComponentService; + } + + ngOnInit(): void { + this._route + .queryParams + .subscribe(params => { + this._serviceInfoService.getServicesJobInfo(true, params['serviceModelId']).subscribe((jobs) => { + this.originalTableData = this._templateModalComponentService.convertResponseToUI(jobs); + this.filterTableData = this.originalTableData; + }); + }); + } + + loadTemplate = () => { + + }; + + + onFilterKeypress = (event : KeyboardEvent) => { + //event.target.value + console.log(event.altKey); + }; + + closeModal(): void { + this.dialogService.removeDialog(this); + } +} diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.service.spec.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.service.spec.ts new file mode 100644 index 000000000..f3bd9152e --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.service.spec.ts @@ -0,0 +1,133 @@ +import {getTestBed, TestBed} from '@angular/core/testing'; +import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'; +import {InstantiationTemplatesModalService} from "./instantiation.templates.modal.service"; +import {AaiService} from "../../../services/aaiService/aai.service"; +import {ActivatedRoute} from "@angular/router"; +import {IframeService} from "../../../utils/iframe.service"; +import {NgRedux} from "@angular-redux/store"; +import {FeatureFlagsService} from "../../../services/featureFlag/feature-flags.service"; +import {InstantiationTemplatesRowModel} from "./instantiation.templates.row.model"; + + +class ActivatedRouteMock<T> { + queryParams() { + return { + serviceModelId: '6e59c5de-f052-46fa-aa7e-2fca9d674c44' + } + } +} + +class MockAppStore { + +} + +describe('instantiation templates modal service', () => { + let injector; + let service: InstantiationTemplatesModalService; + let httpMock: HttpTestingController; + let _aaiService: AaiService; + let _activatedRoute: ActivatedRoute; + + beforeAll(done => (async () => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [InstantiationTemplatesModalService, + IframeService, + AaiService, + FeatureFlagsService, + {provide: ActivatedRoute, useClass: ActivatedRouteMock}, + {provide: NgRedux, useClass: MockAppStore} + ] + }); + await TestBed.compileComponents(); + + injector = getTestBed(); + service = injector.get(InstantiationTemplatesModalService); + httpMock = injector.get(HttpTestingController); + _aaiService = injector.get(AaiService); + _activatedRoute = injector.get(ActivatedRoute); + + })().then(done).catch(done.fail)); + + + test('service should be defined', () => { + expect(service).toBeDefined(); + }); + + + test('convertResponseToUI - should return table data', () => { + const jobs = [{ + "id": 5, + "created": 1524995555000, + "modified": 1524995556000, + "action": "INSTANTIATE", + "createdId": null, + "modifiedId": null, + "rowNum": null, + "auditUserId": null, + "auditTrail": null, + "jobId": "9f88fdb5-bb47-4bf3-8c5f-98f1ad0ec87c", + "templateId": "ce4ec177-cfc8-483e-8a2c-b7aea53fd740", + "userId": "16807000", + "msoRequestId": "c0011670-0e1a-4b74-945d-8bf5aede1d91", + "requestId": null, + "jobStatus": "FAILED", + "statusModifiedDate": 1524995555000, + "hidden": false, + "pause": false, + "owningEntityId": "aaa1", + "owningEntityName": "aaa1", + "project": "WATKINS", + "aicZoneId": "BAN1", + "aicZoneName": "VSDKYUTP-BAN1", + "tenantId": "1178612d2b394be4834ad77f567c0af2", + "tenantName": "AIN Web Tool-15-D-SSPtestcustome", + "regionId": "hvf6", + "regionName": null, + "serviceType": "TYLER SILVIA", + "subscriberName": "e433710f-9217-458d-a79d-1c7aff376d89", + "serviceInstanceId": null, + "serviceInstanceName": 'serviceInstanceName', + "serviceModelId": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0", + "serviceModelName": "ComplexService", + "serviceModelVersion": "1.0", + "createdBulkDate": 1524995555000, + "isRetryEnabled": false + }]; + const tableRows: InstantiationTemplatesRowModel[] = service.convertResponseToUI(jobs); + expect(tableRows).toHaveLength(1); + expect(tableRows[0].userId).toEqual('16807000'); + expect(tableRows[0].createDate).toEqual('2018-04-29 12:52:35'); + expect(tableRows[0].instanceName).toEqual('serviceInstanceName'); + expect(tableRows[0].instantiationStatus).toEqual('FAILED'); + expect(tableRows[0].region).toEqual('hvf6 (AAA1)'); + expect(tableRows[0].tenant).toEqual('AIN Web Tool-15-D-SSPtestcustome'); + expect(tableRows[0].aicZone).toEqual('VSDKYUTP-BAN1'); + expect(tableRows[0].jobId).toEqual('9f88fdb5-bb47-4bf3-8c5f-98f1ad0ec87c'); + }); + + + test('getCloudOwner should remove "-att" from owningEntityName : "att-owner', () => { + let result: InstantiationTemplatesRowModel = new InstantiationTemplatesRowModel({ + owningEntityName: 'att-owner', + regionId: 'regionId' + }); + expect(result.region).toEqual('regionId (OWNER)'); + }); + + test('getCloudOwner should not return owningEntityName if not exist', () => { + let result: InstantiationTemplatesRowModel = new InstantiationTemplatesRowModel({owningEntityName: null, regionId: 'regionId'}); + expect(result.region).toEqual('regionId'); + }); + + test('getInstanceName should return instance name id exist if not exist', () => { + let result: InstantiationTemplatesRowModel = new InstantiationTemplatesRowModel({serviceInstanceName: 'instanceName'}); + expect(result.instanceName).toEqual('instanceName'); + }); + + test('getInstanceName should return <Automatically generated> if instance name not exist', () => { + let result: InstantiationTemplatesRowModel = new InstantiationTemplatesRowModel({}); + expect(result.instanceName).toEqual('<Automatically generated>'); + }); + +}); diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.service.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.service.ts new file mode 100644 index 000000000..7126da36a --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.service.ts @@ -0,0 +1,15 @@ +import {Injectable} from "@angular/core"; +import {InstantiationTemplatesRowModel} from "./instantiation.templates.row.model"; + +@Injectable() +export class InstantiationTemplatesModalService { + convertResponseToUI = (jobsResponse: any[]): InstantiationTemplatesRowModel[] => { + let tableRows: InstantiationTemplatesRowModel[] = []; + + jobsResponse.forEach((job) => { + tableRows.push(new InstantiationTemplatesRowModel(job)); + }); + + return tableRows; + }; +} diff --git a/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.row.model.ts b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.row.model.ts new file mode 100644 index 000000000..08982cc67 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.row.model.ts @@ -0,0 +1,51 @@ +import * as moment from 'moment'; +import * as _ from 'lodash'; + +export class InstantiationTemplatesRowModel { + readonly jobId: string; + readonly userId ?: string; + readonly createDate ?: string; + readonly instanceName ?: string; + readonly instantiationStatus?: string; + readonly summary?: string; + readonly region?: string; + readonly tenant?: string; + readonly aicZone?: string; + + constructor(data) { + this.jobId = data.jobId; + this.userId = !_.isNil(data.created) ? data.userId : null; + this.createDate = !_.isNil(data.created) ? moment(data.created).format("YYYY-MM-DD HH:mm:ss") : null; + this.instanceName = this.getInstanceName(data.serviceInstanceName); + this.instantiationStatus = !_.isNil(data.jobStatus) ? data.jobStatus : null; + this.summary = null; + this.region = this.getRegion(data.regionId, data.owningEntityName); + this.tenant = !_.isNil(data.tenantName) ? data.tenantName : null; + this.aicZone = !_.isNil(data.aicZoneName) ? data.aicZoneName : null; + + } + + + /************************************************************************************************** + return the LCP region and in brackets the cloud owner removing the “att-“ with capital letters. + **************************************************************************************************/ + getCloudOwner = (owningEntityName: string): string => { + const splitByAtt: string[] = owningEntityName.split('att-'); + let owning: string = splitByAtt[splitByAtt.length - 1]; + return owning.toUpperCase(); + }; + + getRegion = (regionId: string, owningEntityName: string): string => { + const convertOwning = !_.isNil(owningEntityName) ? `(${this.getCloudOwner(owningEntityName)})` : ''; + return `${regionId} ${convertOwning}`.trim(); + }; + + + getInstanceName = (instanceName?: string): string => { + if (_.isNil(instanceName)) { + return '<Automatically generated>'; + } + return instanceName; + } +} + diff --git a/vid-webpack-master/src/app/shared/pipes/searchFilter/search-filter.pipe.spec.ts b/vid-webpack-master/src/app/shared/pipes/searchFilter/search-filter.pipe.spec.ts index cbf7324ac..2567cbf27 100644 --- a/vid-webpack-master/src/app/shared/pipes/searchFilter/search-filter.pipe.spec.ts +++ b/vid-webpack-master/src/app/shared/pipes/searchFilter/search-filter.pipe.spec.ts @@ -5,7 +5,7 @@ describe('Search filter pipe', () => { const items= [{'id':1, 'name': 'aaa'}, {'id':12, 'name': 'bbb', 'children':{'first': 155, 'second': 2, 'third': 3}}, - {'id':3, 'name': 'ccc', 'children':{'first': 1, 'BbB': '3', 'third': 3}}, + {'id':3, 'name': 'ccc', 'children':{'first': 1, 'BbB': 'BbB', 'third': 3}}, {'id':4, 'name': 'aad', 'children':{'first': 1, 'second': 2, 'third': 3}}]; test('should return items contains substring bb', () => { diff --git a/vid-webpack-master/src/app/shared/pipes/searchFilter/search-filter.pipe.ts b/vid-webpack-master/src/app/shared/pipes/searchFilter/search-filter.pipe.ts index 725eacb53..6e5cfc667 100644 --- a/vid-webpack-master/src/app/shared/pipes/searchFilter/search-filter.pipe.ts +++ b/vid-webpack-master/src/app/shared/pipes/searchFilter/search-filter.pipe.ts @@ -1,14 +1,43 @@ import {Pipe, PipeTransform} from '@angular/core'; +import * as _ from 'lodash'; @Pipe({ name: 'searchFilter' }) export class SearchFilterPipe implements PipeTransform { transform(items: Object[], searchText: string): any[] { - if(!items) return []; - if(!searchText) return items; - return items.filter( item => { - return JSON.stringify(item).toLowerCase().includes(searchText.toLowerCase()); + if (!items) return []; + if (!searchText) return items; + return items.filter((item: object) => { + + const deepFlatObject = this.flatten(item); + + const values = _.values(deepFlatObject).map((item: string) => { + return item.toString().toLowerCase() + }); + + return _.some(values, _.method('includes', searchText.toLowerCase())); }); } + + flatten = object => { + return Object.assign( + {}, + ...(function _flatten(objectBit, path = '') { + //spread the result into our return object + if(objectBit === null) return []; + return [].concat( + //concat everything into one level + + ...Object.keys(objectBit).map( + //iterate over object + key => + typeof objectBit[key] === 'object' //check if there is a nested object + ? _flatten(objectBit[key], `${path}/${key}`) //call itself if there is + : { [`${path}/${key}`]: objectBit[key] } //append object with it’s path as key + ) + ); + })(object) + ); + }; } diff --git a/vid-webpack-master/src/app/shared/shared.module.ts b/vid-webpack-master/src/app/shared/shared.module.ts index a8b45c99a..273dff472 100644 --- a/vid-webpack-master/src/app/shared/shared.module.ts +++ b/vid-webpack-master/src/app/shared/shared.module.ts @@ -74,6 +74,8 @@ import {DynamicInputsComponent} from "./components/dynamic-inputs/dynamic-inputs import {DynamicInputLabelPipe} from "./pipes/dynamicInputLabel/dynamic-input-label.pipe"; import {ModelInformationService} from "./components/model-information/model-information.service"; import {MultiselectFormControlService} from "./components/formControls/component/multiselect/multiselect.formControl.service"; +import {InstantiationTemplatesModalComponent} from "./components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.component"; +import {InstantiationTemplatesModalService} from "./components/genericFormPopup/instantiationTemplatesModal/instantiation.templates.modal.service"; import {SearchFilterPipe} from "./pipes/searchFilter/search-filter.pipe"; import {RecreateResolver} from "./resolvers/recreate/recreate.resolver"; import {InstantiationTemplatesService} from "./services/templateService/instantiationTemplates.service"; @@ -129,7 +131,8 @@ import {InstantiationTemplatesService} from "./services/templateService/instanti SvgComponent, ErrorMsgComponent, DynamicInputsComponent, - DynamicInputLabelPipe + DynamicInputLabelPipe, + InstantiationTemplatesModalComponent ], exports: [ PopoverComponent, @@ -165,7 +168,8 @@ import {InstantiationTemplatesService} from "./services/templateService/instanti ], entryComponents : [ GenericFormPopupComponent, - SearchElementsModalComponent + SearchElementsModalComponent, + InstantiationTemplatesModalComponent ], providers: [ ServiceInfoService, @@ -205,7 +209,8 @@ import {InstantiationTemplatesService} from "./services/templateService/instanti DataFilterPipe, SearchFilterPipe, ModelInformationService, - MultiselectFormControlService + MultiselectFormControlService, + InstantiationTemplatesModalService ] }) export class SharedModule { |