2 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13 * or implied. See the License for the specific language governing
14 * permissions and limitations under the License.
16 import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js';
17 import Configuration from 'sdc-app/config/Configuration.js';
18 import i18n from 'nfvo-utils/i18n/i18n.js';
19 import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js';
20 import LicenseAgreementActionHelper from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js';
21 import FeatureGroupsActionHelper from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js';
23 import {actionTypes, onboardingOriginTypes, PRODUCT_QUESTIONNAIRE, forms} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
24 import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js';
25 import SoftwareProductComponentsActionHelper from './components/SoftwareProductComponentsActionHelper.js';
26 import {actionsEnum as VersionControllerActionsEnum} from 'nfvo-components/panel/versionController/VersionControllerConstants.js';
27 import {actionTypes as HeatSetupActions} from 'sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupConstants.js';
28 import {actionTypes as featureGroupsActionConstants} from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConstants.js';
29 import {actionTypes as licenseAgreementActionTypes} from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js';
30 import {actionTypes as componentActionTypes} from './components/SoftwareProductComponentsConstants.js';
31 import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
32 import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
33 import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js';
34 import {statusEnum} from 'nfvo-components/panel/versionController/VersionControllerConstants.js';
35 import {actionTypes as commonActionTypes} from 'sdc-app/common/reducers/PlainDataReducerConstants.js';
38 const restPrefix = Configuration.get('restPrefix');
39 return `${restPrefix}/v1.0/vendor-software-products/`;
41 function softwareProductCategoriesUrl() {
42 const restATTPrefix = Configuration.get('restATTPrefix');
43 return `${restATTPrefix}/v1/categories/resources/`;
46 function uploadFile(vspId, formData, version) {
47 return RestAPIUtil.post(`${baseUrl()}${vspId}/versions/${version.id}/orchestration-template-candidate`, formData);
51 function putSoftwareProduct(softwareProduct) {
52 return RestAPIUtil.put(`${baseUrl()}${softwareProduct.id}/versions/${softwareProduct.version.id}`, {
53 name: softwareProduct.name,
54 description: softwareProduct.description,
55 category: softwareProduct.category,
56 subCategory: softwareProduct.subCategory,
57 vendorId: softwareProduct.vendorId,
58 vendorName: softwareProduct.vendorName,
59 licensingVersion: softwareProduct.licensingVersion && softwareProduct.licensingVersion.id ? softwareProduct.licensingVersion : {} ,
60 icon: softwareProduct.icon,
61 licensingData: softwareProduct.licensingData,
62 onboardingMethod: softwareProduct.onboardingMethod,
63 networkPackageName: softwareProduct.networkPackageName,
64 onboardingOrigin: softwareProduct.onboardingOrigin
68 function putSoftwareProductQuestionnaire(vspId, qdata, version) {
69 return RestAPIUtil.put(`${baseUrl()}${vspId}/versions/${version.id}/questionnaire`, qdata);
72 function putSoftwareProductAction(id, action, version) {
73 return RestAPIUtil.put(`${baseUrl()}${id}/versions/${version.id}/actions`, {action: action});
76 function fetchSoftwareProductList() {
77 return RestAPIUtil.fetch(baseUrl());
80 function fetchFinalizedSoftwareProductList() {
81 return RestAPIUtil.fetch(`${baseUrl()}?versionFilter=Final`);
84 function fetchSoftwareProduct(vspId, version) {
85 return RestAPIUtil.fetch(`${baseUrl()}${vspId}/versions/${version.id}`);
88 function fetchSoftwareProductQuestionnaire(vspId, version) {
89 return RestAPIUtil.fetch(`${baseUrl()}${vspId}/versions/${version.id}/questionnaire`);
92 function updateSoftwareProductHeatCandidate(softwareProductId, heatCandidate, version) {
93 return RestAPIUtil.put(`${baseUrl()}${softwareProductId}/versions/${version.id}/orchestration-template-candidate/manifest`, heatCandidate);
95 function validateHeatCandidate(softwareProductId, version) {
96 return RestAPIUtil.put(`${baseUrl()}${softwareProductId}/versions/${version.id}/orchestration-template-candidate/process`);
99 function fetchOrchestrationTemplateCandidate(softwareProductId, version, ) {
100 return RestAPIUtil.fetch(`${baseUrl()}${softwareProductId}/versions/${version.id}/orchestration-template-candidate`, {dataType: 'binary'});
103 function objToString(obj) {
105 if (obj instanceof Array) {
106 obj.forEach((item) => {
107 str += objToString(item) + '\n';
112 if (obj.hasOwnProperty(p)) {
113 str += obj[p] + '\n';
120 function parseUploadErrorMsg(error) {
122 for (let key in error) {
123 if (error.hasOwnProperty(key)) {
124 message += objToString(error[key]) + '\n';
130 function fetchSoftwareProductCategories(dispatch) {
131 let handleResponse = response => dispatch({
132 type: actionTypes.SOFTWARE_PRODUCT_CATEGORIES_LOADED,
133 softwareProductCategories: response
135 return RestAPIUtil.fetch(softwareProductCategoriesUrl())
136 .then(handleResponse)
137 .catch(() => handleResponse(null));
140 function loadLicensingData(dispatch, {licenseModelId, licensingVersion}) {
142 LicenseAgreementActionHelper.fetchLicenseAgreementList(dispatch, {licenseModelId, version: licensingVersion}),
143 FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, {licenseModelId, version: licensingVersion})
147 function getExpandedItemsId(items, itemIdToToggle) {
148 for (let i = 0; i < items.length; i++) {
149 if (items[i].id === itemIdToToggle) {
150 if (items[i].expanded) {
154 return {[itemIdToToggle]: true};
157 else if (items[i].items && items[i].items.length > 0) {
158 let mapOfExpandedIds = getExpandedItemsId(items[i].items, itemIdToToggle);
159 if (mapOfExpandedIds !== false) {
160 mapOfExpandedIds[items[i].id] = true;
161 return mapOfExpandedIds;
168 function getTimestampString() {
169 let date = new Date();
170 let z = n => n < 10 ? '0' + n : n;
171 return `${date.getFullYear()}-${z(date.getMonth())}-${z(date.getDate())}_${z(date.getHours())}-${z(date.getMinutes())}`;
174 function showFileSaveDialog({blob, xhr, defaultFilename, addTimestamp}) {
176 let contentDisposition = xhr.getResponseHeader('content-disposition') ? xhr.getResponseHeader('content-disposition') : '';
177 let match = contentDisposition.match(/filename=(.*?)(;|$)/);
182 filename = defaultFilename;
186 filename = filename.replace(/(^.*?)\.([^.]+$)/, `$1_${getTimestampString()}.$2`);
189 let link = document.createElement('a');
190 let url = URL.createObjectURL(blob);
192 link.download = filename;
193 link.style.display = 'none';
194 document.body.appendChild(link);
196 setTimeout(function(){
197 document.body.removeChild(link);
198 URL.revokeObjectURL(url);
202 function migrateSoftwareProduct(vspId, version) {
203 return RestAPIUtil.put(`${baseUrl()}${vspId}/versions/${version.id}/heal`);
206 function adjustMinorVersion(version, value) {
207 let ar = version.split('.');
208 return ar[0] + '.' + (parseInt(ar[1]) + value);
211 function adjustMajorVersion(version, value) {
212 let ar = version.split('.');
213 return (parseInt(ar[0]) + value) + '.0';
216 const SoftwareProductActionHelper = {
218 fetchFinalizedSoftwareProductList(dispatch) {
219 return fetchFinalizedSoftwareProductList().then(response => dispatch({
220 type: actionTypes.FINALIZED_SOFTWARE_PRODUCT_LIST_LOADED,
225 loadSoftwareProductAssociatedData(dispatch) {
226 fetchSoftwareProductCategories(dispatch);
227 LicenseModelActionHelper.fetchFinalizedLicenseModels(dispatch);
230 loadSoftwareProductDetailsData(dispatch, {licenseModelId, licensingVersion}) {
231 SoftwareProductActionHelper.loadSoftwareProductAssociatedData(dispatch);
232 return loadLicensingData(dispatch, {licenseModelId, licensingVersion});
235 fetchSoftwareProductList(dispatch) {
236 return fetchSoftwareProductList().then(response => dispatch({
237 type: actionTypes.SOFTWARE_PRODUCT_LIST_LOADED,
242 loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version}){
243 return RestAPIUtil.fetch(`${baseUrl()}${softwareProductId}/versions/${version.id}/orchestration-template-candidate/manifest`).then(response => dispatch({
244 type: HeatSetupActions.MANIFEST_LOADED,
249 updateSoftwareProductHeatCandidate(dispatch, {softwareProductId, heatCandidate, version}){
250 return updateSoftwareProductHeatCandidate(softwareProductId, heatCandidate, version);
253 processAndValidateHeatCandidate(dispatch, {softwareProductId, version}){
254 return validateHeatCandidate(softwareProductId, version).then(response => {
255 if (response.status === 'Success') {
256 SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version});
257 SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, {softwareProductId, version});
262 uploadFile(dispatch, {softwareProductId, formData, failedNotificationTitle, version}) {
264 type: HeatSetupActions.FILL_HEAT_SETUP_CACHE,
269 .then(() => uploadFile(softwareProductId, formData, version))
271 if (response.status === 'Success') {
273 type: commonActionTypes.DATA_CHANGED,
274 deltaData: {onboardingOrigin: response.onboardingOrigin},
275 formName: forms.VENDOR_SOFTWARE_PRODUCT_DETAILS
277 switch(response.onboardingOrigin){
278 case onboardingOriginTypes.ZIP:
279 OnboardingActionHelper.navigateToSoftwareProductAttachmentsSetupTab(dispatch, {softwareProductId, version});
281 case onboardingOriginTypes.CSAR:
282 OnboardingActionHelper.navigateToSoftwareProductAttachmentsValidationTab(dispatch, {softwareProductId, version});
287 throw new Error(parseUploadErrorMsg(response.errors));
292 type: modalActionTypes.GLOBAL_MODAL_ERROR,
294 title: failedNotificationTitle,
301 downloadHeatFile(dispatch, {softwareProductId, heatCandidate, isReadOnlyMode, version}){
302 let p = isReadOnlyMode ? Promise.resolve() : SoftwareProductActionHelper.updateSoftwareProductHeatCandidate(dispatch, {softwareProductId, heatCandidate, version});
304 fetchOrchestrationTemplateCandidate(softwareProductId, version)
305 .then((blob, statusText, xhr) => showFileSaveDialog({blob, xhr, defaultFilename: 'HEAT_file.zip', addTimestamp: true}));
306 }, null/* do not download if data was not saved correctly*/);
309 hideUploadConfirm (dispatch) {
311 type: actionTypes.softwareProductEditor.UPLOAD_CONFIRMATION
314 updateSoftwareProduct(dispatch, {softwareProduct, qdata}) {
316 SoftwareProductActionHelper.updateSoftwareProductData(dispatch, {softwareProduct}).then(
318 type: actionTypes.SOFTWARE_PRODUCT_LIST_EDIT,
319 payload: {softwareProduct}
322 SoftwareProductActionHelper.updateSoftwareProductQuestionnaire(dispatch, {
323 softwareProductId: softwareProduct.id,
325 version: softwareProduct.version
330 updateSoftwareProductData(dispatch, {softwareProduct}) {
331 return putSoftwareProduct(softwareProduct);
334 updateSoftwareProductQuestionnaire(dispatch, {softwareProductId, qdata, version}) {
335 return putSoftwareProductQuestionnaire(softwareProductId, qdata, version);
338 softwareProductEditorDataChanged(dispatch, {deltaData}) {
340 type: actionTypes.softwareProductEditor.DATA_CHANGED,
345 softwareProductQuestionnaireUpdate(dispatch, {data}) {
347 type: actionTypes.SOFTWARE_PRODUCT_QUESTIONNAIRE_UPDATE,
348 payload: {qdata: data}
352 softwareProductEditorVendorChanged(dispatch, {deltaData, formName}) {
353 if (deltaData.licensingVersion.id){
354 let p = Promise.all([
355 LicenseAgreementActionHelper.fetchLicenseAgreementList(dispatch, {
356 licenseModelId: deltaData.vendorId,
357 version: {id: deltaData.licensingVersion.id}
359 FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, {
360 licenseModelId: deltaData.vendorId,
361 version: {id: deltaData.licensingVersion.id}
364 ValidationHelper.dataChanged(dispatch, {deltaData, formName});
367 ValidationHelper.dataChanged(dispatch, {deltaData, formName});
370 type: licenseAgreementActionTypes.LICENSE_AGREEMENT_LIST_LOADED,
371 response: {results: []}
375 type: featureGroupsActionConstants.FEATURE_GROUPS_LIST_LOADED,
376 response: {results: []}
382 setIsValidityData(dispatch, {isValidityData}) {
384 type: actionTypes.softwareProductEditor.IS_VALIDITY_DATA_CHANGED,
389 addSoftwareProduct(dispatch, {softwareProduct}) {
391 type: actionTypes.ADD_SOFTWARE_PRODUCT,
396 fetchSoftwareProduct(dispatch, {softwareProductId, version}) {
398 fetchSoftwareProduct(softwareProductId, version).then(response => {
400 type: actionTypes.SOFTWARE_PRODUCT_LOADED,
405 fetchSoftwareProductQuestionnaire(softwareProductId, version).then(response => {
406 ValidationHelper.qDataLoaded(dispatch, {response: {qdata: response.data ? JSON.parse(response.data) : {},
407 qschema: JSON.parse(response.schema)}, qName: PRODUCT_QUESTIONNAIRE});
412 performVCAction(dispatch, {softwareProductId, action, version}) {
413 if (action === VersionControllerActionsEnum.SUBMIT) {
414 return putSoftwareProductAction(softwareProductId, action, version).then(() => {
415 return putSoftwareProductAction(softwareProductId, VersionControllerActionsEnum.CREATE_PACKAGE, version).then(() => {
417 type: modalActionTypes.GLOBAL_MODAL_SUCCESS,
419 title: i18n('Submit Succeeded'),
420 msg: i18n('This software product successfully submitted'),
421 cancelButtonText: i18n('OK'),
425 const newVersionId = adjustMajorVersion(version.label, 1);
426 OnboardingActionHelper.updateCurrentScreenVersion(dispatch, {label: newVersionId, id: newVersionId});
427 SoftwareProductActionHelper.fetchSoftwareProduct(dispatch,{softwareProductId, version: {id: newVersionId}});
428 return Promise.resolve({newVersion: {id: newVersionId}});
430 }, error => dispatch({
431 type: modalActionTypes.GLOBAL_MODAL_ERROR,
433 modalComponentName: modalContentMapper.SUMBIT_ERROR_RESPONSE,
434 title: i18n('Submit Failed'),
435 modalComponentProps: {
436 validationResponse: error.responseJSON
438 cancelButtonText: i18n('Ok')
443 return putSoftwareProductAction(softwareProductId, action, version).then(() => {
444 let newVersionId = version.id;
446 TODO Temorary switch to change version label
449 case VersionControllerActionsEnum.CHECK_OUT:
450 newVersionId = adjustMinorVersion(version.label, 1);
452 case VersionControllerActionsEnum.UNDO_CHECK_OUT:
453 newVersionId = adjustMinorVersion(version.label, -1);
456 OnboardingActionHelper.updateCurrentScreenVersion(dispatch, {label: newVersionId, id: newVersionId});
457 SoftwareProductActionHelper.fetchSoftwareProduct(dispatch,{softwareProductId, version:{id: newVersionId}});
458 return Promise.resolve({newVersion: {id: newVersionId}});
463 switchVersion(dispatch, {softwareProductId, licenseModelId, version}) {
464 OnboardingActionHelper.navigateToSoftwareProductLandingPage(dispatch, {
471 toggleNavigationItems(dispatch, {items, itemIdToExpand}) {
472 let mapOfExpandedIds = getExpandedItemsId(items, itemIdToExpand);
474 type: actionTypes.TOGGLE_NAVIGATION_ITEM,
479 /** for the next verision */
480 addComponent(dispatch, {softwareProductId, modalClassName}) {
481 SoftwareProductComponentsActionHelper.clearComponentCreationData(dispatch);
483 type: componentActionTypes.COMPONENT_CREATE_OPEN
486 type: modalActionTypes.GLOBAL_MODAL_SHOW,
488 modalComponentName: modalContentMapper.COMPONENT_CREATION,
489 modalComponentProps: {softwareProductId},
491 title: 'Create Virtual Function Component'
496 migrateSoftwareProduct(dispatch, {softwareProduct}) {
497 let {licenseModelId, licensingVersion, id: softwareProductId, version, status} = softwareProduct;
498 const newVer = status === statusEnum.CHECK_IN_STATUS || status === statusEnum.SUBMIT_STATUS ?
499 adjustMinorVersion(version.id, 1) : version.id;
500 migrateSoftwareProduct(softwareProductId, version)
501 .then(() =>OnboardingActionHelper.navigateToSoftwareProductLandingPage(dispatch,
502 {softwareProductId, version: {id: newVer, label: newVer}, licenseModelId, licensingVersion}));
507 export default SoftwareProductActionHelper;