2 * Copyright © 2016-2018 European Support Limited
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 showFileSaveDialog from 'nfvo-utils/ShowFileSaveDialog.js';
18 import Configuration from 'sdc-app/config/Configuration.js';
19 import i18n from 'nfvo-utils/i18n/i18n.js';
20 import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js';
21 import LicenseAgreementActionHelper from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js';
22 import FeatureGroupsActionHelper from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js';
26 onboardingOriginTypes,
27 PRODUCT_QUESTIONNAIRE,
29 } from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
30 import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js';
31 import SoftwareProductComponentsActionHelper from './components/SoftwareProductComponentsActionHelper.js';
32 import { actionsEnum as VersionControllerActionsEnum } from 'nfvo-components/panel/versionController/VersionControllerConstants.js';
33 import { actionTypes as HeatSetupActions } from 'sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupConstants.js';
34 import { actionTypes as featureGroupsActionConstants } from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConstants.js';
35 import { actionTypes as licenseAgreementActionTypes } from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js';
36 import { actionTypes as componentActionTypes } from './components/SoftwareProductComponentsConstants.js';
37 import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
38 import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js';
39 import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js';
40 import { default as ItemsHelper } from 'sdc-app/common/helpers/ItemsHelper.js';
41 import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js';
42 import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js';
43 import MergeEditorActionHelper from 'sdc-app/common/merge/MergeEditorActionHelper.js';
44 import { CommitModalType } from 'nfvo-components/panel/versionController/components/CommitCommentModal.jsx';
45 import { actionTypes as commonActionTypes } from 'sdc-app/common/reducers/PlainDataReducerConstants.js';
46 import versionPageActionHelper from 'sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js';
47 import { itemTypes } from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js';
48 import getValue from 'nfvo-utils/getValue.js';
52 } from 'sdc-app/common/helpers/ItemsHelperConstants.js';
54 function getLicensingData(licensingData = {}) {
55 const { licenseAgreement, featureGroups } = licensingData;
56 const newlicenseAgreement = getValue(licenseAgreement);
57 const newfeatureGroups = getValue(featureGroups);
58 return newlicenseAgreement
60 licenseAgreement: newlicenseAgreement,
61 featureGroups: newfeatureGroups
67 const restPrefix = Configuration.get('restPrefix');
68 return `${restPrefix}/v1.0/vendor-software-products/`;
70 function softwareProductCategoriesUrl() {
71 const restCatalogPrefix = Configuration.get('restCatalogPrefix');
72 return `${restCatalogPrefix}/v1/categories/resources/`;
75 function uploadFile(vspId, formData, version) {
76 return RestAPIUtil.post(
77 `${baseUrl()}${vspId}/versions/${
79 }/orchestration-template-candidate`,
84 function putSoftwareProduct({ softwareProduct, version }) {
85 return RestAPIUtil.put(
86 `${baseUrl()}${softwareProduct.id}/versions/${version.id}`,
88 name: softwareProduct.name,
89 description: softwareProduct.description,
90 category: softwareProduct.category,
91 subCategory: softwareProduct.subCategory,
92 vendorId: softwareProduct.vendorId,
93 vendorName: softwareProduct.vendorName,
94 licensingVersion: softwareProduct.licensingVersion
95 ? softwareProduct.licensingVersion
97 icon: softwareProduct.icon,
98 licensingData: getLicensingData(softwareProduct.licensingData)
103 function putSoftwareProductQuestionnaire(vspId, qdata, version) {
104 return RestAPIUtil.put(
105 `${baseUrl()}${vspId}/versions/${version.id}/questionnaire`,
110 function putSoftwareProductAction(id, action, version) {
111 return RestAPIUtil.put(`${baseUrl()}${id}/versions/${version.id}/actions`, {
116 function fetchSoftwareProductList() {
117 return RestAPIUtil.fetch(
118 `${baseUrl()}?versionFilter=${versionStatus.DRAFT}`
122 function fetchArchivedSoftwareProductList() {
123 return RestAPIUtil.fetch(`${baseUrl()}?Status=${itemStatus.ARCHIVED}`);
126 function fetchFinalizedSoftwareProductList() {
127 return RestAPIUtil.fetch(
128 `${baseUrl()}?versionFilter=${versionStatus.CERTIFIED}`
132 function fetchSoftwareProduct(vspId, version) {
133 return RestAPIUtil.fetch(`${baseUrl()}${vspId}/versions/${version.id}`);
136 function fetchSoftwareProductQuestionnaire(vspId, version) {
137 return RestAPIUtil.fetch(
138 `${baseUrl()}${vspId}/versions/${version.id}/questionnaire`
142 function updateSoftwareProductHeatCandidate(
147 return RestAPIUtil.put(
148 `${baseUrl()}${softwareProductId}/versions/${
150 }/orchestration-template-candidate/manifest`,
154 function validateHeatCandidate(softwareProductId, version) {
155 return RestAPIUtil.put(
156 `${baseUrl()}${softwareProductId}/versions/${
158 }/orchestration-template-candidate/process`
162 function fetchOrchestrationTemplateCandidate(softwareProductId, version) {
163 return RestAPIUtil.fetch(
164 `${baseUrl()}${softwareProductId}/versions/${
166 }/orchestration-template-candidate`,
167 { dataType: 'binary' }
171 function abortValidationProcess(softwareProductId, version) {
172 return RestAPIUtil.destroy(
173 `${baseUrl()}${softwareProductId}/versions/${
175 }/orchestration-template-candidate`
179 function objToString(obj) {
181 if (obj instanceof Array) {
182 obj.forEach(item => {
183 str += objToString(item) + '\n';
187 if (obj.hasOwnProperty(p)) {
188 str += obj[p] + '\n';
192 return str.replace(/\n$/, '');
195 function parseUploadErrorMsg(error) {
197 for (let key in error) {
198 if (error.hasOwnProperty(key)) {
199 message += objToString(error[key]) + '\n';
202 return message.replace(/\n$/, '');
205 function fetchSoftwareProductCategories(dispatch) {
206 let handleResponse = response =>
208 type: actionTypes.SOFTWARE_PRODUCT_CATEGORIES_LOADED,
209 softwareProductCategories: response
211 return RestAPIUtil.fetch(softwareProductCategoriesUrl())
212 .then(handleResponse)
213 .catch(() => handleResponse(null));
216 function loadLicensingData(dispatch, { licenseModelId, licensingVersion }) {
217 return ItemsHelper.fetchVersion({
218 itemId: licenseModelId,
219 versionId: licensingVersion
222 LicenseAgreementActionHelper.fetchLicenseAgreementList(dispatch, {
224 version: { id: licensingVersion }
226 FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, {
228 version: { id: licensingVersion }
234 function getExpandedItemsId(items, itemIdToToggle) {
235 for (let i = 0; i < items.length; i++) {
236 if (items[i].id === itemIdToToggle) {
237 if (items[i].expanded) {
240 return { [itemIdToToggle]: true };
242 } else if (items[i].items && items[i].items.length > 0) {
243 let mapOfExpandedIds = getExpandedItemsId(
247 if (mapOfExpandedIds !== false) {
248 mapOfExpandedIds[items[i].id] = true;
249 return mapOfExpandedIds;
256 function migrateSoftwareProduct(vspId, version) {
257 return RestAPIUtil.put(`${baseUrl()}${vspId}/versions/${version.id}/heal`);
260 const SoftwareProductActionHelper = {
261 fetchFinalizedSoftwareProductList(dispatch) {
262 return fetchFinalizedSoftwareProductList().then(response =>
264 type: actionTypes.FINALIZED_SOFTWARE_PRODUCT_LIST_LOADED,
270 fetchArchivedSoftwareProductList(dispatch) {
271 return fetchArchivedSoftwareProductList().then(response =>
273 type: actionTypes.ARCHIVED_SOFTWARE_PRODUCT_LIST_LOADED,
279 loadSoftwareProductAssociatedData(dispatch) {
280 fetchSoftwareProductCategories(dispatch);
281 LicenseModelActionHelper.fetchFinalizedLicenseModels(dispatch);
284 loadSoftwareProductDetailsData(
286 { licenseModelId, licensingVersion }
288 SoftwareProductActionHelper.loadSoftwareProductAssociatedData(dispatch);
289 if (licensingVersion) {
290 return loadLicensingData(dispatch, {
295 return Promise.resolve();
298 fetchSoftwareProductList(dispatch) {
299 return fetchSoftwareProductList().then(response =>
301 type: actionTypes.SOFTWARE_PRODUCT_LIST_LOADED,
307 loadSoftwareProductHeatCandidate(dispatch, { softwareProductId, version }) {
308 return RestAPIUtil.fetch(
309 `${baseUrl()}${softwareProductId}/versions/${
311 }/orchestration-template-candidate/manifest`
314 type: HeatSetupActions.MANIFEST_LOADED,
320 loadLicensingVersionsList(dispatch, { licenseModelId }) {
321 return ItemsHelper.fetchVersions({ itemId: licenseModelId }).then(
324 type: actionTypes.LOAD_LICENSING_VERSIONS_LIST,
325 licensingVersionsList: response.results
330 updateSoftwareProductHeatCandidate(
332 { softwareProductId, heatCandidate, version }
334 return updateSoftwareProductHeatCandidate(
341 processAndValidateHeatCandidate(dispatch, { softwareProductId, version }) {
342 return validateHeatCandidate(softwareProductId, version).then(
344 if (response.status === 'Success') {
345 SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(
347 { softwareProductId, version }
349 SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, {
354 SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, {
365 { softwareProductId, formData, failedNotificationTitle, version }
368 type: HeatSetupActions.FILL_HEAT_SETUP_CACHE,
373 .then(() => uploadFile(softwareProductId, formData, version))
375 if (response.status === 'Success') {
377 type: commonActionTypes.DATA_CHANGED,
379 onboardingOrigin: response.onboardingOrigin
381 formName: forms.VENDOR_SOFTWARE_PRODUCT_DETAILS
383 switch (response.onboardingOrigin) {
384 case onboardingOriginTypes.ZIP:
385 ScreensHelper.loadScreen(dispatch, {
388 .SOFTWARE_PRODUCT_ATTACHMENTS_SETUP,
389 screenType: screenTypes.SOFTWARE_PRODUCT,
390 props: { softwareProductId, version }
393 type: actionTypes.CANDIDATE_IN_PROCESS,
397 case onboardingOriginTypes.CSAR:
398 ScreensHelper.loadScreen(dispatch, {
401 .SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION,
402 screenType: screenTypes.SOFTWARE_PRODUCT,
403 props: { softwareProductId, version }
408 throw new Error(parseUploadErrorMsg(response.errors));
413 type: modalActionTypes.GLOBAL_MODAL_ERROR,
415 title: failedNotificationTitle,
418 (error.responseJSON && error.responseJSON.message)
426 { softwareProductId, heatCandidate, isReadOnlyMode, version }
428 let p = isReadOnlyMode
430 : SoftwareProductActionHelper.updateSoftwareProductHeatCandidate(
439 fetchOrchestrationTemplateCandidate(
445 headers: response.headers,
446 defaultFilename: 'HEAT_file.zip',
450 }, null /* do not download if data was not saved correctly*/);
453 hideUploadConfirm(dispatch) {
455 type: actionTypes.softwareProductEditor.UPLOAD_CONFIRMATION
458 updateSoftwareProduct(dispatch, { softwareProduct, version, qdata }) {
460 SoftwareProductActionHelper.updateSoftwareProductData(dispatch, {
465 type: actionTypes.SOFTWARE_PRODUCT_LIST_EDIT,
466 payload: { softwareProduct }
469 SoftwareProductActionHelper.updateSoftwareProductQuestionnaire(
472 softwareProductId: softwareProduct.id,
480 updateSoftwareProductData(dispatch, { softwareProduct, version }) {
481 return putSoftwareProduct({ softwareProduct, version });
484 updateSoftwareProductQuestionnaire(
486 { softwareProductId, qdata, version }
488 return putSoftwareProductQuestionnaire(
495 softwareProductEditorDataChanged(dispatch, { deltaData }) {
497 type: actionTypes.softwareProductEditor.DATA_CHANGED,
502 softwareProductQuestionnaireUpdate(dispatch, { data }) {
504 type: actionTypes.SOFTWARE_PRODUCT_QUESTIONNAIRE_UPDATE,
505 payload: { qdata: data }
509 softwareProductEditorVendorChanged(dispatch, { deltaData, formName }) {
510 if (deltaData.licensingVersion) {
511 return loadLicensingData(dispatch, {
512 licenseModelId: deltaData.vendorId,
513 licensingVersion: deltaData.licensingVersion
515 ValidationHelper.dataChanged(dispatch, { deltaData, formName });
516 return Promise.resolve();
518 } else if (deltaData.vendorId) {
519 ValidationHelper.dataChanged(dispatch, { deltaData, formName });
520 return SoftwareProductActionHelper.loadLicensingVersionsList(
523 licenseModelId: deltaData.vendorId
526 OnboardingActionHelper.forceBreadCrumbsUpdate(dispatch)
529 ValidationHelper.dataChanged(dispatch, { deltaData, formName });
532 type: licenseAgreementActionTypes.LICENSE_AGREEMENT_LIST_LOADED,
533 response: { results: [] }
537 type: featureGroupsActionConstants.FEATURE_GROUPS_LIST_LOADED,
538 response: { results: [] }
543 setIsValidityData(dispatch, { isValidityData }) {
545 type: actionTypes.softwareProductEditor.IS_VALIDITY_DATA_CHANGED,
550 fetchSoftwareProduct(dispatch, { softwareProductId, version }) {
552 fetchSoftwareProduct(softwareProductId, version).then(response => {
554 type: actionTypes.SOFTWARE_PRODUCT_LOADED,
559 fetchSoftwareProductQuestionnaire(softwareProductId, version).then(
561 ValidationHelper.qDataLoaded(dispatch, {
564 ? JSON.parse(response.data)
566 qschema: JSON.parse(response.schema)
568 qName: PRODUCT_QUESTIONNAIRE
575 manageSubmitAction(dispatch, { softwareProductId, version, isDirty }) {
577 const onCommit = comment => {
578 return this.performVCAction(dispatch, {
580 action: VersionControllerActionsEnum.COMMIT,
584 return this.performSubmitAction(dispatch, {
591 type: modalActionTypes.GLOBAL_MODAL_SHOW,
593 modalComponentName: modalContentMapper.COMMIT_COMMENT,
594 modalComponentProps: {
596 type: CommitModalType.COMMIT_SUBMIT
598 title: i18n('Commit & Submit')
601 return Promise.resolve(version);
603 return this.performSubmitAction(dispatch, {
609 performSubmitAction(dispatch, { softwareProductId, version }) {
610 return putSoftwareProductAction(
612 VersionControllerActionsEnum.SUBMIT,
616 return putSoftwareProductAction(
618 VersionControllerActionsEnum.CREATE_PACKAGE,
621 return ItemsHelper.checkItemStatus(dispatch, {
622 itemId: softwareProductId,
623 versionId: version.id
624 }).then(updatedVersion => {
626 type: modalActionTypes.GLOBAL_MODAL_SUCCESS,
628 title: i18n('Submit Succeeded'),
630 'This software product successfully submitted'
632 cancelButtonText: i18n('OK'),
636 versionPageActionHelper.fetchVersions(dispatch, {
637 itemType: itemTypes.SOFTWARE_PRODUCT,
638 itemId: softwareProductId
640 return Promise.resolve(updatedVersion);
646 type: modalActionTypes.GLOBAL_MODAL_ERROR,
649 modalContentMapper.SUMBIT_ERROR_RESPONSE,
650 title: i18n('Submit Failed'),
651 modalComponentProps: {
652 validationResponse: error.responseJSON
654 cancelButtonText: i18n('OK')
657 return Promise.reject(error.responseJSON);
662 performVCAction(dispatch, { softwareProductId, action, version, comment }) {
663 return MergeEditorActionHelper.analyzeSyncResult(dispatch, {
664 itemId: softwareProductId,
666 }).then(({ inMerge, isDirty, updatedVersion }) => {
668 (updatedVersion.status === versionStatus.CERTIFIED ||
669 updatedVersion.archivedStatus === itemStatus.ARCHIVED) &&
670 (action === VersionControllerActionsEnum.COMMIT ||
671 action === VersionControllerActionsEnum.SYNC)
673 versionPageActionHelper.fetchVersions(dispatch, {
674 itemType: itemTypes.SOFTWARE_PRODUCT,
675 itemId: softwareProductId
678 updatedVersion.archivedStatus === itemStatus.ARCHIVED
679 ? i18n('Item was Archived')
680 : i18n('Item version already Certified');
682 type: modalActionTypes.GLOBAL_MODAL_WARNING,
684 title: i18n('Commit error'),
686 cancelButtonText: i18n('Cancel')
689 return Promise.resolve(updatedVersion);
692 if (action === VersionControllerActionsEnum.SUBMIT) {
693 return this.manageSubmitAction(dispatch, {
699 let isCallActionValid =
700 action !== VersionControllerActionsEnum.COMMIT ||
702 if (isCallActionValid) {
703 return ItemsHelper.performVCAction({
704 itemId: softwareProductId,
709 versionPageActionHelper.fetchVersions(dispatch, {
710 itemType: itemTypes.LICENSE_MODEL,
711 itemId: softwareProductId
713 if (action === VersionControllerActionsEnum.SYNC) {
714 return MergeEditorActionHelper.analyzeSyncResult(
716 { itemId: softwareProductId, version }
717 ).then(({ updatedVersion }) => {
718 return Promise.resolve(updatedVersion);
721 return ItemsHelper.checkItemStatus(dispatch, {
722 itemId: softwareProductId,
723 versionId: version.id
729 type: modalActionTypes.GLOBAL_MODAL_ERROR,
731 title: i18n('Commit Failed'),
732 msg: i18n('There is nothing to commit')
741 toggleNavigationItems(dispatch, { items, itemIdToExpand }) {
742 let mapOfExpandedIds = getExpandedItemsId(items, itemIdToExpand);
744 type: actionTypes.TOGGLE_NAVIGATION_ITEM,
749 /** for the next verision */
750 addComponent(dispatch, { softwareProductId, modalClassName, version }) {
751 SoftwareProductComponentsActionHelper.clearComponentCreationData(
755 type: componentActionTypes.COMPONENT_CREATE_OPEN
758 type: modalActionTypes.GLOBAL_MODAL_SHOW,
760 modalComponentName: modalContentMapper.COMPONENT_CREATION,
761 modalComponentProps: { softwareProductId, version },
763 title: 'Create Virtual Function Component'
768 migrateSoftwareProduct(dispatch, { softwareProduct }) {
769 let { id: softwareProductId, version } = softwareProduct;
770 const newVer = version.id;
771 migrateSoftwareProduct(softwareProductId, version).then(() =>
772 ScreensHelper.loadScreen(dispatch, {
773 screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE,
774 screenType: screenTypes.SOFTWARE_PRODUCT,
777 version: { id: newVer, label: newVer }
783 abortCandidateValidation(dispatch, { softwareProductId, version }) {
784 return abortValidationProcess(softwareProductId, version);
788 export default SoftwareProductActionHelper;