/*! * Copyright © 2016-2018 European Support Limited * * 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. */ import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; import TabulatedEditor from 'src/nfvo-components/editor/TabulatedEditor.jsx'; import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import { onboardingMethod as onboardingMethodTypes, onboardingOriginTypes } from './SoftwareProductConstants.js'; import SoftwareProductActionHelper from './SoftwareProductActionHelper.js'; import SoftwareProductComponentsActionHelper from './components/SoftwareProductComponentsActionHelper.js'; import PermissionsActionHelper from './../permissions/PermissionsActionHelper.js'; import RevisionsActionHelper from './../revisions/RevisionsActionHelper.js'; import HeatSetupActionHelper from './attachments/setup/HeatSetupActionHelper.js'; import { actionsEnum as versionControllerActions } from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; import { CommitModalType } from 'nfvo-components/panel/versionController/components/CommitCommentModal.jsx'; import { onboardingMethod as onboardingMethodType } from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; import { SyncStates } from 'sdc-app/common/merge/MergeEditorConstants.js'; import { catalogItemStatuses } from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js'; function getActiveNavigationId(screen, componentId) { let activeItemId = componentId ? screen + '|' + componentId : screen; return activeItemId; } const buildComponentNavigationBarGroups = ({ componentId, meta }) => { const groups = [ { id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL + '|' + componentId, name: i18n('General'), disabled: false, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE + '|' + componentId, name: i18n('Compute'), disabled: false, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING + '|' + componentId, name: i18n('High Availability & Load Balancing'), disabled: false, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK + '|' + componentId, name: i18n('Networks'), disabled: false, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE + '|' + componentId, name: i18n('Storage'), disabled: false, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES + '|' + componentId, name: i18n('Images'), disabled: false, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES + '|' + componentId, name: i18n('Process Details'), disabled: false, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING + '|' + componentId, name: i18n('Monitoring'), disabled: false, meta } ]; return groups; }; const buildNavigationBarProps = ({ softwareProduct, meta, screen, componentId, componentsList, mapOfExpandedIds, isCertified }) => { const { softwareProductEditor: { data: currentSoftwareProduct = {} } } = softwareProduct; const { id, name, onboardingMethod, candidateOnboardingOrigin, onboardingOrigin } = currentSoftwareProduct; const groups = [ { id: id, name: name, items: [ { id: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, name: i18n('Overview'), disabled: false, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_DETAILS, name: i18n('General'), disabled: false, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT, name: i18n('Deployment Flavors'), disabled: false, hidden: onboardingMethod !== onboardingMethodTypes.MANUAL, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES, name: i18n('Process Details'), disabled: false, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS, name: i18n('Networks'), disabled: false, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS, name: i18n('Attachments'), disabled: false, hidden: !candidateOnboardingOrigin && !onboardingOrigin, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG, name: i18n('Activity Log'), disabled: false, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES, name: i18n('Component Dependencies'), hidden: componentsList.length <= 1, disabled: false, meta }, { id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS, name: i18n('Components'), hidden: componentsList.length <= 0, meta, expanded: mapOfExpandedIds[ enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS ] === true && screen !== enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, items: [ ...componentsList.map(({ id, displayName }) => ({ id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS + '|' + id, name: displayName, meta, expanded: mapOfExpandedIds[ enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS + '|' + id ] === true && screen !== enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, items: buildComponentNavigationBarGroups({ componentId: id, meta }) })) ] } ] } ]; let activeItemId = getActiveNavigationId(screen, componentId); return { activeItemId, groups, disabled: !!candidateOnboardingOrigin && !isCertified }; }; const buildVersionControllerProps = ({ softwareProduct, versions, currentVersion, permissions, userInfo, isArchived, usersList, itemPermission, isReadOnlyMode }) => { const { softwareProductEditor = { data: {} } } = softwareProduct; const { isValidityData = true, data: { name, onboardingMethod, candidateOnboardingOrigin } } = softwareProductEditor; return { version: currentVersion, viewableVersions: versions, isFormDataValid: isValidityData, permissions, itemName: name, itemPermission, isReadOnlyMode, isArchived, userInfo, usersList, isManual: onboardingMethod === onboardingMethodType.MANUAL, candidateInProcess: !!candidateOnboardingOrigin && !itemPermission.isCertified }; }; function buildMeta({ softwareProduct, componentId, softwareProductDependencies, isReadOnlyMode }) { const { softwareProductEditor, softwareProductComponents, softwareProductQuestionnaire, softwareProductAttachments } = softwareProduct; const { data: currentSoftwareProduct = {} } = softwareProductEditor; const { version, onboardingOrigin, candidateOnboardingOrigin } = currentSoftwareProduct; const { qdata } = softwareProductQuestionnaire; const { heatSetup, heatSetupCache } = softwareProductAttachments; let currentComponentMeta = {}; if (componentId) { const { componentEditor: { data: componentData = {}, qdata: componentQdata } } = softwareProductComponents; currentComponentMeta = { componentData, componentQdata }; } const meta = { softwareProduct: currentSoftwareProduct, qdata, version, onboardingOrigin, candidateOnboardingOrigin, heatSetup, heatSetupCache, isReadOnlyMode, currentComponentMeta, softwareProductDependencies }; return meta; } const mapStateToProps = ( { softwareProduct, users: { usersList, userInfo }, versionsPage: { versionsList: { versions }, permissions } }, { currentScreen: { screen, itemPermission, props: { version: currentVersion, componentId, isReadOnlyMode } } } ) => { const { softwareProductEditor, softwareProductComponents, softwareProductDependencies } = softwareProduct; const { mapOfExpandedIds = [] } = softwareProductEditor; const { componentsList = [] } = softwareProductComponents; const meta = buildMeta({ softwareProduct, componentId, softwareProductDependencies, isReadOnlyMode }); return { versionControllerProps: buildVersionControllerProps({ softwareProduct, versions, currentVersion, userInfo, usersList, isArchived: itemPermission.isArchived, permissions, itemPermission: { ...itemPermission, isDirty: true }, isReadOnlyMode }), navigationBarProps: buildNavigationBarProps({ softwareProduct, meta, screen, componentId, componentsList, mapOfExpandedIds, isCertified: itemPermission.isCertified }), meta }; }; const autoSaveBeforeNavigate = ({ dispatch, screen, softwareProductId, version, componentId, meta: { isReadOnlyMode, softwareProduct, qdata, currentComponentMeta: { componentData, componentQdata } } }) => { let promise; if (isReadOnlyMode) { promise = Promise.resolve(); } else { switch (screen) { case enums.SCREEN.SOFTWARE_PRODUCT_DETAILS: promise = SoftwareProductActionHelper.updateSoftwareProduct( dispatch, { softwareProduct, version, qdata } ); break; case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL: promise = SoftwareProductComponentsActionHelper.updateSoftwareProductComponent( dispatch, { softwareProductId, version, vspComponentId: componentId, componentData, qdata: componentQdata } ); break; case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING: promise = SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire( dispatch, { softwareProductId, version, vspComponentId: componentId, qdata: componentQdata } ); break; default: promise = Promise.resolve(); break; } } return promise; }; const mapActionsToProps = ( dispatch, { currentScreen: { screen, props: { softwareProductId, licenseModelId, version, componentId: currentComponentId } } } ) => { const props = { onVersionSwitching: (versionToSwitch, meta) => { ScreensHelper.loadScreen(dispatch, { screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, screenType: screenTypes.SOFTWARE_PRODUCT, props: { softwareProductId: meta.softwareProduct.id, version: versionToSwitch } }); }, onOpenPermissions: ({ users }) => { return PermissionsActionHelper.fetchItemUsers(dispatch, { itemId: softwareProductId, allUsers: users }); }, onOpenRevisionsModal: () => { return RevisionsActionHelper.openRevisionsView(dispatch, { itemId: softwareProductId, version: version, itemType: screenTypes.SOFTWARE_PRODUCT }); }, onOpenCommentCommitModal: ({ onCommit, title }) => dispatch({ type: modalActionTypes.GLOBAL_MODAL_SHOW, data: { modalComponentName: modalContentMapper.COMMIT_COMMENT, modalComponentProps: { onCommit, type: CommitModalType.COMMIT }, title } }), onMoreVersionsClick: ({ itemName, users }) => { ScreensHelper.loadScreen(dispatch, { screen: enums.SCREEN.SOFTWARE_PRODUCT_VERSIONS_PAGE, screenType: screenTypes.SOFTWARE_PRODUCT, props: { softwareProductId, softwareProduct: { name: itemName, vendorId: licenseModelId }, usersList: users } }); }, onToggle: (groups, itemIdToExpand) => groups.map(({ items }) => SoftwareProductActionHelper.toggleNavigationItems(dispatch, { items, itemIdToExpand }) ), onNavigate: ({ id, meta, newVersion }) => { let navigationVersion = newVersion || version; let { onboardingOrigin, candidateOnboardingOrigin, heatSetup, heatSetupCache } = meta; let heatSetupPopupPromise = screen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS ? HeatSetupActionHelper.heatSetupLeaveConfirmation( dispatch, { softwareProductId, heatSetup, heatSetupCache } ) : Promise.resolve(); let preNavigate = meta ? autoSaveBeforeNavigate({ dispatch, screen, meta, version, softwareProductId, componentId: currentComponentId }) : Promise.resolve(); version = version || (meta ? meta.version : undefined); Promise.all([preNavigate, heatSetupPopupPromise]) .then(() => { let [nextScreen, nextComponentId] = id.split('|'); if ( nextScreen === enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS && nextComponentId && nextComponentId === currentComponentId ) { ScreensHelper.loadScreen(dispatch, { screen: nextScreen, screenType: screenTypes.SOFTWARE_PRODUCT, props: { softwareProductId, version: navigationVersion } }); } else { if ( nextScreen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS ) { if ( onboardingOrigin === onboardingOriginTypes.ZIP || candidateOnboardingOrigin === onboardingOriginTypes.ZIP ) { nextScreen = enums.SCREEN .SOFTWARE_PRODUCT_ATTACHMENTS_SETUP; } else if ( onboardingOrigin === onboardingOriginTypes.CSAR ) { nextScreen = enums.SCREEN .SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION; } } ScreensHelper.loadScreen(dispatch, { screen: nextScreen, screenType: screenTypes.SOFTWARE_PRODUCT, props: { softwareProductId, version: navigationVersion, componentId: nextComponentId } }); } }) .catch(e => { console.error(e); }); } }; switch (screen) { case enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE: case enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS: case enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES: case enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS: case enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES: case enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS: case enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING: props.onSave = () => Promise.resolve(); break; default: props.onSave = ({ softwareProduct, qdata }) => SoftwareProductActionHelper.updateSoftwareProduct(dispatch, { softwareProduct, qdata, version }); break; } props.onVersionControllerAction = (action, version, comment, meta) => { let { heatSetup, heatSetupCache } = meta; let autoSavePromise = meta ? autoSaveBeforeNavigate({ dispatch, screen, meta, version, softwareProductId, componentId: currentComponentId }) : Promise.resolve(); let heatSetupPopupPromise = screen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS && action === versionControllerActions.COMMIT ? HeatSetupActionHelper.heatSetupLeaveConfirmation(dispatch, { softwareProductId, heatSetup, heatSetupCache }) : Promise.resolve(); Promise.all([autoSavePromise, heatSetupPopupPromise]) .then(() => { return SoftwareProductActionHelper.performVCAction(dispatch, { softwareProductId, action, version, comment, meta }).then(updatedVersion => { const inMerge = updatedVersion && updatedVersion.state && updatedVersion.state.synchronizationState === SyncStates.MERGE; if ( (action === versionControllerActions.SYNC && !inMerge) || ((action === versionControllerActions.COMMIT || action === versionControllerActions.SYNC) && updatedVersion.status === catalogItemStatuses.CERTIFIED) ) { ScreensHelper.loadLandingScreen(dispatch, { previousScreenName: screen, props: { softwareProductId, version: updatedVersion } }); } else { ScreensHelper.loadScreen(dispatch, { screen, screenType: screenTypes.SOFTWARE_PRODUCT, props: { softwareProductId, version: updatedVersion, componentId: currentComponentId } }); } }); }) .catch(e => { console.error(e); }); }; props.onManagePermissions = () => PermissionsActionHelper.openPermissonsManager(dispatch, { itemId: softwareProductId, askForRights: false }); return props; }; export default connect(mapStateToProps, mapActionsToProps)(TabulatedEditor);