diff options
33 files changed, 603 insertions, 114 deletions
diff --git a/features.properties.md b/features.properties.md index b2e453c52..ce153b869 100644 --- a/features.properties.md +++ b/features.properties.md @@ -199,6 +199,9 @@ * FLAG_2004_INSTANTIATION_TEMPLATES_POPUP Enables a designated Templates selection modal, accessible when creating a new instance through "Browse SDC". +* FLAG_2006_VFM_SDNC_PRELOAD_FILES + Enables upload files when SDNC preload checkbox is checked + * FLAG_2002_UNLIMITED_MAX when flag is true and max_instances is not declare than user can add unlimited VND, NETWORK, VFMODULE, User can duplicate up to 10 record in single time. @@ -207,8 +210,3 @@ * FLAG_MORE_AUDIT_INFO_LINK_ON_AUDIT_INFO On the "audit info" modal (available on Instantiation Status page), shows a link navigating to the read-only RETRY page with more audit info. - -*FLAG_2006_USER_PERMISSIONS_BY_OWNING_ENTITY - When flag is true the user will be provided with edit permissions by owning entity id even the user have no permission by Subscriber, - when the flag is false the user provided with edit permission by Subscriber. -
\ No newline at end of file diff --git a/vid-app-common/src/main/java/org/onap/vid/controller/PreLoadController.java b/vid-app-common/src/main/java/org/onap/vid/controller/PreLoadController.java new file mode 100644 index 000000000..ba20997cd --- /dev/null +++ b/vid-app-common/src/main/java/org/onap/vid/controller/PreLoadController.java @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * VID + * ================================================================================ + * Copyright (C) 2017 - 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.vid.controller; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletRequest; + +@RestController +@RequestMapping(PreLoadController.PRE_LOAD) +public class PreLoadController extends VidRestrictedBaseController{ + public static final String PRE_LOAD = "preload"; + + @PostMapping() + public Boolean postPreload (HttpServletRequest request) { + return true; + } +} diff --git a/vid-app-common/src/main/java/org/onap/vid/properties/Features.java b/vid-app-common/src/main/java/org/onap/vid/properties/Features.java index fd50321a3..27190466d 100644 --- a/vid-app-common/src/main/java/org/onap/vid/properties/Features.java +++ b/vid-app-common/src/main/java/org/onap/vid/properties/Features.java @@ -82,6 +82,7 @@ public enum Features implements Feature { FLAG_2004_INSTANTIATION_STATUS_FILTER, FLAG_2004_CREATE_ANOTHER_INSTANCE_FROM_TEMPLATE, FLAG_2004_INSTANTIATION_TEMPLATES_POPUP, + FLAG_2006_VFM_SDNC_PRELOAD_FILES, FLAG_2002_UNLIMITED_MAX, FLAG_MORE_AUDIT_INFO_LINK_ON_AUDIT_INFO, FLAG_2006_USER_PERMISSIONS_BY_OWNING_ENTITY, diff --git a/vid-automation/src/main/java/vid/automation/test/infra/Features.java b/vid-automation/src/main/java/vid/automation/test/infra/Features.java index 8495ceb0f..d98103402 100644 --- a/vid-automation/src/main/java/vid/automation/test/infra/Features.java +++ b/vid-automation/src/main/java/vid/automation/test/infra/Features.java @@ -57,7 +57,7 @@ public enum Features implements Feature { FLAG_2004_CREATE_ANOTHER_INSTANCE_FROM_TEMPLATE, FLAG_2002_UNLIMITED_MAX, FLAG_2004_INSTANTIATION_TEMPLATES_POPUP, - FLAG_2006_USER_PERMISSIONS_BY_OWNING_ENTITY, + FLAG_2006_VFM_SDNC_PRELOAD_FILES, ; public boolean isActive() { diff --git a/vid-webpack-master/cypress/integration/iFrames/instantiation-templates.e2e.ts b/vid-webpack-master/cypress/integration/iFrames/instantiation-templates.e2e.ts index d1bee9c70..f7419ef33 100644 --- a/vid-webpack-master/cypress/integration/iFrames/instantiation-templates.e2e.ts +++ b/vid-webpack-master/cypress/integration/iFrames/instantiation-templates.e2e.ts @@ -25,7 +25,7 @@ describe('Drawing Board: Instantiation Templates', function () { it(`Given a stored template - when click "deploy" - then a coherent request should be sent upon deploy`, () => { - loadDrawingBoardWithRecreateMode(); + cy.loadDrawingBoardWithRecreateMode(templateWithVnfSetup); // Then... cy.getElementByDataTestsId("node-vProbe_NC_VNF 0").should('be.visible'); @@ -34,7 +34,7 @@ describe('Drawing Board: Instantiation Templates', function () { it('Given a template - User can remove existing VNF', () => { - loadDrawingBoardWithRecreateMode(); + cy.loadDrawingBoardWithRecreateMode(templateWithVnfSetup); removeVNFWithVFModules('node-21ae311e-432f-4c54-b855-446d0b8ded72-vProbe_NC_VNF 0'); removeVNFWithVFModules('node-21ae311e-432f-4c54-b855-446d0b8ded72-vProbe_NC_VNF 0'); @@ -47,7 +47,7 @@ describe('Drawing Board: Instantiation Templates', function () { }); it('Given a template - User can add new VNF', () => { - loadDrawingBoardWithRecreateMode(); + cy.loadDrawingBoardWithRecreateMode(templateWithVnfSetup); // add new node addNewNode('node-vProbe_NC_VNF 0-add-btn') .fillVnfPopup() @@ -66,10 +66,10 @@ describe('Drawing Board: Instantiation Templates', function () { // check instance name not change if empty - editNode('node-21ae311e-432f-4c54-b855-446d0b8ded72-vProbe_NC_VNF 0', 0) + cy.editNode('node-21ae311e-432f-4c54-b855-446d0b8ded72-vProbe_NC_VNF 0', 0) .clearInput('instanceName'); cy.getElementByDataTestsId('form-set').click({force: true}).then((done) => { - editNode('node-21ae311e-432f-4c54-b855-446d0b8ded72-vProbe_NC_VNF 0', 0) + cy.editNode('node-21ae311e-432f-4c54-b855-446d0b8ded72-vProbe_NC_VNF 0', 0) .getElementByDataTestsId('instanceName').should('be.empty') }); }); @@ -77,8 +77,8 @@ describe('Drawing Board: Instantiation Templates', function () { it('Given a template - User can Duplicate VNF', () => { const numberOfDuplicate: number = 4; - loadDrawingBoardWithRecreateMode(); - nodeAction('node-21ae311e-432f-4c54-b855-446d0b8ded72-vProbe_NC_VNF 0', 'Duplicate') + cy.loadDrawingBoardWithRecreateMode(templateWithVnfSetup); + cy.nodeAction('node-21ae311e-432f-4c54-b855-446d0b8ded72-vProbe_NC_VNF 0', 'Duplicate') .getElementByDataTestsId('duplicate-amount-vfmodules').select(numberOfDuplicate.toString()) .getTagElementContainsText('button', 'Duplicate').click() .getDrawingBoardDeployBtn().click() @@ -89,10 +89,10 @@ describe('Drawing Board: Instantiation Templates', function () { it('Given a stored template - when "edit" vnf and vfmodules are opened - then template’s details are visible as expected and deploy without changes', () => { - loadDrawingBoardWithRecreateMode(); + cy.loadDrawingBoardWithRecreateMode(templateWithVnfSetup); // Then... - editNode("node-21ae311e-432f-4c54-b855-446d0b8ded72-vProbe_NC_VNF 0") + cy.editNode("node-21ae311e-432f-4c54-b855-446d0b8ded72-vProbe_NC_VNF 0") .getElementByDataTestsId("instanceName").should('have.value', 'hvf6arlba007') .getElementByDataTestsId("productFamily").should('contain', 'Emanuel') .getElementByDataTestsId("tenant").should('contain', 'DN5242-Nov21-T1') @@ -102,14 +102,14 @@ describe('Drawing Board: Instantiation Templates', function () { .checkPlatformValue('xxx1') .getElementByDataTestsId("cancelButton").click(); - editNode("node-c5b26cc1-a66f-4b69-aa23-6abc7c647c88-vprobe_nc_vnf0..VprobeNcVnf..FE_base_module..module-0") + cy.editNode("node-c5b26cc1-a66f-4b69-aa23-6abc7c647c88-vprobe_nc_vnf0..VprobeNcVnf..FE_base_module..module-0") .getElementByDataTestsId("instanceName").should('have.value', 'hvf6arlba007_lba_Base_01') .getElementByDataTestsId("lcpRegion").should('contain', 'hvf6') .getElementByDataTestsId("tenant").should('contain', 'DN5242-Nov21-T1') .getElementByDataTestsId("rollback").should('contain', 'Rollback') .getElementByDataTestsId("cancelButton").click(); - editNode("node-c09e4530-8fd8-418f-9483-2f57ce927b05-vprobe_nc_vnf0..VprobeNcVnf..FE_Add_On_Module_vlbagent_eph..module-1") + cy.editNode("node-c09e4530-8fd8-418f-9483-2f57ce927b05-vprobe_nc_vnf0..VprobeNcVnf..FE_Add_On_Module_vlbagent_eph..module-1") .getElementByDataTestsId("instanceName").should('have.value', 'my_hvf6arlba007_lba_dj_01') .getElementByDataTestsId("volumeGroupName").should('have.value', 'my_special_hvf6arlba007_lba_dj_01_vol') .getElementByDataTestsId("lcpRegion").should('contain', 'hvf6') @@ -126,7 +126,7 @@ describe('Drawing Board: Instantiation Templates', function () { it(`Given a stored template - when "edit" service is opened - then template’s details are visible as expected`, function () { - loadDrawingBoardWithRecreateMode(); + cy.loadDrawingBoardWithRecreateMode(templateWithVnfSetup); cy.openServiceContextMenu() .getElementByDataTestsId("context-menu-header-edit-item").click() @@ -140,7 +140,7 @@ describe('Drawing Board: Instantiation Templates', function () { }); it(`Given a stored template - add one VfModule, edit its details, and deploy - deploy is added with the vfModule details`, () => { - loadDrawingBoardWithRecreateMode(); + cy.loadDrawingBoardWithRecreateMode(templateWithVnfSetup); let newVfModuleName = "new.vfmodule.name"; let module1ModelId = "VprobeNcVnf..FE_Add_On_Module_vlbagent_eph..module-1"; @@ -153,7 +153,7 @@ describe('Drawing Board: Instantiation Templates', function () { cy.drawingBoardPressAddButtonByElementName(`node-${module1CustomizationId}`) .click({force: true}); - editNode(`node-c09e4530-8fd8-418f-9483-2f57ce927b05-${module1CustomizationId}`, 1); + cy.editNode(`node-c09e4530-8fd8-418f-9483-2f57ce927b05-${module1CustomizationId}`, 1); cy.clearInput("instanceName"); cy.typeToInput("instanceName", newVfModuleName); cy.selectDropdownOptionByText('lcpRegion', 'hvf6'); @@ -196,8 +196,8 @@ describe('Drawing Board: Instantiation Templates', function () { it('Given a template - User can remove existing vfmodule', function () { - loadDrawingBoardWithRecreateMode(); - nodeAction('node-c09e4530-8fd8-418f-9483-2f57ce927b05-vprobe_nc_vnf0..VprobeNcVnf..FE_Add_On_Module_vlbagent_eph..module-1', 'Remove'); + cy.loadDrawingBoardWithRecreateMode(templateWithVnfSetup); + cy.nodeAction('node-c09e4530-8fd8-418f-9483-2f57ce927b05-vprobe_nc_vnf0..VprobeNcVnf..FE_Add_On_Module_vlbagent_eph..module-1', 'Remove'); let removed_vfModule_Path = [ ...vnfPath, "vfModules", "vprobe_nc_vnf0..VprobeNcVnf..FE_Add_On_Module_vlbagent_eph..module-1", @@ -217,7 +217,7 @@ describe('Drawing Board: Instantiation Templates', function () { it(`Given a stored template - edit service vnf and vfmodule ${testCase.desc} - deploy request should be ${testCase.desc}`, function () { - loadDrawingBoardWithRecreateMode(); + cy.loadDrawingBoardWithRecreateMode(templateWithVnfSetup); //edit service cy.openServiceContextMenu(); @@ -229,7 +229,7 @@ describe('Drawing Board: Instantiation Templates', function () { cy.getElementByDataTestsId('form-set').click(); // edit vnf - editNode("node-21ae311e-432f-4c54-b855-446d0b8ded72-vProbe_NC_VNF 0"); + cy.editNode("node-21ae311e-432f-4c54-b855-446d0b8ded72-vProbe_NC_VNF 0"); if (testCase.modifySomeValues) { cy.selectPlatformValue('platform'); cy.selectDropdownOptionByText("tenant", "CESAR-100-D-spjg61909"); @@ -237,7 +237,7 @@ describe('Drawing Board: Instantiation Templates', function () { cy.getElementByDataTestsId('form-set').click(); //edit vf module - editNode("node-c5b26cc1-a66f-4b69-aa23-6abc7c647c88-vprobe_nc_vnf0..VprobeNcVnf..FE_base_module..module-0"); + cy.editNode("node-c5b26cc1-a66f-4b69-aa23-6abc7c647c88-vprobe_nc_vnf0..VprobeNcVnf..FE_base_module..module-0"); if (testCase.modifySomeValues) { cy.getElementByDataTestsId('sdncPreLoad').click(); } @@ -266,7 +266,7 @@ describe('Drawing Board: Instantiation Templates', function () { it(`Given a stored template of Network - - it is loaded`, () => { - loadDrawingBoardWithRecreateModeNetwork(); + cy.loadDrawingBoardWithRecreateModeNetwork(templateWithNetworkSetup); // Then... cy.getElementByDataTestsId("node-SR-IOV Provider 2-1").should('be.visible'); @@ -276,9 +276,9 @@ describe('Drawing Board: Instantiation Templates', function () { it(`Given a stored template of Network - User can remove existing network`, () => { - loadDrawingBoardWithRecreateModeNetwork(); + cy.loadDrawingBoardWithRecreateModeNetwork(templateWithNetworkSetup); - nodeAction('node-01f4c475-3f89-4f00-a2f4-39a873dba0ae-SR-IOV Provider 2-1', 'Remove'); + cy.nodeAction('node-01f4c475-3f89-4f00-a2f4-39a873dba0ae-SR-IOV Provider 2-1', 'Remove'); let removed_network_Path = [ "networks", "SR-IOV Provider 2-1", ]; @@ -295,7 +295,7 @@ describe('Drawing Board: Instantiation Templates', function () { it('Given a template - User can add a new network', () => { - loadDrawingBoardWithRecreateModeNetwork(); + cy.loadDrawingBoardWithRecreateModeNetwork(templateWithNetworkSetup); // add new node addNewNode('node-SR-IOV Provider 2-1-add-btn') @@ -341,58 +341,14 @@ const vnfPath2 = [ "vnfs", "vProbe_NC_VNF 0_1" ]; -function loadDrawingBoardWithRecreateMode() { - loadDrawingBoardWithRecreateModeInternal( - '../../' + templateWithVnfSetup.instanceTemplateFile, - templateWithVnfSetup.serviceModelId, - templateWithVnfSetup.serviceModelFile); -} - -function loadDrawingBoardWithRecreateModeNetwork() { - loadDrawingBoardWithRecreateModeInternal( - '../../' + templateWithNetworkSetup.instanceTemplateFile, - templateWithNetworkSetup.serviceModelId, - templateWithNetworkSetup.serviceModelFile); -} - -function loadDrawingBoardWithRecreateModeInternal(instanceTemplate: string, serviceModelIdToLoad: any, serviceModel: string) { - const templateUuid = "46390edd-7100-46b2-9f18-419bd24fb60b"; - - const drawingBoardAction = `RECREATE`; - const templateTopologyEndpoint = "templateTopology"; - cy.route(`**/rest/models/services/${serviceModelIdToLoad}`, - 'fixture:' + serviceModel) - .as('serviceModel'); - - cy.route(`**/instantiationTemplates/${templateTopologyEndpoint}/${templateUuid}`, - 'fixture:' + instanceTemplate) - .as('templateTopology'); - - // When... - cy.openIframe(`app/ui/#/servicePlanning/${drawingBoardAction}` + - `?jobId=${templateUuid}` + - `&serviceModelId=${serviceModelIdToLoad}`); - - cy.wait('@serviceModel'); - cy.wait('@templateTopology'); -} - -function nodeAction(dataTestId: string, action: string, index ?: number) { - return cy.drawingBoardTreeOpenContextMenuByElementDataTestId(dataTestId, index) - .drawingBoardTreeClickOnContextMenuOptionByName(action) -} - -function editNode(dataTestId: string, index ?: number) { - return nodeAction(dataTestId, 'Edit', index); -} function addNewNode(dataTestId: string) { return cy.getElementByDataTestsId(dataTestId).click({force: true}) } function removeVNFWithVFModules(dataTestId: string) { - return nodeAction(dataTestId, 'Remove') + return cy.nodeAction(dataTestId, 'Remove') .getTagElementContainsText('button', 'Remove VNF').click() } @@ -465,6 +421,7 @@ function mockAsyncBulkResponse() { url: Cypress.config('baseUrl') + '/asyncInstantiation/bulk', method: 'POST', status: 200, - response: "[]", + response: true, }).as("expectedPostAsyncInstantiation"); } + diff --git a/vid-webpack-master/cypress/integration/iFrames/sdncPreload.e2e.ts b/vid-webpack-master/cypress/integration/iFrames/sdncPreload.e2e.ts new file mode 100644 index 000000000..877506cad --- /dev/null +++ b/vid-webpack-master/cypress/integration/iFrames/sdncPreload.e2e.ts @@ -0,0 +1,92 @@ +describe('SDNC preload ', () => { + + beforeEach(() => { + cy.clearSessionStorage(); + cy.setTestApiParamToGR(); + cy.initAAIMock(); + cy.initGetAAISubDetails(); + cy.initVidMock(); + cy.initDrawingBoardUserPermission(); + cy.login(); + }); + + afterEach(() => { + cy.screenshot(); + }); + + it('feature toggle is on and SDNC is checked then SDNC preload file is enable : upload success' , () => { + mockPreloadResult(true, 200); + cy.loadDrawingBoardWithRecreateMode(templateWithVnfSetup); + cy.editNode("node-c09e4530-8fd8-418f-9483-2f57ce927b05-vprobe_nc_vnf0..VprobeNcVnf..FE_Add_On_Module_vlbagent_eph..module-1"); + checkUploadLinkLogic(); + + uploadFile().then(() => { + cy.get('.sdc-modal__content').should('contain', 'The pre-load file(s) have been uploaded successfully.'); + cy.getElementByDataTestsId('button-ok').click() + .getElementByDataTestsId('sdnc_pereload_upload_link').should('contain', 'Upload another') + }); + }); + + it('feature toggle is on and SDNC is checked then SDNC preload file is enable : upload fail', () => { + mockPreloadResult(false, 200); + cy.loadDrawingBoardWithRecreateMode(templateWithVnfSetup); + + cy.editNode("node-c09e4530-8fd8-418f-9483-2f57ce927b05-vprobe_nc_vnf0..VprobeNcVnf..FE_Add_On_Module_vlbagent_eph..module-1"); + checkUploadLinkLogic(); + + uploadFile().then(() => { + cy.get('.sdc-modal__content').should('contain', 'Failed to upload one or more of the files, please retry.'); + cy.getElementByDataTestsId('button-ok').click() + .getElementByDataTestsId('sdnc_pereload_upload_link').should('contain', 'Upload') + }); + }); +}); + + +let apiTestResources = '../vid-automation/src/test/resources/asyncInstantiation/'; + +const templateWithVnfSetup = { + serviceModelId: '6cfeeb18-c2b0-49df-987a-da47493c8e38', + instanceTemplateFile: apiTestResources + 'templates__instance_template.json', + instanceTemplateSetWithoutModifyFile: apiTestResources + 'templates__instance_from_template__set_without_modify1.json', + serviceModelFile: '../support/jsonBuilders/mocks/jsons/instantiationTemplates/templates__service_model.json', +}; + +function mockAsyncBulkResponse() { + cy.server().route({ + url: Cypress.config('baseUrl') + '/asyncInstantiation/bulk', + method: 'POST', + status: 200, + response: true, + }).as("expectedPostAsyncInstantiation"); +} + +function mockPreloadResult(response: boolean, status?: number) { + cy.server().route({ + url: Cypress.config('baseUrl') + '/preload', + method: 'POST', + status: status ? status : 200, + response: response, + }).as("preload"); +} + + +function uploadFile() { + // @ts-ignore + return new Promise((resolve) => { + const fileName = '../support/uploadFiles/sdncPreLoadFileExample.json'; + cy.fixture(fileName).then(fileContent => { + // @ts-ignore + cy.get('input[type=file]').eq(0).upload({fileContent, fileName, mimeType: 'application/json'}).then(() => { + resolve(); + }); + }) + }); +} + +function checkUploadLinkLogic() { + cy.getElementByDataTestsId('sdnc_pereload_upload_link').should('contain', 'Upload').should('not.have.class', 'disabled') + .getElementByDataTestsId('sdncPreLoad').click() + .getElementByDataTestsId('sdnc_pereload_upload_link').should('contain', 'Upload').should('have.class', 'disabled') + .getElementByDataTestsId('sdncPreLoad').click() +} diff --git a/vid-webpack-master/cypress/support/index.js b/vid-webpack-master/cypress/support/index.js index 5062f5100..d9e64c0f5 100644 --- a/vid-webpack-master/cypress/support/index.js +++ b/vid-webpack-master/cypress/support/index.js @@ -15,6 +15,7 @@ // Import commands.js using ES2015 syntax: import './commands'; +import 'cypress-file-upload'; import './steps/login.step'; import './steps/fill.service.popup.step'; import './steps/fill.vnf.popup.step'; @@ -36,12 +37,14 @@ import './steps/drawingBoard/drawingBoardModel.steps'; import './steps/drawingBoard/drawingBoardTree.steps'; import './steps/genericForm/genericFormAction.steps'; import './steps/genericForm/popupViewport.step'; -import './steps/drawingBoard/drawingBoardHeader.steps'; import './steps/drawingBoard/general.steps'; +import './steps/drawingBoard/drawingBoardRecreate.steps'; +import './steps/drawingBoard/drawingBoardHeader.steps'; import './steps/general/clickOutside.step'; import './steps/drawingBoard/drawingBoardComponentInfo.steps'; import './steps/genericForm/checkPopover.step'; + // Alternatively you can use CommonJS syntax: // require('./commands') 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 bd9fb9025..e2b9d8ad7 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 @@ -23,5 +23,5 @@ "FLAG_2004_INSTANTIATION_TEMPLATES_POPUP" : false, "FLAG_2002_UNLIMITED_MAX" : true, "FLAG_2004_CREATE_ANOTHER_INSTANCE_FROM_TEMPLATE": true, - "FLAG_2006_USER_PERMISSIONS_BY_OWNING_ENTITY": true + "FLAG_2006_VFM_SDNC_PRELOAD_FILES" : true } diff --git a/vid-webpack-master/cypress/support/steps/drawingBoard/drawingBoardRecreate.steps.ts b/vid-webpack-master/cypress/support/steps/drawingBoard/drawingBoardRecreate.steps.ts new file mode 100644 index 000000000..16f418bc9 --- /dev/null +++ b/vid-webpack-master/cypress/support/steps/drawingBoard/drawingBoardRecreate.steps.ts @@ -0,0 +1,52 @@ +declare namespace Cypress { + interface Chainable { + loadDrawingBoardWithRecreateMode: typeof loadDrawingBoardWithRecreateMode , + loadDrawingBoardWithRecreateModeNetwork: typeof loadDrawingBoardWithRecreateModeNetwork, + loadDrawingBoardWithRecreateModeInternal: typeof loadDrawingBoardWithRecreateModeInternal + } +} + +function loadDrawingBoardWithRecreateMode(templateWithVnfSetup : any) { + cy.loadDrawingBoardWithRecreateModeInternal( + '../../' + templateWithVnfSetup.instanceTemplateFile, + templateWithVnfSetup.serviceModelId, + templateWithVnfSetup.serviceModelFile); +} + +function loadDrawingBoardWithRecreateModeNetwork(templateWithNetworkSetup : any) { + cy.loadDrawingBoardWithRecreateModeInternal( + '../../' + templateWithNetworkSetup.instanceTemplateFile, + templateWithNetworkSetup.serviceModelId, + templateWithNetworkSetup.serviceModelFile); +} + +function loadDrawingBoardWithRecreateModeInternal(instanceTemplate: string, serviceModelIdToLoad: any, serviceModel: string) { + const templateUuid = "46390edd-7100-46b2-9f18-419bd24fb60b"; + + const drawingBoardAction = `RECREATE`; + const templateTopologyEndpoint = "templateTopology"; + cy.route(`**/rest/models/services/${serviceModelIdToLoad}`, + 'fixture:' + serviceModel) + .as('serviceModel'); + + cy.route(`**/instantiationTemplates/${templateTopologyEndpoint}/${templateUuid}`, + 'fixture:' + instanceTemplate) + .as('templateTopology'); + + // When... + + cy.openIframe(`app/ui/#/servicePlanning/${drawingBoardAction}` + + `?jobId=${templateUuid}` + + `&serviceModelId=${serviceModelIdToLoad}`); + + cy.wait('@serviceModel'); + cy.wait('@templateTopology'); +} + + + + + +Cypress.Commands.add('loadDrawingBoardWithRecreateMode', loadDrawingBoardWithRecreateMode); +Cypress.Commands.add('loadDrawingBoardWithRecreateModeNetwork', loadDrawingBoardWithRecreateModeNetwork); +Cypress.Commands.add('loadDrawingBoardWithRecreateModeInternal', loadDrawingBoardWithRecreateModeInternal); diff --git a/vid-webpack-master/cypress/support/steps/drawingBoard/general.steps.ts b/vid-webpack-master/cypress/support/steps/drawingBoard/general.steps.ts index 8d2bb8a24..797fff095 100644 --- a/vid-webpack-master/cypress/support/steps/drawingBoard/general.steps.ts +++ b/vid-webpack-master/cypress/support/steps/drawingBoard/general.steps.ts @@ -1,7 +1,10 @@ declare namespace Cypress { interface Chainable { updateServiceShouldNotOverrideChild: typeof updateServiceShouldNotOverrideChild - openServiceContextMenu: typeof openServiceContextMenu + openServiceContextMenu: typeof openServiceContextMenu, + drawingBoardTreeClickOnContextMenuOptionByName : typeof drawingBoardTreeClickOnContextMenuOptionByName, + nodeAction: typeof nodeAction, + editNode : typeof editNode } } @@ -18,7 +21,6 @@ function updateServiceShouldNotOverrideChild() : void { }); }); }); - } @@ -26,5 +28,36 @@ function openServiceContextMenu() : Chainable<any> { return cy.getElementByDataTestsId('openMenuBtn').click({force: true}); } +function nodeAction(dataTestId: string, action: string, index ?: number) { + return cy.drawingBoardTreeOpenContextMenuByElementDataTestId(dataTestId, index) + .drawingBoardTreeClickOnContextMenuOptionByName(action) +} + +function drawingBoardTreeClickOnContextMenuOptionByName(optionName : string) : Chainable<any> { + switch (optionName) { + case 'Duplicate': + return cy.getElementByDataTestsId('context-menu-duplicate').click({force : true}); + case 'Remove': + return cy.getElementByDataTestsId('context-menu-remove').click({force : true}); + case 'Edit': + return cy.getElementByDataTestsId('context-menu-edit').click({force : true}); + case 'Delete': + return cy.getElementByDataTestsId('context-menu-delete').trigger('mouseover').click(); + case 'Upgrade': + return cy.getElementByDataTestsId('context-menu-upgrade').trigger('mouseover').click(); + case 'Undo Upgrade': + return cy.getElementByDataTestsId('context-menu-undoUpgrade').trigger('mouseover').click(); + default: + return cy.getElementByDataTestsId('context-menu-duplicate').click({force : true}); + } +} + +function editNode(dataTestId: string, index ?: number) { + return cy.nodeAction(dataTestId, 'Edit', index); +} + Cypress.Commands.add('updateServiceShouldNotOverrideChild', updateServiceShouldNotOverrideChild); Cypress.Commands.add('openServiceContextMenu', openServiceContextMenu); +Cypress.Commands.add('drawingBoardTreeClickOnContextMenuOptionByName', drawingBoardTreeClickOnContextMenuOptionByName); +Cypress.Commands.add('nodeAction', nodeAction); +Cypress.Commands.add('editNode', editNode); diff --git a/vid-webpack-master/cypress/support/uploadFiles/sdncPreLoadFileExample.json b/vid-webpack-master/cypress/support/uploadFiles/sdncPreLoadFileExample.json new file mode 100644 index 000000000..c317c4183 --- /dev/null +++ b/vid-webpack-master/cypress/support/uploadFiles/sdncPreLoadFileExample.json @@ -0,0 +1,3 @@ +{ + "comment" : "invalid file, just for upload mock file" +} diff --git a/vid-webpack-master/package.cypress.json b/vid-webpack-master/package.cypress.json index da6aa602f..8ce197f32 100644 --- a/vid-webpack-master/package.cypress.json +++ b/vid-webpack-master/package.cypress.json @@ -16,6 +16,7 @@ "cypress": "3.6.1", "typescript": "3.1.6", "rxjs": "^6.3.3", - "rxjs-compat": "^6.3.3" + "rxjs-compat": "^6.3.3", + "cypress-file-upload": "^3.5.3" } } diff --git a/vid-webpack-master/package.json b/vid-webpack-master/package.json index 1843de030..fdaf3e3d5 100755 --- a/vid-webpack-master/package.json +++ b/vid-webpack-master/package.json @@ -59,6 +59,7 @@ "moment": "^2.24.0", "ng-multiselect-dropdown": "0.1.3", "ng2-bootstrap-modal": "1.0.1", + "ng2-file-upload": "^1.4.0", "ngx-bootstrap": "^2.0.2", "ngx-contextmenu": "^5.1.1", "ngx-datatable": "1.0.3", @@ -88,8 +89,10 @@ "@types/node": "^10.12.18", "angular2-template-loader": "0.6.2", "babel-jest": "24.1.0", + "blueimp-file-upload": "^10.7.0", "codelyzer": "^5.0.1", "cypress": "3.6.1", + "cypress-file-upload": "^3.5.3", "hammerjs": "2.0.8", "husky": "^1.3.1", "istanbul-reports": "2.1.1", diff --git a/vid-webpack-master/src/app/shared/components/formControls/component/checkbox/checkbox.formControl.component.html b/vid-webpack-master/src/app/shared/components/formControls/component/checkbox/checkbox.formControl.component.html index 26362ebed..fe7744e43 100644 --- a/vid-webpack-master/src/app/shared/components/formControls/component/checkbox/checkbox.formControl.component.html +++ b/vid-webpack-master/src/app/shared/components/formControls/component/checkbox/checkbox.formControl.component.html @@ -8,4 +8,9 @@ data-toggle="toggle"> <label class="checkbox-label" for="{{data?.dataTestId}}">{{data?.displayName}}</label> + <div *ngFor="let extraContent of data?.extraContents" class="form-conrtols"> + <div [ngSwitch]="extraContent.type"> + <upload-files *ngSwitchCase="'UPLOAD_FILE'" [uploadFilesModel]="extraContent" [form]="form"></upload-files> + </div> + </div> </div> diff --git a/vid-webpack-master/src/app/shared/components/formControls/component/checkbox/checkbox.formControl.component.scss b/vid-webpack-master/src/app/shared/components/formControls/component/checkbox/checkbox.formControl.component.scss index 005e28cc6..81180e06f 100644 --- a/vid-webpack-master/src/app/shared/components/formControls/component/checkbox/checkbox.formControl.component.scss +++ b/vid-webpack-master/src/app/shared/components/formControls/component/checkbox/checkbox.formControl.component.scss @@ -11,6 +11,7 @@ .details-item label { position: relative; cursor: pointer; + float: left; } .details-item label:before { diff --git a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/sharedControlles/shared.controllers.service.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/sharedControlles/shared.controllers.service.ts index acfaf78ab..83f722704 100644 --- a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/sharedControlles/shared.controllers.service.ts +++ b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/sharedControlles/shared.controllers.service.ts @@ -133,13 +133,14 @@ export class SharedControllersService { }) }; - getSDNCControl = (instance: any): FormControlModel => { + getSDNCControl = (instance: any, extraContents? : object[]): FormControlModel => { return new CheckboxFormControl({ controlName: SDN_C_PRE_LOAD, displayName: 'SDN-C pre-load', dataTestId: 'sdncPreLoad', value: instance ? instance.sdncPreLoad : false, - validations: [new ValidatorModel(ValidatorOptions.required, 'is required')] + validations: [new ValidatorModel(ValidatorOptions.required, 'is required')], + extraContents }) }; diff --git a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.spec.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.spec.ts index b3bb1fe54..49deb3a50 100644 --- a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.spec.ts +++ b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.spec.ts @@ -4,7 +4,7 @@ import {NgRedux} from '@angular-redux/store'; import {ControlGeneratorUtil, SDN_C_PRE_LOAD} from "../control.generator.util.service"; import {AaiService} from "../../../../services/aaiService/aai.service"; import {GenericFormService} from "../../generic-form.service"; -import {FormBuilder} from "@angular/forms"; +import {FormBuilder, FormControl, FormGroup} from "@angular/forms"; import {LogService} from "../../../../utils/log/log.service"; import { FormControlModel, @@ -16,6 +16,7 @@ import {FeatureFlagsService} from "../../../../services/featureFlag/feature-flag import {VfModuleInstance} from "../../../../models/vfModuleInstance"; import {VfModule} from "../../../../models/vfModule"; import {SharedControllersService} from "../sharedControlles/shared.controllers.service"; +import {AppState} from "../../../../store/reducers"; import {SharedTreeService} from "../../../../../drawingBoard/service-planning/objectsToTree/shared.tree.service"; class MockAppStore<T> { @@ -919,6 +920,7 @@ describe('VFModule Control Generator', () => { let injector; let service: VfModuleControlGenerator; let httpMock: HttpTestingController; + let store : NgRedux<AppState>; beforeAll(done => (async () => { TestBed.configureTestingModule({ @@ -939,6 +941,7 @@ describe('VFModule Control Generator', () => { injector = getTestBed(); service = injector.get(VfModuleControlGenerator); httpMock = injector.get(HttpTestingController); + store = injector.get(NgRedux); jest.spyOn(console, 'error'); })().then(done).catch(done.fail)); @@ -1164,5 +1167,29 @@ describe('VFModule Control Generator', () => { expect(controls[i].controlName).toEqual(orderedControls[i]); } }); + + + test('when flag is active - response should contains upload file', ()=>{ + spyOn(store, 'getState').and.returnValue( { + "global": { + "flags": { + "FLAG_2006_VFM_SDNC_PRELOAD_FILES" : true + } + } + }); + + const extraContent = service.getSdncExtraContents(); + console.log("extraContent", extraContent); + const uploadFileData = <any>extraContent[0]; + + expect(uploadFileData.type).toEqual('UPLOAD_FILE'); + expect(uploadFileData.dataTestId).toEqual('sdnc_pereload_upload_link'); + expect(uploadFileData.uploadMethod).toBeDefined(); + expect(uploadFileData.isDisabled).toBeDefined(); + expect(uploadFileData.onSuccess).toBeDefined(); + expect(uploadFileData.onFailed).toBeDefined(); + + }) + }); diff --git a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.ts b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.ts index b00312d5f..5189af0d6 100644 --- a/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.ts +++ b/vid-webpack-master/src/app/shared/components/genericForm/formControlsServices/vfModuleGenerator/vfModule.control.generator.ts @@ -3,7 +3,7 @@ import {GenericFormService} from "../../generic-form.service"; import {AaiService} from "../../../../services/aaiService/aai.service"; import {NgRedux} from "@angular-redux/store"; import {HttpClient} from "@angular/common/http"; -import {ControlGeneratorUtil} from "../control.generator.util.service"; +import {ControlGeneratorUtil, SDN_C_PRE_LOAD} from "../control.generator.util.service"; import { CustomValidatorOptions, FormControlModel, @@ -20,6 +20,8 @@ import {VNFModel} from "../../../../models/vnfModel"; import {VnfInstance} from "../../../../models/vnfInstance"; import * as _ from 'lodash'; import {SharedControllersService} from "../sharedControlles/shared.controllers.service"; +import {MessageModal} from "../../../messageModal/message-modal.service"; +import {ButtonType} from "../../../customModal/models/button.type"; import {SharedTreeService} from "../../../../../drawingBoard/service-planning/objectsToTree/shared.tree.service"; export enum FormControlNames { @@ -36,7 +38,7 @@ export enum FormControlNames { export class VfModuleControlGenerator { aaiService: AaiService; vfModuleModel: VfModule; - isUpdateMode : boolean; + isUpdateMode: boolean; constructor(private genericFormService: GenericFormService, private _basicControlGenerator: ControlGeneratorUtil, @@ -54,7 +56,7 @@ export class VfModuleControlGenerator { if (isUpdateMode && this.store.getState().service.serviceInstance[serviceId] && _.has(this.store.getState().service.serviceInstance[serviceId].vnfs, vnfStoreKey) && _.has(this.store.getState().service.serviceInstance[serviceId].vnfs[vnfStoreKey].vfModules, UUIDData['modelName'])) { - vfModuleInstance = Object.assign({},this.store.getState().service.serviceInstance[serviceId].vnfs[vnfStoreKey].vfModules[UUIDData['modelName']][UUIDData['vFModuleStoreKey']]); + vfModuleInstance = Object.assign({}, this.store.getState().service.serviceInstance[serviceId].vnfs[vnfStoreKey].vfModules[UUIDData['modelName']][UUIDData['vFModuleStoreKey']]); } return vfModuleInstance; }; @@ -65,11 +67,11 @@ export class VfModuleControlGenerator { return vfModule; } - getMacroFormControls(serviceId: string, vnfStoreKey: string, vfModuleStoreKey: string, uuidData : Object, isUpdateMode: boolean): FormControlModel[] { + getMacroFormControls(serviceId: string, vnfStoreKey: string, vfModuleStoreKey: string, uuidData: Object, isUpdateMode: boolean): FormControlModel[] { this.isUpdateMode = isUpdateMode; this.extractVfAccordingToVfModuleUuid(serviceId, uuidData); if (_.isNil(serviceId) || _.isNil(vnfStoreKey) || _.isNil(vfModuleStoreKey)) { - if(isUpdateMode){ + if (isUpdateMode) { this._logService.error('should provide serviceId, vfModuleStoreKey, vnfStoreKey', serviceId); return []; } @@ -85,7 +87,7 @@ export class VfModuleControlGenerator { if (!_.isNil(vfModuleModel)) { result = this.pushInstanceAndVGToForm(result, vfModuleInstance, serviceId, vnfModel, false); } - if(this.store.getState().global.flags['FLAG_SUPPLEMENTARY_FILE']) { + if (this.store.getState().global.flags['FLAG_SUPPLEMENTARY_FILE']) { result = this._basicControlGenerator.concatSupplementaryFile(result, vfModuleInstance); } return result; @@ -99,7 +101,7 @@ export class VfModuleControlGenerator { return new VNFModel(model); } - pushInstanceAndVGToForm(result: FormControlModel[], vfModuleElement: any, serviceId: string, vnfModel: any, isALaCarte: boolean) :FormControlModel[]{ + pushInstanceAndVGToForm(result: FormControlModel[], vfModuleElement: any, serviceId: string, vnfModel: any, isALaCarte: boolean): FormControlModel[] { result.push(this.getInstanceName(vfModuleElement, serviceId, vnfModel.isEcompGeneratedNaming)); if (this.vfModuleModel.volumeGroupAllowed) { result.push(this.getVolumeGroupData(vfModuleElement, serviceId, vnfModel.isEcompGeneratedNaming, isALaCarte)); @@ -107,16 +109,16 @@ export class VfModuleControlGenerator { return result; } - getAlaCarteFormControls(serviceId: string, vnfStoreKey: string, vfModuleStoreKey: string, uuidData : Object, isUpdateMode: boolean): FormControlModel[] { + getAlaCarteFormControls(serviceId: string, vnfStoreKey: string, vfModuleStoreKey: string, uuidData: Object, isUpdateMode: boolean): FormControlModel[] { this.isUpdateMode = isUpdateMode; this.extractVfAccordingToVfModuleUuid(serviceId, uuidData); if (_.isNil(serviceId) || _.isNil(vnfStoreKey) || _.isNil(vfModuleStoreKey)) { - if(isUpdateMode){ + if (isUpdateMode) { this._logService.error('should provide serviceId, vfModuleStoreKey, vnfStoreKey', serviceId); return []; } } - const vnf: VnfInstance = this.store.getState().service.serviceInstance[serviceId].vnfs[vnfStoreKey] ; + const vnf: VnfInstance = this.store.getState().service.serviceInstance[serviceId].vnfs[vnfStoreKey]; const vnfModel = this.newVNFModel(serviceId, vnf); const vfModuleInstance = this._basicControlGenerator.retrieveInstanceIfUpdateMode(this.store, this.getVfModuleInstance(serviceId, vnfStoreKey, uuidData, isUpdateMode)); @@ -126,26 +128,64 @@ export class VfModuleControlGenerator { result.push(this._sharedControllersService.getLegacyRegion(vfModuleInstance)); result.push(this._sharedControllersService.getTenantControl(serviceId, vfModuleInstance)); result.push(this._sharedControllersService.getRollbackOnFailureControl(vfModuleInstance)); - result.push(this._sharedControllersService.getSDNCControl(vfModuleInstance)); - if(this.store.getState().global.flags['FLAG_SUPPLEMENTARY_FILE']) { + result.push(this._sharedControllersService.getSDNCControl(vfModuleInstance, this.getSdncExtraContents())); + if (this.store.getState().global.flags['FLAG_SUPPLEMENTARY_FILE']) { result = this._basicControlGenerator.concatSupplementaryFile(result, vfModuleInstance); } return result; } - getInstanceName(instance: any, serviceId: string, isEcompGeneratedNaming: boolean): FormControlModel { - let formControlModel:FormControlModel = this._sharedControllersService.getInstanceNameController(instance, serviceId, isEcompGeneratedNaming, this.vfModuleModel); - formControlModel.onBlur = (event, form : FormGroup) => { - if(!_.isNil(form.controls['volumeGroupName'])&& event.target.value.length > 0){ - form.controls['volumeGroupName'].setValue(event.target.value + "_vol"); + getSdncExtraContents() : object[] { + return _.compact([ + !!this.store.getState().global.flags['FLAG_2006_VFM_SDNC_PRELOAD_FILES'] ? { + type: 'UPLOAD_FILE', + dataTestId: 'sdnc_pereload_upload_link', + uploadMethod: (form: FormGroup) : Promise<boolean> => { + // this -> files item + return this._aaiService.sdncPreload().toPromise() + .then((response : boolean)=>{ + return response; + }).catch(err => { + return false; + }); + }, + isDisabled: (form: FormGroup): boolean => { + return !form.controls[SDN_C_PRE_LOAD].value; + }, + onSuccess: (form: FormGroup): void => { + MessageModal.showMessageModal({ + text: 'The pre-load file(s) have been uploaded successfully.', + type: "success", + title: 'Success', + buttons: [{type: ButtonType.success, size: 'large', text: 'OK', closeModal: true}] + }) + }, + onFailed: (form: FormGroup) : void=> { + MessageModal.showMessageModal({ + text: 'Failed to upload one or more of the files, please retry.', + type: "error", + title: 'Failure', + buttons: [{type: ButtonType.error, size: 'large', text: 'OK', closeModal: true}] + }) } - }; + } : null + ]); + } + + + getInstanceName(instance: any, serviceId: string, isEcompGeneratedNaming: boolean): FormControlModel { + let formControlModel: FormControlModel = this._sharedControllersService.getInstanceNameController(instance, serviceId, isEcompGeneratedNaming, this.vfModuleModel); + formControlModel.onBlur = (event, form: FormGroup) => { + if (!_.isNil(form.controls['volumeGroupName']) && event.target.value.length > 0) { + form.controls['volumeGroupName'].setValue(event.target.value + "_vol"); + } + }; return formControlModel; } getDefaultVolumeGroupName(instance: any, isEcompGeneratedNaming: boolean): string { - if ((!_.isNil(instance) && instance.volumeGroupName)) { + if ((!_.isNil(instance) && instance.volumeGroupName)) { return instance.volumeGroupName; } if (isEcompGeneratedNaming) { @@ -165,12 +205,12 @@ export class VfModuleControlGenerator { displayName: 'Volume Group Name', dataTestId: 'volumeGroupName', validations: validations, - tooltip : 'When filled, VID will create a Volume Group by this name and associate with this module.\n' + - 'When empty, the module is created without a Volume Group.', - isVisible: this.shouldVGNameBeVisible(isEcompGeneratedNaming,isALaCarte), + tooltip: 'When filled, VID will create a Volume Group by this name and associate with this module.\n' + + 'When empty, the module is created without a Volume Group.', + isVisible: this.shouldVGNameBeVisible(isEcompGeneratedNaming, isALaCarte), value: this.getDefaultVolumeGroupName(instance, isEcompGeneratedNaming), onKeypress: (event) => { - const pattern:RegExp = ControlGeneratorUtil.INSTANCE_NAME_REG_EX; + const pattern: RegExp = ControlGeneratorUtil.INSTANCE_NAME_REG_EX; if (pattern) { if (!pattern.test(event['key'])) { event.preventDefault(); @@ -182,7 +222,7 @@ export class VfModuleControlGenerator { } private shouldVGNameBeVisible(isEcompGeneratedNaming: boolean, isALaCarte: boolean) { - if((!isALaCarte && !isEcompGeneratedNaming) || isALaCarte){ + if ((!isALaCarte && !isEcompGeneratedNaming) || isALaCarte) { return true; } return false; diff --git a/vid-webpack-master/src/app/shared/components/genericForm/generic-form.component.html b/vid-webpack-master/src/app/shared/components/genericForm/generic-form.component.html index edf86823c..627f6426a 100644 --- a/vid-webpack-master/src/app/shared/components/genericForm/generic-form.component.html +++ b/vid-webpack-master/src/app/shared/components/genericForm/generic-form.component.html @@ -3,7 +3,7 @@ <div *ngFor="let formControl of formControls" class="form-conrtols"> <div [ngSwitch]="formControl.type"> <form-control-input *ngSwitchCase="'INPUT'" [data]="formControl" [form]="dynamicFormGroup"></form-control-input> - <checkbox-form-control *ngSwitchCase="'CHECKBOX'" [data]="formControl" [form]="dynamicFormGroup" ></checkbox-form-control> + <checkbox-form-control *ngSwitchCase="'CHECKBOX'" [data]="formControl" [form]="dynamicFormGroup"></checkbox-form-control> <dropdown-form-control *ngSwitchCase="'DROPDOWN'" [data]="formControl" [form]="dynamicFormGroup" ></dropdown-form-control> <file-form-control *ngSwitchCase="'FILE'" [data]="formControl" [form]="dynamicFormGroup"></file-form-control> <multiselect-form-control *ngSwitchCase="'MULTI_SELECT'" diff --git a/vid-webpack-master/src/app/shared/components/genericForm/genericFormSharedComponent/uploadFiles/upload-files-link.component.html b/vid-webpack-master/src/app/shared/components/genericForm/genericFormSharedComponent/uploadFiles/upload-files-link.component.html new file mode 100644 index 000000000..6f59c0ce2 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericForm/genericFormSharedComponent/uploadFiles/upload-files-link.component.html @@ -0,0 +1,15 @@ +<div> + <a [attr.data-tests-id]="uploadFilesModel.dataTestId" + (click)="uploadFilesTrigger()" + href="javascript:void(0)" + class="upload-text" + [class.disabled]="uploadFilesModel.isDisabled && uploadFilesModel.isDisabled(form)">{{uploadFilesModel.uploadText || 'Upload'}}</a> + <span class="hide-span"> + <input + type="file" + #fileInput + ng2FileSelect + [uploader]="uploader" + [attr.data-tests-id]="uploadFilesModel.dataTestId + '-input'"/> + </span> +</div> diff --git a/vid-webpack-master/src/app/shared/components/genericForm/genericFormSharedComponent/uploadFiles/upload-files-link.component.scss b/vid-webpack-master/src/app/shared/components/genericForm/genericFormSharedComponent/uploadFiles/upload-files-link.component.scss new file mode 100644 index 000000000..ce9e14fbe --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericForm/genericFormSharedComponent/uploadFiles/upload-files-link.component.scss @@ -0,0 +1,23 @@ +.upload-text { + margin-left: 30px; + font-family: OpenSans-Semibold; + font-size: 14px; + line-height: 23px; +} + +a.disabled { + color: gray; + cursor: not-allowed; + text-decoration: underline; +} + +.hide-span { + visibility: hidden; + position: absolute; + overflow: hidden; + width: 0px; + height: 0px; + border: none; + margin: 0; + padding: 0 +} diff --git a/vid-webpack-master/src/app/shared/components/genericForm/genericFormSharedComponent/uploadFiles/upload-files-link.component.ts b/vid-webpack-master/src/app/shared/components/genericForm/genericFormSharedComponent/uploadFiles/upload-files-link.component.ts new file mode 100644 index 000000000..803d5d053 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericForm/genericFormSharedComponent/uploadFiles/upload-files-link.component.ts @@ -0,0 +1,41 @@ +import {Component, ElementRef, Input, OnInit, ViewChild} from "@angular/core"; +import {FileItem, FileUploader} from "ng2-file-upload"; +import {UploadFilesLinkModel} from "./upload-files-link.model"; +import {FormGroup} from "@angular/forms"; + +@Component({ + selector: 'upload-files', + templateUrl: './upload-files-link.component.html', + styleUrls: ['./upload-files-link.component.scss'] +}) +export class UploadFilesLinkComponent implements OnInit { + uploader: FileUploader; + @Input() uploadFilesModel: UploadFilesLinkModel; + @Input() form: FormGroup; + @ViewChild('fileInput', {static: false}) fileInput: ElementRef; + + ngOnInit(): void { + this.uploader = new FileUploader({}); + + this.uploader.onAfterAddingAll = async (files: FileItem[]) => { + const result = await this.uploadFilesModel.uploadMethod.call(files, this.form); + if (result && this.uploadFilesModel.onSuccess) { + this.uploadFilesModel.onSuccess.call(this.form); + } else if (!result && this.uploadFilesModel.onFailed) { + this.uploadFilesModel.onFailed.call(this.form); + } + this.uploadFilesModel.uploadText = result ? 'Upload another' : 'Upload' + }; + this.resetUpload(); + } + + resetUpload(): void { + this.fileInput.nativeElement.value = ''; + } + + uploadFilesTrigger() { + if (this.uploadFilesModel.isDisabled && !this.uploadFilesModel.isDisabled(this.form)) { + this.fileInput.nativeElement.click(); + } + } +} diff --git a/vid-webpack-master/src/app/shared/components/genericForm/genericFormSharedComponent/uploadFiles/upload-files-link.model.ts b/vid-webpack-master/src/app/shared/components/genericForm/genericFormSharedComponent/uploadFiles/upload-files-link.model.ts new file mode 100644 index 000000000..beb54f43a --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/genericForm/genericFormSharedComponent/uploadFiles/upload-files-link.model.ts @@ -0,0 +1,30 @@ +import {FileItem} from "ng2-file-upload"; + +export class UploadFilesLinkModel { + uploadText?: string; + + /********************************************************************* + Implement success method - run after uploadMethod return true result + **********************************************************************/ + onSuccess?: (...args) => void; + + /********************************************************************* + Implement failed method - run after uploadMethod return false result + **********************************************************************/ + onFailed?: (...args) => void; + + /********************************************************************************* + Implement upload method and return the upload result status (false/true) + *********************************************************************************/ + uploadMethod: (file: FileItem[], ...args) => Promise<boolean>; + + /******************************** + Should upload file be disabled + ********************************/ + isDisabled?: (...args) => boolean; + + /******************************** + a tag data test id + ********************************/ + dataTestId : string; +} diff --git a/vid-webpack-master/src/app/shared/components/messageModal/message-modal.model.ts b/vid-webpack-master/src/app/shared/components/messageModal/message-modal.model.ts new file mode 100644 index 000000000..d29144095 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/messageModal/message-modal.model.ts @@ -0,0 +1,15 @@ +import {ButtonType} from "../customModal/models/button.type"; + +export class MessageModalModel { + title : string; + text : string; + type : 'error' | 'info' | 'success'; + buttons : {text: string, size: string, type : ButtonType, closeModal: boolean}[]; + + constructor( title : string, text : string, type , buttons : {text: string, size: string, type : ButtonType, closeModal: boolean}[]){ + this.title = title; + this.text = text; + this.type = type; + this.buttons = buttons; + } +} diff --git a/vid-webpack-master/src/app/shared/components/messageModal/message-modal.service.spec.ts b/vid-webpack-master/src/app/shared/components/messageModal/message-modal.service.spec.ts new file mode 100644 index 000000000..ffaccb198 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/messageModal/message-modal.service.spec.ts @@ -0,0 +1,56 @@ +import {MessageModal} from "./message-modal.service"; +import {getTestBed, TestBed} from "@angular/core/testing"; +import {SdcUiCommon} from "onap-ui-angular"; +import each from "jest-each"; +import {MessageBoxService} from "../messageBox/messageBox.service"; +import {MessageModalModel} from "./message-modal.model"; +import {MessageBoxData} from "../messageBox/messageBox.data"; + + +describe('Message Modal Service', () => { + let injector; + let service: MessageModal; + + beforeAll(done => (async () => { + TestBed.configureTestingModule({ + imports: [], + providers: [MessageModal] + }); + await TestBed.compileComponents(); + + injector = getTestBed(); + service = injector.get(MessageModal); + })().then(done).catch(done.fail)); + + + each([ + ["error", SdcUiCommon.ModalType.error], + ["info", SdcUiCommon.ModalType.info], + ["success", SdcUiCommon.ModalType.success] + ]).test('getModalType with type %s should return %s', (inputMessageType, expectedResult) => { + + let message = { + type: inputMessageType + }; + + const type = MessageModal.getModalType(<any>message) + expect(type).toEqual(expectedResult); + }); + + test('showMessageModal should call open modal with all data' , async (done)=>{ + spyOn(MessageBoxService.openModal, 'next'); + let message : MessageModalModel = new MessageModalModel('title', 'text', "success", []); + + MessageModal.showMessageModal(message); + setTimeout(()=>{ + const messageBoxData = new MessageBoxData( message.title, + message.text, + SdcUiCommon.ModalType.success, + SdcUiCommon.ModalSize.medium, + message.buttons) + expect(MessageBoxService.openModal.next).toHaveBeenCalledWith(messageBoxData); + done(); + }, 500) + }); + +}); diff --git a/vid-webpack-master/src/app/shared/components/messageModal/message-modal.service.ts b/vid-webpack-master/src/app/shared/components/messageModal/message-modal.service.ts new file mode 100644 index 000000000..e1f85bdb0 --- /dev/null +++ b/vid-webpack-master/src/app/shared/components/messageModal/message-modal.service.ts @@ -0,0 +1,39 @@ +import {Injectable} from "@angular/core"; +import {MessageBoxService} from '../messageBox/messageBox.service'; +import {MessageBoxData} from '../messageBox/messageBox.data'; +import {SdcUiCommon} from "onap-ui-angular"; +import {MessageModalModel} from "./message-modal.model"; + +@Injectable() +export class MessageModal { + static showMessageModal(message: MessageModalModel): void { + setTimeout(() => { + let messageBoxData: MessageBoxData = new MessageBoxData( + message.title, + message.text, + this.getModalType(message), + SdcUiCommon.ModalSize.medium, + message.buttons); + MessageBoxService.openModal.next(messageBoxData); + } + , 500); + }; + + + static getModalType = (message: MessageModalModel): string => { + switch (message.type) { + case "error": { + return SdcUiCommon.ModalType.error + } + case "info": { + return SdcUiCommon.ModalType.info; + } + case "success": { + return SdcUiCommon.ModalType.success; + } + } + }; +} + + + diff --git a/vid-webpack-master/src/app/shared/models/formControlModels/checkboxFormControl.model.ts b/vid-webpack-master/src/app/shared/models/formControlModels/checkboxFormControl.model.ts index f505b5667..1675917d2 100644 --- a/vid-webpack-master/src/app/shared/models/formControlModels/checkboxFormControl.model.ts +++ b/vid-webpack-master/src/app/shared/models/formControlModels/checkboxFormControl.model.ts @@ -1,11 +1,13 @@ import {FormControlModel} from "./formControl.model"; import {FormControlType} from "./formControlTypes.enum"; +import * as _ from "lodash"; export class CheckboxFormControl extends FormControlModel{ - + extraContents : object[]; constructor(data) { super(data); this.type = FormControlType.CHECKBOX; this.validations = []; + this.extraContents = !_.isNil(data.extraContents) ? data.extraContents : null; } } diff --git a/vid-webpack-master/src/app/shared/models/formControlModels/formControl.model.ts b/vid-webpack-master/src/app/shared/models/formControlModels/formControl.model.ts index 24116549e..b3a53d9f2 100644 --- a/vid-webpack-master/src/app/shared/models/formControlModels/formControl.model.ts +++ b/vid-webpack-master/src/app/shared/models/formControlModels/formControl.model.ts @@ -43,6 +43,7 @@ export class FormControlModel { this.preventionsAttribute = data.preventionsAttribute || []; this.onBlur = function(){}; this.onChange = data.onChange ? data.onChange: function () {} + } isRequired() : boolean { diff --git a/vid-webpack-master/src/app/shared/services/aaiService/aai.service.ts b/vid-webpack-master/src/app/shared/services/aaiService/aai.service.ts index 1cc5593f7..9026a5648 100644 --- a/vid-webpack-master/src/app/shared/services/aaiService/aai.service.ts +++ b/vid-webpack-master/src/app/shared/services/aaiService/aai.service.ts @@ -44,6 +44,11 @@ export class AaiService { } + sdncPreload(): Observable<boolean> { + let pathQuery: string = Constants.Path.PRE_LOAD; + return this.http.post<boolean>(pathQuery, {}) + } + getServiceModelById = (serviceModelId: string): Observable<any> => { if (_.has(this.store.getState().service.serviceHierarchy, serviceModelId)) { return of(<any> JSON.parse(JSON.stringify(this.store.getState().service.serviceHierarchy[serviceModelId]))); diff --git a/vid-webpack-master/src/app/shared/services/featureFlag/feature-flags.service.ts b/vid-webpack-master/src/app/shared/services/featureFlag/feature-flags.service.ts index db270decf..722deca99 100644 --- a/vid-webpack-master/src/app/shared/services/featureFlag/feature-flags.service.ts +++ b/vid-webpack-master/src/app/shared/services/featureFlag/feature-flags.service.ts @@ -15,6 +15,7 @@ export enum Features { FLAG_2002_VFM_UPGRADE_ADDITIONAL_OPTIONS ='FLAG_2002_VFM_UPGRADE_ADDITIONAL_OPTIONS', FLAG_2004_INSTANTIATION_STATUS_FILTER ='FLAG_2004_INSTANTIATION_STATUS_FILTER', FLAG_2004_CREATE_ANOTHER_INSTANCE_FROM_TEMPLATE = 'FLAG_2004_CREATE_ANOTHER_INSTANCE_FROM_TEMPLATE', + FLAG_2006_VFM_SDNC_PRELOAD_FILES = 'FLAG_2006_VFM_SDNC_PRELOAD_FILES', FLAG_MORE_AUDIT_INFO_LINK_ON_AUDIT_INFO = 'FLAG_MORE_AUDIT_INFO_LINK_ON_AUDIT_INFO', FLAG_2004_INSTANTIATION_TEMPLATES_POPUP = 'FLAG_2004_INSTANTIATION_TEMPLATES_POPUP', FLAG_2006_USER_PERMISSIONS_BY_OWNING_ENTITY= 'FLAG_2006_USER_PERMISSIONS_BY_OWNING_ENTITY' diff --git a/vid-webpack-master/src/app/shared/shared.module.ts b/vid-webpack-master/src/app/shared/shared.module.ts index 08b7fe520..bae7c11f9 100644 --- a/vid-webpack-master/src/app/shared/shared.module.ts +++ b/vid-webpack-master/src/app/shared/shared.module.ts @@ -93,6 +93,9 @@ import {SvgIconComponent} from "./components/customIcon/custom-icon.component"; import {TooltipTemplateComponent} from "./components/customTooltip/custom-tooltip.component"; import {TooltipDirective} from "./components/customTooltip/tooltip.directive"; import {SdcUiComponentsModule} from "onap-ui-angular"; +import {UploadFilesLinkComponent} from "./components/genericForm/genericFormSharedComponent/uploadFiles/upload-files-link.component"; +import { FileUploadModule } from 'ng2-file-upload'; +import {MessageModal} from "./components/messageModal/message-modal.service"; @@ -111,7 +114,8 @@ import {SdcUiComponentsModule} from "onap-ui-angular"; AngularMultiSelectModule, BootstrapModalModule, DataTableModule, - ModalModule.forRoot() + ModalModule.forRoot(), + FileUploadModule ], declarations: [ PopoverComponent, @@ -156,7 +160,8 @@ import {SdcUiComponentsModule} from "onap-ui-angular"; CustomModalButtonComponent, LoaderComponent, SvgIconComponent, - TooltipTemplateComponent + TooltipTemplateComponent, + UploadFilesLinkComponent ], exports: [ PopoverComponent, @@ -197,7 +202,8 @@ import {SdcUiComponentsModule} from "onap-ui-angular"; CustomModalButtonComponent, LoaderComponent, SvgIconComponent, - TooltipTemplateComponent + TooltipTemplateComponent, + UploadFilesLinkComponent ], entryComponents : [ GenericFormPopupComponent, @@ -248,7 +254,8 @@ import {SdcUiComponentsModule} from "onap-ui-angular"; ModelInformationService, MultiselectFormControlService, InstantiationTemplatesModalService, - LoaderService + LoaderService, + MessageModal ] }) export class SharedModule { diff --git a/vid-webpack-master/src/app/shared/utils/constants.ts b/vid-webpack-master/src/app/shared/utils/constants.ts index da717c8f4..01466f113 100644 --- a/vid-webpack-master/src/app/shared/utils/constants.ts +++ b/vid-webpack-master/src/app/shared/utils/constants.ts @@ -97,6 +97,7 @@ export module Constants { public static SERVICE_MODEL_ID = 'serviceModelId'; public static SERVICES_RETRY_TOPOLOGY = '../../asyncInstantiation/bulkForRetry'; public static INSTANTIATION_TEMPLATE_TOPOLOGY = '../../instantiationTemplates/templateTopology'; + public static PRE_LOAD = '../../preload'; public static CONFIGURATION_PATH = '../../get_property/{name}/defaultvalue'; public static SERVICES_JOB_AUDIT_PATH = '/auditStatus'; public static SERVICES_PROBE_PATH = "../../probe"; diff --git a/vid-webpack-master/src/styles.scss b/vid-webpack-master/src/styles.scss index f170f35f5..1d332ed63 100644 --- a/vid-webpack-master/src/styles.scss +++ b/vid-webpack-master/src/styles.scss @@ -239,4 +239,6 @@ sdc-checkbox { display: none !important; } - +sdc-modal { + z-index: 10000 !important; +} |