2 * Copyright © 2016-2018 European Support Limited
3 * Modifications copyright (c) 2021 Nokia
4 * Modifications Copyright (C) 2021 Nordix Foundation.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
15 * or implied. See the License for the specific language governing
16 * permissions and limitations under the License.
18 import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js';
19 import showFileSaveDialog from 'nfvo-utils/ShowFileSaveDialog.js';
20 import Configuration from 'sdc-app/config/Configuration.js';
21 import i18n from 'nfvo-utils/i18n/i18n.js';
22 import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js';
23 import LicenseAgreementActionHelper from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js';
24 import FeatureGroupsActionHelper from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js';
28 onboardingOriginTypes,
29 PRODUCT_QUESTIONNAIRE,
31 } from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
32 import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js';
33 import SoftwareProductComponentsActionHelper from './components/SoftwareProductComponentsActionHelper.js';
34 import { actionsEnum as VersionControllerActionsEnum } from 'nfvo-components/panel/versionController/VersionControllerConstants.js';
35 import { actionTypes as HeatSetupActions } from 'sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupConstants.js';
36 import { actionTypes as featureGroupsActionConstants } from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConstants.js';
37 import { actionTypes as licenseAgreementActionTypes } from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js';
38 import { actionTypes as componentActionTypes } from './components/SoftwareProductComponentsConstants.js';
39 import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
40 import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js';
41 import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js';
42 import { default as ItemsHelper } from 'sdc-app/common/helpers/ItemsHelper.js';
43 import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js';
44 import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js';
45 import MergeEditorActionHelper from 'sdc-app/common/merge/MergeEditorActionHelper.js';
46 import { CommitModalType } from 'nfvo-components/panel/versionController/components/CommitCommentModal.jsx';
47 import { actionTypes as commonActionTypes } from 'sdc-app/common/reducers/PlainDataReducerConstants.js';
48 import versionPageActionHelper from 'sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js';
49 import { itemTypes } from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js';
50 import getValue from 'nfvo-utils/getValue.js';
54 } from 'sdc-app/common/helpers/ItemsHelperConstants.js';
56 let shouldDisplayTimingValidationInfo = true;
57 let alertValidationTiming = Configuration.get(
58 'displayAlertValidationAfterMilisec'
61 function getLicensingData(licensingData = {}) {
62 const { licenseAgreement, featureGroups } = licensingData;
63 const newlicenseAgreement = getValue(licenseAgreement);
64 const newfeatureGroups = getValue(featureGroups);
65 return newlicenseAgreement
67 licenseAgreement: newlicenseAgreement,
68 featureGroups: newfeatureGroups
73 function getTimingInfoWarning() {
75 type: modalActionTypes.GLOBAL_MODAL_WARNING,
77 title: 'Please be patient',
78 msg: 'Large files processing may take up to several minutes.',
79 cancelButtonText: 'OK'
84 function displayTimingValidationInfo(dispatch) {
85 shouldDisplayTimingValidationInfo = true;
87 if (shouldDisplayTimingValidationInfo) {
88 dispatch(getTimingInfoWarning());
90 }, alertValidationTiming);
93 function closeTimingValidationInfo(dispatch) {
94 shouldDisplayTimingValidationInfo = false;
96 type: modalActionTypes.GLOBAL_MODAL_CLOSE
101 const restPrefix = Configuration.get('restPrefix');
102 return `${restPrefix}/v1.0/vendor-software-products/`;
105 function softwareProductCategoriesUrl() {
106 const restCatalogPrefix = Configuration.get('restCatalogPrefix');
107 return `${restCatalogPrefix}/v1/categories/resources/`;
110 function getModelUrl() {
111 const restCatalogPrefix = Configuration.get('restCatalogPrefix');
112 return `${restCatalogPrefix}/v1/catalog/model?modelType=normative`;
115 function uploadFile(vspId, formData, version, onUploadProgress = undefined) {
119 if (onUploadProgress) {
120 options.onUploadProgress = onUploadProgress;
122 return RestAPIUtil.post(
123 `${baseUrl()}${vspId}/versions/${
125 }/orchestration-template-candidate`,
131 function uploadVNFFile(csarId, softwareProductId, version) {
132 let verId = typeof version === 'object' ? version.id : version;
133 return RestAPIUtil.post(
134 `${baseUrl()}${softwareProductId}/versions/${verId}/vnfrepository/vnfpackage/${csarId}/import`
137 function putSoftwareProduct({ softwareProduct, version }) {
138 return RestAPIUtil.put(
139 `${baseUrl()}${softwareProduct.id}/versions/${version.id}`,
141 name: softwareProduct.name,
142 description: softwareProduct.description,
143 category: softwareProduct.category,
144 subCategory: softwareProduct.subCategory,
145 vendorId: softwareProduct.vendorId,
146 vendorName: softwareProduct.vendorName,
147 licensingVersion: softwareProduct.licensingVersion
148 ? softwareProduct.licensingVersion
150 icon: softwareProduct.icon,
151 licenseType: softwareProduct.licenseType,
152 selectedModelList: softwareProduct.selectedModelList,
153 licensingData: getLicensingData(softwareProduct.licensingData)
158 function putSoftwareProductQuestionnaire(vspId, qdata, version) {
159 return RestAPIUtil.put(
160 `${baseUrl()}${vspId}/versions/${version.id}/questionnaire`,
165 function putSoftwareProductAction(id, action, version) {
166 return RestAPIUtil.put(`${baseUrl()}${id}/versions/${version.id}/actions`, {
171 function fetchSoftwareProductList() {
172 return RestAPIUtil.fetch(
173 `${baseUrl()}?versionFilter=${versionStatus.DRAFT}`
177 function fetchArchivedSoftwareProductList() {
178 return RestAPIUtil.fetch(`${baseUrl()}?Status=${itemStatus.ARCHIVED}`);
181 function fetchFinalizedSoftwareProductList() {
182 return RestAPIUtil.fetch(
183 `${baseUrl()}?versionFilter=${versionStatus.CERTIFIED}`
187 function fetchSoftwareProduct(vspId, version) {
188 return RestAPIUtil.fetch(`${baseUrl()}${vspId}/versions/${version.id}`);
191 function fetchSoftwareProductQuestionnaire(vspId, version) {
192 return RestAPIUtil.fetch(
193 `${baseUrl()}${vspId}/versions/${version.id}/questionnaire`
197 function updateSoftwareProductHeatCandidate(
202 return RestAPIUtil.put(
203 `${baseUrl()}${softwareProductId}/versions/${
205 }/orchestration-template-candidate/manifest`,
209 function validateHeatCandidate(softwareProductId, version) {
210 return RestAPIUtil.put(
211 `${baseUrl()}${softwareProductId}/versions/${
213 }/orchestration-template-candidate/process`
217 function fetchOrchestrationTemplateCandidate(softwareProductId, version) {
218 return RestAPIUtil.fetch(
219 `${baseUrl()}${softwareProductId}/versions/${
221 }/orchestration-template-candidate`,
222 { dataType: 'binary' }
226 function abortValidationProcess(softwareProductId, version) {
227 return RestAPIUtil.destroy(
228 `${baseUrl()}${softwareProductId}/versions/${
230 }/orchestration-template-candidate`
234 function objToString(obj) {
236 if (obj instanceof Array) {
237 obj.forEach(item => {
238 str += objToString(item) + '\n';
242 if (obj.hasOwnProperty(p)) {
243 str += obj[p] + '\n';
247 return str.replace(/\n$/, '');
250 function parseUploadErrorMsg(error) {
252 for (let key in error) {
253 if (error.hasOwnProperty(key)) {
254 message += objToString(error[key]) + '\n';
257 return message.replace(/\n$/, '');
260 function showWarningValidationInfo(dispatch, errors) {
262 type: modalActionTypes.GLOBAL_MODAL_WARNING,
264 title: 'Validation messages',
265 msg: parseUploadErrorMsg(errors),
266 cancelButtonText: 'OK'
271 function fetchSoftwareProductCategories(dispatch) {
272 let handleResponse = response =>
274 type: actionTypes.SOFTWARE_PRODUCT_CATEGORIES_LOADED,
275 softwareProductCategories: response
277 return RestAPIUtil.fetch(softwareProductCategoriesUrl())
278 .then(handleResponse)
279 .catch(() => handleResponse(null));
282 function fetchModelList(dispatch) {
283 let handleResponse = response =>
285 type: actionTypes.SOFTWARE_PRODUCT_MODELS_LOADED,
288 RestAPIUtil.fetch(getModelUrl())
289 .then(handleResponse)
290 .catch(() => handleResponse(null));
293 function loadLicensingData(dispatch, { licenseModelId, licensingVersion }) {
294 return ItemsHelper.fetchVersion({
295 itemId: licenseModelId,
296 versionId: licensingVersion
299 LicenseAgreementActionHelper.fetchLicenseAgreementList(dispatch, {
301 version: { id: licensingVersion }
303 FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, {
305 version: { id: licensingVersion }
311 function getExpandedItemsId(items, itemIdToToggle) {
312 for (let i = 0; i < items.length; i++) {
313 if (items[i].id === itemIdToToggle) {
314 if (items[i].expanded) {
317 return { [itemIdToToggle]: true };
319 } else if (items[i].items && items[i].items.length > 0) {
320 let mapOfExpandedIds = getExpandedItemsId(
324 if (mapOfExpandedIds !== false) {
325 mapOfExpandedIds[items[i].id] = true;
326 return mapOfExpandedIds;
333 function migrateSoftwareProduct(vspId, version) {
334 return RestAPIUtil.put(`${baseUrl()}${vspId}/versions/${version.id}/heal`);
337 const SoftwareProductActionHelper = {
338 fetchFinalizedSoftwareProductList(dispatch) {
339 return fetchFinalizedSoftwareProductList().then(response =>
341 type: actionTypes.FINALIZED_SOFTWARE_PRODUCT_LIST_LOADED,
347 fetchArchivedSoftwareProductList(dispatch) {
348 return fetchArchivedSoftwareProductList().then(response =>
350 type: actionTypes.ARCHIVED_SOFTWARE_PRODUCT_LIST_LOADED,
356 fetchUploadStatus(vspId, versionId) {
358 validateStatus: function(status) {
359 return status < 400 || status === 404;
363 return RestAPIUtil.get(
364 `${baseUrl()}${vspId}/versions/${versionId}/orchestration-template-candidate/upload`,
369 createUploadStatus(vspId, versionId) {
373 return RestAPIUtil.post(
374 `${baseUrl()}${vspId}/versions/${versionId}/orchestration-template-candidate/upload`,
379 loadSoftwareProductAssociatedData(dispatch) {
380 fetchSoftwareProductCategories(dispatch);
381 fetchModelList(dispatch);
382 LicenseModelActionHelper.fetchFinalizedLicenseModels(dispatch);
385 loadSoftwareProductDetailsData(
387 { licenseModelId, licensingVersion }
389 SoftwareProductActionHelper.loadSoftwareProductAssociatedData(dispatch);
390 if (licensingVersion) {
391 return loadLicensingData(dispatch, {
396 return Promise.resolve();
399 fetchSoftwareProductList(dispatch) {
400 return fetchSoftwareProductList().then(response =>
402 type: actionTypes.SOFTWARE_PRODUCT_LIST_LOADED,
408 loadSoftwareProductHeatCandidate(dispatch, { softwareProductId, version }) {
409 return RestAPIUtil.fetch(
410 `${baseUrl()}${softwareProductId}/versions/${
412 }/orchestration-template-candidate/manifest`
415 type: HeatSetupActions.MANIFEST_LOADED,
421 loadLicensingVersionsList(dispatch, { licenseModelId }) {
422 return ItemsHelper.fetchVersions({ itemId: licenseModelId }).then(
425 type: actionTypes.LOAD_LICENSING_VERSIONS_LIST,
426 licensingVersionsList: response.results
431 updateSoftwareProductHeatCandidate(
433 { softwareProductId, heatCandidate, version }
435 return updateSoftwareProductHeatCandidate(
442 processAndValidateHeatCandidate(dispatch, { softwareProductId, version }) {
443 displayTimingValidationInfo(dispatch);
444 return validateHeatCandidate(softwareProductId, version).then(
446 if (response.status === 'Success') {
447 SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(
449 { softwareProductId, version }
451 SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, {
456 SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, {
461 closeTimingValidationInfo(dispatch);
471 failedNotificationTitle,
473 onUploadProgress = undefined
477 type: HeatSetupActions.FILL_HEAT_SETUP_CACHE,
480 return Promise.resolve()
490 if (response.status === 'Success') {
492 type: commonActionTypes.DATA_CHANGED,
494 onboardingOrigin: response.onboardingOrigin
496 formName: forms.VENDOR_SOFTWARE_PRODUCT_DETAILS
498 switch (response.onboardingOrigin) {
499 case onboardingOriginTypes.ZIP:
500 ScreensHelper.loadScreen(dispatch, {
503 .SOFTWARE_PRODUCT_ATTACHMENTS_SETUP,
504 screenType: screenTypes.SOFTWARE_PRODUCT,
505 props: { softwareProductId, version }
508 type: actionTypes.CANDIDATE_IN_PROCESS,
512 case onboardingOriginTypes.CSAR:
513 ScreensHelper.loadScreen(dispatch, {
516 .SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION,
517 screenType: screenTypes.SOFTWARE_PRODUCT,
518 props: { softwareProductId, version }
522 closeTimingValidationInfo(dispatch);
524 response.errors !== null &&
525 Object.keys(response.errors).length !== 0
527 showWarningValidationInfo(dispatch, response.errors);
530 throw new Error(parseUploadErrorMsg(response.errors));
536 type: modalActionTypes.GLOBAL_MODAL_ERROR,
538 title: failedNotificationTitle,
541 (error.responseJSON &&
542 error.responseJSON.message) ||
543 parseUploadErrorMsg(error.responseJSON.errors)
546 closeTimingValidationInfo(dispatch)
553 { csarId, failedNotificationTitle, softwareProductId, version }
556 type: HeatSetupActions.FILL_HEAT_SETUP_CACHE,
561 .then(() => uploadVNFFile(csarId, softwareProductId, version))
563 if (response.status === 'Success') {
565 type: commonActionTypes.DATA_CHANGED,
567 onboardingOrigin: response.onboardingOrigin
569 formName: forms.VENDOR_SOFTWARE_PRODUCT_DETAILS
571 switch (response.onboardingOrigin) {
572 case onboardingOriginTypes.ZIP:
573 OnboardingActionHelper.navigateToSoftwareProductAttachmentsSetupTab(
575 { softwareProductId, version }
578 case onboardingOriginTypes.CSAR:
579 OnboardingActionHelper.navigateToSoftwareProductAttachmentsValidationTab(
581 { softwareProductId, version }
586 throw new Error(parseUploadErrorMsg(response.errors));
591 type: modalActionTypes.GLOBAL_MODAL_ERROR,
593 title: failedNotificationTitle,
601 { softwareProductId, heatCandidate, isReadOnlyMode, version }
603 let p = isReadOnlyMode
605 : SoftwareProductActionHelper.updateSoftwareProductHeatCandidate(
614 fetchOrchestrationTemplateCandidate(
620 headers: response.headers,
621 defaultFilename: 'HEAT_file.zip',
625 }, null /* do not download if data was not saved correctly*/);
628 hideUploadConfirm(dispatch) {
630 type: actionTypes.softwareProductEditor.UPLOAD_CONFIRMATION
633 updateSoftwareProduct(dispatch, { softwareProduct, version, qdata }) {
635 SoftwareProductActionHelper.updateSoftwareProductData(dispatch, {
640 type: actionTypes.SOFTWARE_PRODUCT_LIST_EDIT,
641 payload: { softwareProduct }
644 SoftwareProductActionHelper.updateSoftwareProductQuestionnaire(
647 softwareProductId: softwareProduct.id,
655 updateSoftwareProductData(dispatch, { softwareProduct, version }) {
656 return putSoftwareProduct({ softwareProduct, version });
659 updateSoftwareProductQuestionnaire(
661 { softwareProductId, qdata, version }
663 return putSoftwareProductQuestionnaire(
670 softwareProductEditorDataChanged(dispatch, { deltaData }) {
672 type: actionTypes.softwareProductEditor.DATA_CHANGED,
677 softwareProductQuestionnaireUpdate(dispatch, { data }) {
679 type: actionTypes.SOFTWARE_PRODUCT_QUESTIONNAIRE_UPDATE,
680 payload: { qdata: data }
684 softwareProductEditorVendorChanged(dispatch, { deltaData, formName }) {
685 if (deltaData.licensingVersion) {
686 return loadLicensingData(dispatch, {
687 licenseModelId: deltaData.vendorId,
688 licensingVersion: deltaData.licensingVersion
690 ValidationHelper.dataChanged(dispatch, { deltaData, formName });
691 return Promise.resolve();
693 } else if (deltaData.vendorId) {
694 ValidationHelper.dataChanged(dispatch, { deltaData, formName });
695 return SoftwareProductActionHelper.loadLicensingVersionsList(
698 licenseModelId: deltaData.vendorId
701 OnboardingActionHelper.forceBreadCrumbsUpdate(dispatch)
704 ValidationHelper.dataChanged(dispatch, { deltaData, formName });
707 type: licenseAgreementActionTypes.LICENSE_AGREEMENT_LIST_LOADED,
708 response: { results: [] }
712 type: featureGroupsActionConstants.FEATURE_GROUPS_LIST_LOADED,
713 response: { results: [] }
718 setIsValidityData(dispatch, { isValidityData }) {
720 type: actionTypes.softwareProductEditor.IS_VALIDITY_DATA_CHANGED,
725 fetchSoftwareProduct(dispatch, { softwareProductId, version }) {
727 fetchSoftwareProduct(softwareProductId, version).then(response => {
729 type: actionTypes.SOFTWARE_PRODUCT_LOADED,
734 fetchSoftwareProductQuestionnaire(softwareProductId, version).then(
736 ValidationHelper.qDataLoaded(dispatch, {
739 ? JSON.parse(response.data)
741 qschema: JSON.parse(response.schema)
743 qName: PRODUCT_QUESTIONNAIRE
750 manageSubmitAction(dispatch, { softwareProductId, version, isDirty }) {
752 const onCommit = comment => {
753 return this.performVCAction(dispatch, {
755 action: VersionControllerActionsEnum.COMMIT,
759 return this.performSubmitAction(dispatch, {
766 type: modalActionTypes.GLOBAL_MODAL_SHOW,
768 modalComponentName: modalContentMapper.COMMIT_COMMENT,
769 modalComponentProps: {
771 type: CommitModalType.COMMIT_SUBMIT
773 title: i18n('Commit & Submit')
776 return Promise.resolve(version);
778 return this.performSubmitAction(dispatch, {
784 performSubmitAction(dispatch, { softwareProductId, version }) {
785 return putSoftwareProductAction(
787 VersionControllerActionsEnum.SUBMIT,
791 return putSoftwareProductAction(
793 VersionControllerActionsEnum.CREATE_PACKAGE,
796 return ItemsHelper.checkItemStatus(dispatch, {
797 itemId: softwareProductId,
798 versionId: version.id
799 }).then(updatedVersion => {
801 type: modalActionTypes.GLOBAL_MODAL_SUCCESS,
803 title: i18n('Submit Succeeded'),
805 'This software product successfully submitted'
807 cancelButtonText: i18n('OK'),
811 versionPageActionHelper.fetchVersions(dispatch, {
812 itemType: itemTypes.SOFTWARE_PRODUCT,
813 itemId: softwareProductId
815 return Promise.resolve(updatedVersion);
821 type: modalActionTypes.GLOBAL_MODAL_ERROR,
824 modalContentMapper.SUMBIT_ERROR_RESPONSE,
825 title: i18n('Submit Failed'),
826 modalComponentProps: {
827 validationResponse: error.responseJSON
829 cancelButtonText: i18n('OK')
832 return Promise.reject(error.responseJSON);
837 performVCAction(dispatch, { softwareProductId, action, version, comment }) {
838 return MergeEditorActionHelper.analyzeSyncResult(dispatch, {
839 itemId: softwareProductId,
841 }).then(({ inMerge, isDirty, updatedVersion }) => {
843 (updatedVersion.status === versionStatus.CERTIFIED ||
844 updatedVersion.archivedStatus === itemStatus.ARCHIVED) &&
845 (action === VersionControllerActionsEnum.COMMIT ||
846 action === VersionControllerActionsEnum.SYNC)
848 versionPageActionHelper.fetchVersions(dispatch, {
849 itemType: itemTypes.SOFTWARE_PRODUCT,
850 itemId: softwareProductId
853 updatedVersion.archivedStatus === itemStatus.ARCHIVED
854 ? i18n('Item was Archived')
855 : i18n('Item version already Certified');
857 type: modalActionTypes.GLOBAL_MODAL_WARNING,
859 title: i18n('Commit error'),
861 cancelButtonText: i18n('Cancel')
864 return Promise.resolve(updatedVersion);
867 if (action === VersionControllerActionsEnum.SUBMIT) {
868 return this.manageSubmitAction(dispatch, {
874 let isCallActionValid =
875 action !== VersionControllerActionsEnum.COMMIT ||
877 if (isCallActionValid) {
878 return ItemsHelper.performVCAction({
879 itemId: softwareProductId,
884 versionPageActionHelper.fetchVersions(dispatch, {
885 itemType: itemTypes.LICENSE_MODEL,
886 itemId: softwareProductId
888 if (action === VersionControllerActionsEnum.SYNC) {
889 return MergeEditorActionHelper.analyzeSyncResult(
891 { itemId: softwareProductId, version }
892 ).then(({ updatedVersion }) => {
893 return Promise.resolve(updatedVersion);
896 return ItemsHelper.checkItemStatus(dispatch, {
897 itemId: softwareProductId,
898 versionId: version.id
904 type: modalActionTypes.GLOBAL_MODAL_ERROR,
906 title: i18n('Commit Failed'),
907 msg: i18n('There is nothing to commit')
916 toggleNavigationItems(dispatch, { items, itemIdToExpand }) {
917 let mapOfExpandedIds = getExpandedItemsId(items, itemIdToExpand);
919 type: actionTypes.TOGGLE_NAVIGATION_ITEM,
924 /** for the next verision */
925 addComponent(dispatch, { softwareProductId, version }) {
926 SoftwareProductComponentsActionHelper.clearComponentCreationData(
930 type: componentActionTypes.COMPONENT_CREATE_OPEN
933 type: modalActionTypes.GLOBAL_MODAL_SHOW,
935 modalComponentName: modalContentMapper.COMPONENT_CREATION,
936 modalComponentProps: { softwareProductId, version },
937 title: 'Create Virtual Function Component'
942 migrateSoftwareProduct(dispatch, { softwareProduct }) {
943 let { id: softwareProductId, version } = softwareProduct;
944 const newVer = version.id;
945 migrateSoftwareProduct(softwareProductId, version).then(() =>
946 ScreensHelper.loadScreen(dispatch, {
947 screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE,
948 screenType: screenTypes.SOFTWARE_PRODUCT,
951 version: { id: newVer, label: newVer }
957 abortCandidateValidation(dispatch, { softwareProductId, version }) {
958 return abortValidationProcess(softwareProductId, version);
962 export default SoftwareProductActionHelper;