[SDC] Onboarding 1710 rebase.
Change-Id: If3b6b81d221fde13908f1e8160db6f7d9433c535
Signed-off-by: Avi Ziv <avi.ziv@amdocs.com>
diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js
index eb99bdc..2b59361 100644
--- a/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js
+++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js
@@ -20,16 +20,20 @@
import EntitlementPoolsActionHelper from './licenseModel/entitlementPools/EntitlementPoolsActionHelper.js';
import SoftwareProductActionHelper from './softwareProduct/SoftwareProductActionHelper.js';
import SoftwareProductProcessesActionHelper from './softwareProduct/processes/SoftwareProductProcessesActionHelper.js';
+import SoftwareProductDeploymentActionHelper from './softwareProduct/deployment/SoftwareProductDeploymentActionHelper.js';
import SoftwareProductNetworksActionHelper from './softwareProduct/networks/SoftwareProductNetworksActionHelper.js';
import SoftwareProductComponentsActionHelper from './softwareProduct/components/SoftwareProductComponentsActionHelper.js';
import SoftwareProductComponentProcessesActionHelper from './softwareProduct/components/processes/SoftwareProductComponentProcessesActionHelper.js';
import SoftwareProductComponentsNetworkActionHelper from './softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.js';
import SoftwareProductDependenciesActionHelper from './softwareProduct/dependencies/SoftwareProductDependenciesActionHelper.js';
+import ComputeFlavorActionHelper from './softwareProduct/components/compute/ComputeFlavorActionHelper.js';
import OnboardActionHelper from './onboard/OnboardActionHelper.js';
import SoftwareProductComponentsMonitoringAction from './softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringActionHelper.js';
import {actionTypes, enums} from './OnboardingConstants.js';
-import {navigationItems as SoftwareProductNavigationItems, actionTypes as SoftwareProductActionTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
-import ActivityLogActionHelper from 'nfvo-components/activity-log/ActivityLogActionHelper.js';
+import SoftwareProductComponentsImageActionHelper from './softwareProduct/components/images/SoftwareProductComponentsImageActionHelper.js';
+import {navigationItems as SoftwareProductNavigationItems, actionTypes as SoftwareProductActionTypes,
+ onboardingMethod as onboardingMethodTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
+import ActivityLogActionHelper from 'sdc-app/common/activity-log/ActivityLogActionHelper.js';
import licenseModelOverviewActionHelper from 'sdc-app/onboarding/licenseModel/overview/licenseModelOverviewActionHelper.js';
import store from 'sdc-app/AppStore.js';
import {selectedButton as licenseModelOverviewSelectedButton} from 'sdc-app/onboarding/licenseModel/overview/LicenseModelOverviewConstants.js';
@@ -160,9 +164,18 @@
const newVersion = response[0].version ? response[0].version : version;
SoftwareProductActionHelper.loadSoftwareProductDetailsData(dispatch, {licenseModelId, licensingVersion});
- SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version: newVersion});
- SoftwareProductActionHelper.loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version: newVersion});
- setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, {softwareProductId, licenseModelId, version: newVersion});
+ let isFetchImageDetails = (response[0].onboardingMethod === onboardingMethodTypes.HEAT);
+ if (isFetchImageDetails) {
+ // will only continue after we can properly build the navigation bar with the images links
+ SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version: newVersion, isFetchImageDetails}).then(() => {
+ SoftwareProductActionHelper.loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version: newVersion});
+ setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, {softwareProductId, licenseModelId, version: newVersion});
+ });
+ } else {
+ SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version: newVersion, isFetchImageDetails});
+ SoftwareProductActionHelper.loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version: newVersion});
+ setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, {softwareProductId, licenseModelId, version: newVersion});
+ }
});
},
@@ -199,7 +212,11 @@
SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version});
setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS, {softwareProductId, version});
},
-
+ navigateToSoftwareProductDeployment(dispatch, {softwareProductId, version}) {
+ SoftwareProductDeploymentActionHelper.fetchDeploymentFlavorsList(dispatch, {softwareProductId, version});
+ ComputeFlavorActionHelper.fetchComputesListForVSP(dispatch, {softwareProductId, version});
+ setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT, {softwareProductId, version});
+ },
navigateToSoftwareProductActivityLog(dispatch, {softwareProductId, version}){
ActivityLogActionHelper.fetchActivityLog(dispatch, {itemId: softwareProductId, versionId: version.id});
setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG, {softwareProductId, version});
@@ -226,6 +243,9 @@
navigateToComponentCompute(dispatch, {softwareProductId, componentId, version}) {
SoftwareProductComponentsActionHelper.fetchSoftwareProductComponent(dispatch, {softwareProductId, vspComponentId: componentId, version});
+ if (componentId && softwareProductId) {
+ ComputeFlavorActionHelper.fetchComputesList(dispatch, {softwareProductId, componentId, version});
+ }
setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE, {softwareProductId, version, componentId});
},
@@ -255,6 +275,15 @@
navigateToComponentLoadBalancing(dispatch, {softwareProductId, componentId, version}) {
SoftwareProductComponentsActionHelper.fetchSoftwareProductComponent(dispatch, {softwareProductId, vspComponentId: componentId, version});
setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING, {softwareProductId, version, componentId});
+ },
+
+ navigateToComponentImages(dispatch, {softwareProductId, componentId, version}) {
+ SoftwareProductComponentsImageActionHelper.fetchImagesList(dispatch, {
+ softwareProductId,
+ componentId,
+ version
+ });
+ setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES, {softwareProductId, version, componentId});
}
};
diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingConstants.js b/openecomp-ui/src/sdc-app/onboarding/OnboardingConstants.js
index 7811950..0fff513 100644
--- a/openecomp-ui/src/sdc-app/onboarding/OnboardingConstants.js
+++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingConstants.js
@@ -15,6 +15,8 @@
*/
import keyMirror from 'nfvo-utils/KeyMirror.js';
+export const DATE_FORMAT = 'MM/DD/YYYY';
+
export const actionTypes = keyMirror({
SET_CURRENT_SCREEN: null,
SET_CURRENT_LICENSE_MODEL: null
@@ -36,6 +38,7 @@
SOFTWARE_PRODUCT_DETAILS: 'SOFTWARE_PRODUCT_DETAILS',
SOFTWARE_PRODUCT_ATTACHMENTS: 'SOFTWARE_PRODUCT_ATTACHMENTS',
SOFTWARE_PRODUCT_PROCESSES: 'SOFTWARE_PRODUCT_PROCESSES',
+ SOFTWARE_PRODUCT_DEPLOYMENT: 'SOFTWARE_PRODUCT_DEPLOYMENT',
SOFTWARE_PRODUCT_NETWORKS: 'SOFTWARE_PRODUCT_NETWORKS',
SOFTWARE_PRODUCT_DEPENDENCIES: 'SOFTWARE_PRODUCT_DEPENDENCIES',
SOFTWARE_PRODUCT_ACTIVITY_LOG: 'SOFTWARE_PRODUCT_ACTIVITY_LOG',
@@ -45,7 +48,8 @@
SOFTWARE_PRODUCT_COMPONENT_GENERAL: 'SOFTWARE_PRODUCT_COMPONENT_GENERAL',
SOFTWARE_PRODUCT_COMPONENT_COMPUTE: 'SOFTWARE_PRODUCT_COMPONENT_COMPUTE',
SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING: 'SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING',
- SOFTWARE_PRODUCT_COMPONENT_MONITORING: 'SOFTWARE_PRODUCT_COMPONENT_MONITORING'
+ SOFTWARE_PRODUCT_COMPONENT_MONITORING: 'SOFTWARE_PRODUCT_COMPONENT_MONITORING',
+ SOFTWARE_PRODUCT_COMPONENT_IMAGES: 'SOFTWARE_PRODUCT_COMPONENT_IMAGES'
},
SCREEN: {
@@ -61,6 +65,7 @@
SOFTWARE_PRODUCT_DETAILS: null,
SOFTWARE_PRODUCT_ATTACHMENTS: null,
SOFTWARE_PRODUCT_PROCESSES: null,
+ SOFTWARE_PRODUCT_DEPLOYMENT: null,
SOFTWARE_PRODUCT_NETWORKS: null,
SOFTWARE_PRODUCT_DEPENDENCIES: null,
SOFTWARE_PRODUCT_ACTIVITY_LOG: null,
@@ -71,6 +76,7 @@
SOFTWARE_PRODUCT_COMPONENT_NETWORK: null,
SOFTWARE_PRODUCT_COMPONENT_GENERAL: null,
SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING: null,
- SOFTWARE_PRODUCT_COMPONENT_MONITORING: null
+ SOFTWARE_PRODUCT_COMPONENT_MONITORING: null,
+ SOFTWARE_PRODUCT_COMPONENT_IMAGES: null
}
});
diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx b/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx
index e8a844b..1f0bef7 100644
--- a/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx
@@ -27,7 +27,7 @@
import Onboard from './onboard/Onboard.js';
import LicenseModel from './licenseModel/LicenseModel.js';
import LicenseModelOverview from './licenseModel/overview/LicenseModelOverview.js';
-import ActivityLog from 'nfvo-components/activity-log/ActivityLog.js';
+import ActivityLog from 'sdc-app/common/activity-log/ActivityLog.js';
import {doesHeatDataExist} from './softwareProduct/attachments/SoftwareProductAttachmentsUtils.js';
import LicenseAgreementListEditor from './licenseModel/licenseAgreement/LicenseAgreementListEditor.js';
@@ -39,17 +39,25 @@
import SoftwareProductDetails from './softwareProduct/details/SoftwareProductDetails.js';
import SoftwareProductAttachments from './softwareProduct/attachments/SoftwareProductAttachments.js';
import SoftwareProductProcesses from './softwareProduct/processes/SoftwareProductProcesses.js';
+import SoftwareProductDeployment from './softwareProduct/deployment/SoftwareProductDeployment.js';
import SoftwareProductNetworks from './softwareProduct/networks/SoftwareProductNetworks.js';
import SoftwareProductDependencies from './softwareProduct/dependencies/SoftwareProductDependencies.js';
-import SoftwareProductComponentsList from './softwareProduct/components/SoftwareProductComponentsList.js';
+
+import SoftwareProductComponentsList from './softwareProduct/components/SoftwareProductComponents.js';
import SoftwareProductComponentProcessesList from './softwareProduct/components/processes/SoftwareProductComponentProcessesList.js';
import SoftwareProductComponentStorage from './softwareProduct/components/storage/SoftwareProductComponentStorage.js';
import SoftwareProductComponentsNetworkList from './softwareProduct/components/network/SoftwareProductComponentsNetworkList.js';
import SoftwareProductComponentsGeneral from './softwareProduct/components/general/SoftwareProductComponentsGeneral.js';
import SoftwareProductComponentsCompute from './softwareProduct/components/compute/SoftwareProductComponentCompute.js';
import SoftwareProductComponentLoadBalancing from './softwareProduct/components/loadBalancing/SoftwareProductComponentLoadBalancing.js';
+import SoftwareProductComponentsImageList from './softwareProduct/components/images/SoftwareProductComponentsImageList.js';
import SoftwareProductComponentsMonitoring from './softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.js';
-import {navigationItems as SoftwareProductNavigationItems, actionTypes as SoftwareProductActionTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
+import {
+ navigationItems as SoftwareProductNavigationItems,
+ onboardingMethod as onboardingMethodTypes,
+ actionTypes as SoftwareProductActionTypes
+} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
+
import {statusEnum as VCItemStatus} from 'nfvo-components/panel/versionController/VersionControllerConstants.js';
import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js';
@@ -123,6 +131,7 @@
case enums.SCREEN.SOFTWARE_PRODUCT_DETAILS:
case enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS:
case enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES:
+ case enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT:
case enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS:
case enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES:
case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS:
@@ -132,6 +141,7 @@
case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL:
case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE:
case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING:
+ case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES:
case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING:
case enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG:
return (
@@ -147,6 +157,8 @@
return <SoftwareProductAttachments className='no-padding-content-area' {...props} />;
case enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES:
return <SoftwareProductProcesses {...props}/>;
+ case enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT:
+ return <SoftwareProductDeployment {...props}/>;
case enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS:
return <SoftwareProductNetworks {...props}/>;
case enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES:
@@ -165,6 +177,8 @@
return <SoftwareProductComponentsCompute {...props}/>;
case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING:
return <SoftwareProductComponentLoadBalancing{...props}/>;
+ case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES:
+ return <SoftwareProductComponentsImageList{...props}/>;
case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING:
return <SoftwareProductComponentsMonitoring {...props}/>;
case enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG:
@@ -220,11 +234,11 @@
handleData(data) {
let {breadcrumbs: {selectedKeys = []} = {}} = data;
let dispatch = action => store.dispatch(action);
- let {currentScreen, softwareProductList, softwareProduct: {softwareProductEditor: {data: vspData = {}},
+ let {currentScreen, softwareProductList, softwareProduct: {softwareProductEditor: {data: vspData = {}},
softwareProductComponents = {}, softwareProductQuestionnaire = {}},
licenseModelList, licenseModel: {licenseModelEditor: {data: {id: currentLicenseModelId, version: currentLicenseModelVersion} = {}}}} = store.getState();
let {id: currentSoftwareProductId, version: currentSoftwareProductVersion} = vspData;
- let {componentEditor: {data: componentData = {}, qdata: componentQData = {}}} = softwareProductComponents;
+ let {componentEditor: {data: componentData = {}, qdata: componentQData = {}}} = softwareProductComponents;
if (this.programmaticBreadcrumbsUpdate) {
this.prevSelectedKeys = selectedKeys;
this.programmaticBreadcrumbsUpdate = false;
@@ -237,7 +251,7 @@
let preNavigate = Promise.resolve();
if(screenType === enums.BREADCRUMS.SOFTWARE_PRODUCT && vspData.status === VCItemStatus.CHECK_OUT_STATUS && VersionControllerUtils.isCheckedOutByCurrentUser(vspData)) {
let dataToSave = prevVspId ? prevComponentId ? {componentData, qdata: componentQData} : {softwareProduct: vspData, qdata: softwareProductQuestionnaire.qdata} : {};
- preNavigate = OnboardingActionHelper.autoSaveBeforeNavigate(dispatch, {
+ preNavigate = OnboardingActionHelper.autoSaveBeforeNavigate(dispatch, {
softwareProductId: prevVspId,
version: currentSoftwareProductVersion,
vspComponentId: prevComponentId,
@@ -305,6 +319,9 @@
case enums.BREADCRUMS.SOFTWARE_PRODUCT_PROCESSES:
OnboardingActionHelper.navigateToSoftwareProductProcesses(dispatch, {softwareProductId, version: currentSoftwareProductVersion});
break;
+ case enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPLOYMENT:
+ OnboardingActionHelper.navigateToSoftwareProductDeployment(dispatch, {softwareProductId, version: currentSoftwareProductVersion});
+ break;
case enums.BREADCRUMS.SOFTWARE_PRODUCT_NETWORKS:
OnboardingActionHelper.navigateToSoftwareProductNetworks(dispatch, {softwareProductId, version: currentSoftwareProductVersion});
break;
@@ -355,22 +372,29 @@
OnboardingActionHelper.navigateToSoftwareProductComponentGeneral(dispatch, {softwareProductId, componentId, version: currentSoftwareProductVersion});
break;
case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_COMPUTE:
- OnboardingActionHelper.navigateToComponentCompute(dispatch, {softwareProductId, componentId});
+ OnboardingActionHelper.navigateToComponentCompute(dispatch, {softwareProductId, componentId, version: currentSoftwareProductVersion});
break;
case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING:
- OnboardingActionHelper.navigateToComponentLoadBalancing(dispatch, {softwareProductId, componentId});
+ OnboardingActionHelper.navigateToComponentLoadBalancing(dispatch, {softwareProductId, componentId, version: currentSoftwareProductVersion});
break;
case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_NETWORK:
- OnboardingActionHelper.navigateToComponentNetwork(dispatch, {softwareProductId, componentId});
+ OnboardingActionHelper.navigateToComponentNetwork(dispatch, {softwareProductId, componentId, version: currentSoftwareProductVersion});
break;
case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_STORAGE:
- OnboardingActionHelper.navigateToComponentStorage(dispatch, {softwareProductId, componentId});
+ OnboardingActionHelper.navigateToComponentStorage(dispatch, {softwareProductId, componentId, version: currentSoftwareProductVersion});
break;
case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_PROCESSES:
- OnboardingActionHelper.navigateToSoftwareProductComponentProcesses(dispatch, {softwareProductId, componentId});
+ OnboardingActionHelper.navigateToSoftwareProductComponentProcesses(dispatch, {softwareProductId, componentId, version: currentSoftwareProductVersion});
break;
case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_MONITORING:
- OnboardingActionHelper.navigateToSoftwareProductComponentMonitoring(dispatch, {softwareProductId, componentId});
+ OnboardingActionHelper.navigateToSoftwareProductComponentMonitoring(dispatch, {softwareProductId, componentId, version: currentSoftwareProductVersion});
+ break;
+ case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_IMAGES:
+ OnboardingActionHelper.navigateToComponentImages(dispatch, {
+ softwareProductId,
+ componentId,
+ version: currentSoftwareProductVersion
+ });
break;
}
} else {
@@ -390,8 +414,10 @@
handleStoreChange() {
let {currentScreen, licenseModelList, softwareProductList,
- softwareProduct: {softwareProductComponents: {componentsList}, softwareProductAttachments: {heatSetup}}} = store.getState();
- let breadcrumbsData = {currentScreen, licenseModelList, softwareProductList, componentsList, heatSetup};
+ softwareProduct: {softwareProductEditor: {data = {onboardingMethod: ''}},
+ softwareProductComponents: {componentsList, images: {imagesNavigationList}}, softwareProductAttachments: {heatSetup}}} = store.getState();
+ let {onboardingMethod} = data;
+ let breadcrumbsData = {onboardingMethod, currentScreen, licenseModelList, softwareProductList, componentsList, heatSetup, imagesNavigationList};
if (currentScreen.forceBreadCrumbsUpdate || !isEqual(breadcrumbsData, this.prevBreadcrumbsData) || this.breadcrumbsPrefixSelected) {
this.prevBreadcrumbsData = breadcrumbsData;
this.breadcrumbsPrefixSelected = false;
@@ -408,7 +434,7 @@
}
}
- buildBreadcrumbs({currentScreen: {screen, props}, licenseModelList, softwareProductList, componentsList, heatSetup}) {
+ buildBreadcrumbs({currentScreen: {screen, props}, onboardingMethod, licenseModelList, softwareProductList, componentsList, heatSetup, imagesNavigationList}) {
let screenToBreadcrumb;
switch (screen) {
case enums.SCREEN.ONBOARDING_CATALOG:
@@ -474,6 +500,7 @@
case enums.SCREEN.SOFTWARE_PRODUCT_DETAILS:
case enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS:
case enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES:
+ case enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT:
case enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS:
case enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES:
case enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG:
@@ -485,12 +512,14 @@
case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK:
case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL:
case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING:
+ case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES:
case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING:
screenToBreadcrumb = {
[enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE]: enums.BREADCRUMS.SOFTWARE_PRODUCT_LANDING_PAGE,
[enums.SCREEN.SOFTWARE_PRODUCT_DETAILS]: enums.BREADCRUMS.SOFTWARE_PRODUCT_DETAILS,
[enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS]: enums.BREADCRUMS.SOFTWARE_PRODUCT_ATTACHMENTS,
[enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES]: enums.BREADCRUMS.SOFTWARE_PRODUCT_PROCESSES,
+ [enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT]: enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPLOYMENT,
[enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS]: enums.BREADCRUMS.SOFTWARE_PRODUCT_NETWORKS,
[enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES]: enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPENDENCIES,
[enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENTS,
@@ -503,6 +532,7 @@
[enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_NETWORK,
[enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_GENERAL,
[enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING,
+ [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_IMAGES,
[enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_MONITORING
};
let licenseModelId = softwareProductList.find(({id}) => id === props.softwareProductId).vendorId;
@@ -542,6 +572,9 @@
key: enums.BREADCRUMS.SOFTWARE_PRODUCT_DETAILS,
displayText: i18n('General')
}, {
+ key: enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPLOYMENT,
+ displayText: i18n('Deployment Flavors')
+ }, {
key: enums.BREADCRUMS.SOFTWARE_PRODUCT_PROCESSES,
displayText: i18n('Process Details')
}, {
@@ -561,14 +594,16 @@
displayText: i18n('Components')
}].filter(item => {
let isHeatData = doesHeatDataExist(heatSetup);
- let isComponentsData = componentsList.length > 0;
+ let isManualMode = onboardingMethod === onboardingMethodTypes.MANUAL;
switch (item.key) {
case enums.BREADCRUMS.SOFTWARE_PRODUCT_ATTACHMENTS:
return isHeatData;
case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENTS:
- return isComponentsData;
+ return (componentsList.length > 0);
+ case enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPLOYMENT:
+ return isManualMode;
case enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPENDENCIES:
- return isComponentsData;
+ return (componentsList.length > 1);
default:
return true;
}
@@ -603,12 +638,23 @@
key: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_STORAGE,
displayText: i18n('Storage')
}, {
+ key: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_IMAGES,
+ displayText: i18n('Images')
+ }, {
key: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_PROCESSES,
displayText: i18n('Process Details')
}, {
key: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_MONITORING,
displayText: i18n('Monitoring')
- }]
+ }].filter(item => {
+ switch (item.key) {
+ case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_IMAGES:
+ return (onboardingMethod === onboardingMethodTypes.MANUAL ||
+ (imagesNavigationList && imagesNavigationList[props.componentId] === true));
+ default:
+ return true;
+ }
+ })
}]
];
}
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js
index e21b0a8..895a329 100644
--- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js
@@ -18,7 +18,7 @@
import i18n from 'nfvo-utils/i18n/i18n.js';
import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js';
import TabulatedEditor from 'src/nfvo-components/editor/TabulatedEditor.jsx';
-import ActivityLogActionHelper from 'nfvo-components/activity-log/ActivityLogActionHelper.js';
+import ActivityLogActionHelper from 'sdc-app/common/activity-log/ActivityLogActionHelper.js';
import {enums} from 'sdc-app/onboarding/OnboardingConstants.js';
import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js';
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js
index 9a2d114..bd060a4 100644
--- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js
@@ -15,7 +15,7 @@
*/
import {combineReducers} from 'redux';
-import activityLogReducer from 'nfvo-components/activity-log/ActivityLogReducer.js';
+import activityLogReducer from 'sdc-app/common/activity-log/ActivityLogReducer.js';
import licenseModelCreationReducer from './creation/LicenseModelCreationReducer.js';
import licenseModelEditorReducer from './LicenseModelEditorReducer.js';
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js
index fe95b03..a7c95f6 100644
--- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js
@@ -39,7 +39,9 @@
aggregationFunction: entitlementPool.aggregationFunction,
operationalScope: entitlementPool.operationalScope,
time: entitlementPool.time,
- manufacturerReferenceNumber: entitlementPool.manufacturerReferenceNumber
+ manufacturerReferenceNumber: entitlementPool.manufacturerReferenceNumber,
+ startDate: entitlementPool.startDate,
+ expiryDate: entitlementPool.expiryDate
});
}
@@ -55,7 +57,9 @@
aggregationFunction: entitlementPool.aggregationFunction,
operationalScope: entitlementPool.operationalScope,
time: entitlementPool.time,
- manufacturerReferenceNumber: entitlementPool.manufacturerReferenceNumber
+ manufacturerReferenceNumber: entitlementPool.manufacturerReferenceNumber,
+ startDate: entitlementPool.startDate,
+ expiryDate: entitlementPool.expiryDate
});
}
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js
index ba0b238..761614d 100644
--- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js
@@ -113,3 +113,5 @@
};
export const SP_ENTITLEMENT_POOL_FORM = 'SPENTITLEMENTPOOL';
+
+export const EP_TIME_FORMAT = 'MM/DD/YYYY';
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorReducer.js
index db1a3a9..bc95497 100644
--- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorReducer.js
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorReducer.js
@@ -14,10 +14,20 @@
* permissions and limitations under the License.
*/
import {actionTypes, defaultState, SP_ENTITLEMENT_POOL_FORM} from './EntitlementPoolsConstants.js';
+import moment from 'moment';
+import {DATE_FORMAT} from 'sdc-app/onboarding/OnboardingConstants.js';
export default (state = {}, action) => {
switch (action.type) {
case actionTypes.entitlementPoolsEditor.OPEN:
+ let entitlementPoolData = {...action.entitlementPool};
+ let {startDate, expiryDate} = entitlementPoolData;
+ if (startDate) {
+ entitlementPoolData.startDate = moment(startDate, DATE_FORMAT).format(DATE_FORMAT);
+ }
+ if (expiryDate) {
+ entitlementPoolData.expiryDate = moment(expiryDate, DATE_FORMAT).format(DATE_FORMAT);
+ }
return {
...state,
formReady: null,
@@ -72,9 +82,19 @@
isValid: true,
errorText: '',
validations: [{type: 'required', data: true}]
+ },
+ 'startDate': {
+ isValid: true,
+ errorText: '',
+ validations: []
+ },
+ 'expiryDate': {
+ isValid: true,
+ errorText: '',
+ validations: []
}
},
- data: action.entitlementPool ? {...action.entitlementPool} : defaultState.ENTITLEMENT_POOLS_EDITOR_DATA
+ data: action.entitlementPool ? entitlementPoolData : defaultState.ENTITLEMENT_POOLS_EDITOR_DATA
};
case actionTypes.entitlementPoolsEditor.DATA_CHANGED:
return {
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorView.jsx
index d484437..e4b52fc 100644
--- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorView.jsx
@@ -23,7 +23,7 @@
import Form from 'nfvo-components/input/validation/Form.jsx';
import GridSection from 'nfvo-components/grid/GridSection.jsx';
import GridItem from 'nfvo-components/grid/GridItem.jsx';
-import {optionsInputValues as EntitlementPoolsOptionsInputValues, thresholdUnitType, SP_ENTITLEMENT_POOL_FORM} from './EntitlementPoolsConstants.js';
+import {optionsInputValues as EntitlementPoolsOptionsInputValues, thresholdUnitType, SP_ENTITLEMENT_POOL_FORM, EP_TIME_FORMAT} from './EntitlementPoolsConstants.js';
import {other as optionInputOther} from 'nfvo-components/input/inputOptions/InputOptions.jsx';
const EntitlementPoolPropType = React.PropTypes.shape({
@@ -50,10 +50,11 @@
})
});
-const EntitlementPoolsFormContent = ({data, genericFieldInfo, onDataChanged, validateName, validateChoiceWithOther, validateTimeOtherValue, thresholdValueValidation}) => {
+const EntitlementPoolsFormContent = ({data, genericFieldInfo, onDataChanged, validateName, validateChoiceWithOther, validateTimeOtherValue,
+ thresholdValueValidation, validateStartDate}) => {
let {
name, description, manufacturerReferenceNumber, operationalScope , aggregationFunction, thresholdUnits, thresholdValue,
- increments, time, entitlementMetric} = data;
+ increments, time, entitlementMetric, startDate, expiryDate} = data;
return (
<GridSection>
@@ -175,6 +176,8 @@
onChange={manufacturerReferenceNumber => onDataChanged({manufacturerReferenceNumber}, SP_ENTITLEMENT_POOL_FORM)}
label={i18n('Manufacturer Reference Number')}
value={manufacturerReferenceNumber}
+ isValid={genericFieldInfo.manufacturerReferenceNumber.isValid}
+ errorText={genericFieldInfo.manufacturerReferenceNumber.errorText}
isRequired={true}
data-test-id='create-ep-reference-number'
type='text'/>
@@ -206,6 +209,40 @@
data-test-id='create-ep-increments'
type='text'/>
</GridItem>
+ <GridItem colSpan={2} />
+ <GridItem colSpan={2}>
+ <Input
+ type='date'
+ label={i18n('Start Date')}
+ value={startDate}
+ dateFormat={EP_TIME_FORMAT}
+ startDate={startDate}
+ endDate={expiryDate}
+ onChange={startDate => onDataChanged(
+ {startDate: startDate ? startDate.format(EP_TIME_FORMAT) : ''},
+ SP_ENTITLEMENT_POOL_FORM,
+ {startDate: validateStartDate}
+ )}
+ isValid={genericFieldInfo.startDate.isValid}
+ errorText={genericFieldInfo.startDate.errorText}
+ selectsStart/>
+ </GridItem>
+ <GridItem colSpan={2}>
+ <Input
+ type='date'
+ label={i18n('Expiry Date')}
+ value={expiryDate}
+ dateFormat={EP_TIME_FORMAT}
+ startDate={startDate}
+ endDate={expiryDate}
+ onChange={expiryDate => {
+ onDataChanged({expiryDate: expiryDate ? expiryDate.format(EP_TIME_FORMAT) : ''}, SP_ENTITLEMENT_POOL_FORM);
+ onDataChanged({startDate}, SP_ENTITLEMENT_POOL_FORM, {startDate: validateStartDate});
+ }}
+ isValid={genericFieldInfo.expiryDate.isValid}
+ errorText={genericFieldInfo.expiryDate.errorText}
+ selectsEnd/>
+ </GridItem>
</GridSection>
);
};
@@ -251,6 +288,7 @@
validateName={(value)=> this.validateName(value)}
validateTimeOtherValue ={(value)=> this.validateTimeOtherValue(value)}
validateChoiceWithOther={(value)=> this.validateChoiceWithOther(value)}
+ validateStartDate={(value, state)=> this.validateStartDate(value, state)}
thresholdValueValidation={(value, state)=> this.thresholdValueValidation(value, state)}/>
</Form>
}
@@ -271,6 +309,15 @@
{isValid: false, errorText: i18n('Entitlement pool by the name \'' + value + '\' already exists. Entitlement pool name must be unique')};
}
+ validateStartDate(value, state) {
+ if (state.data.expiryDate) {
+ if (!value) {
+ return {isValid: false, errorText: i18n('Start date has to be specified if expiry date is specified')};
+ }
+ }
+ return {isValid: true, errorText: ''};
+ }
+
validateTimeOtherValue(value) {
return Validator.validate('time', value.other, [{type: 'required', data: true}, {type: 'numeric', data: true}]);
}
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditorView.jsx
index 07a6f21..55fd11b 100644
--- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditorView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditorView.jsx
@@ -45,14 +45,14 @@
};
render() {
- let {licenseModelId, vendorName, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props;
+ let {licenseModelId, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props;
let {onAddEntitlementPoolClick} = this.props;
const {localFilter} = this.state;
return (
<div className='entitlement-pools-list-editor'>
<ListEditorView
- title={i18n('Entitlement Pools', {vendorName})}
+ title={i18n('Entitlement Pools')}
plusButtonTitle={i18n('Add Entitlement Pool')}
onAdd={onAddEntitlementPoolClick}
filterValue={localFilter}
@@ -132,7 +132,7 @@
export function generateConfirmationMsg(entitlementPoolToDelete) {
let poolName = entitlementPoolToDelete ? entitlementPoolToDelete.name : '';
- let msg = i18n('Are you sure you want to delete "{poolName}"?', {poolName});
+ let msg = i18n(`Are you sure you want to delete "${poolName}"?`);
let subMsg = entitlementPoolToDelete
&& entitlementPoolToDelete.referencingFeatureGroups
&& entitlementPoolToDelete.referencingFeatureGroups.length > 0 ?
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditorView.jsx
index bc0f5c7..f883bd7 100644
--- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditorView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditorView.jsx
@@ -51,12 +51,12 @@
};
render() {
- let {vendorName, licenseModelId, featureGroupsModal, isReadOnlyMode, onAddFeatureGroupClick, version} = this.props;
+ let {licenseModelId, featureGroupsModal, isReadOnlyMode, onAddFeatureGroupClick, version} = this.props;
const {localFilter} = this.state;
return (
<div className='feature-groups-list-editor'>
<ListEditorView
- title={i18n('Feature Groups', {vendorName})}
+ title={i18n('Feature Groups')}
plusButtonTitle={i18n('Add Feature Group')}
filterValue={localFilter}
onFilter={value => this.setState({localFilter: value})}
@@ -146,7 +146,7 @@
export function generateConfirmationMsg(featureGroupToDelete) {
let name = featureGroupToDelete ? featureGroupToDelete.name : '';
- let msg = i18n('Are you sure you want to delete "{name}"?', {name});
+ let msg = i18n(`Are you sure you want to delete "${name}"?`);
let subMsg = featureGroupToDelete.referencingLicenseAgreements
&& featureGroupToDelete.referencingLicenseAgreements.length > 0 ?
i18n('This feature group is associated with one ore more license agreements') :
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditor.js
index 373694f..72a99e2 100644
--- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditor.js
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditor.js
@@ -44,7 +44,7 @@
onDeleteLicenseAgreement: (licenseAgreement, version) => dispatch({
type: globalMoadlActions.GLOBAL_MODAL_WARNING,
data:{
- msg: i18n('Are you sure you want to delete "{name}"?', {name: licenseAgreement.name}),
+ msg: i18n(`Are you sure you want to delete "${licenseAgreement.name}"?`),
title: i18n('Warning'),
onConfirmed: ()=>LicenseAgreementActionHelper.deleteLicenseAgreement(dispatch, {licenseModelId, licenseAgreementId: licenseAgreement.id, version})
}
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditorView.jsx
index 776b04b..192d2de 100644
--- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditorView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditorView.jsx
@@ -44,14 +44,14 @@
};
render() {
- const {licenseModelId, vendorName, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props;
+ const {licenseModelId, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props;
const {onAddLicenseAgreementClick} = this.props;
const {localFilter} = this.state;
return (
<div className='license-agreement-list-editor'>
<ListEditorView
- title={i18n('License Agreements', {vendorName})}
+ title={i18n('License Agreements')}
plusButtonTitle={i18n('Add License Agreement')}
onAdd={() => onAddLicenseAgreementClick(version)}
filterValue={localFilter}
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditorView.jsx
index a303e46..b8ccd68 100644
--- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditorView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditorView.jsx
@@ -46,14 +46,14 @@
};
render() {
- let {licenseModelId, vendorName, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props;
+ let {licenseModelId, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props;
let {onAddLicenseKeyGroupClick} = this.props;
const {localFilter} = this.state;
return (
<div className='license-key-groups-list-editor'>
<ListEditorView
- title={i18n('License Key Groups', {vendorName})}
+ title={i18n('License Key Groups')}
plusButtonTitle={i18n('Add License Key Group')}
onAdd={onAddLicenseKeyGroupClick}
filterValue={localFilter}
@@ -147,7 +147,7 @@
export function generateConfirmationMsg(licenseKeyGroupToDelete) {
let name = licenseKeyGroupToDelete ? licenseKeyGroupToDelete.name : '';
- let msg = i18n('Are you sure you want to delete "{name}"?', {name});
+ let msg = i18n(`Are you sure you want to delete "${name}"?`);
let subMsg = licenseKeyGroupToDelete.referencingFeatureGroups
&& licenseKeyGroupToDelete.referencingFeatureGroups.length > 0 ?
i18n('This license key group is associated with one or more feature groups') :
diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.jsx
index c63fbff..3b3e2fc 100644
--- a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.jsx
@@ -18,45 +18,40 @@
import CatalogTile from './CatalogTile.jsx';
import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js';
import {statusEnum, statusBarTextMap} from 'nfvo-components/panel/versionController/VersionControllerConstants.js';
-import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
+import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
import i18n from 'nfvo-utils/i18n/i18n.js';
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js';
import tooltip from './onboardingCatalog/Tooltip.jsx';
-
const CatalogTileIcon = ({catalogItemTypeClass}) => (
- <div className={'catalog-tile-icon ' + catalogItemTypeClass}>
- <div className='icon'><SVGIcon
- name={catalogItemTypeClass === catalogItemTypeClasses.LICENSE_MODEL ? 'vlm' : 'vsp' }/>
- </div>
+ <div className={'catalog-tile-icon ' + catalogItemTypeClass}>
+ <div className='icon'><SVGIcon
+ name={catalogItemTypeClass === catalogItemTypeClasses.LICENSE_MODEL ? 'vlm' : 'vsp' }/>
</div>
+ </div>
);
const ItemTypeTitle = ({catalogItemTypeClass}) => {
const itemTypeTitle = catalogItemTypeClass === catalogItemTypeClasses.LICENSE_MODEL ? i18n('VLM') : i18n('VSP');
- return(
+ return (
<div className={`catalog-tile-type ${catalogItemTypeClass}`}>{itemTypeTitle}</div>
);
};
-const CatalogTileVendorName = ({vendorName, catalogItemTypeClass}) => {
- const name = catalogItemTypeClass === catalogItemTypeClasses.SOFTWARE_PRODUCT ? vendorName : '';
- return(
- <div>
- <OverlayTrigger placement='top' overlay={tooltip(name)}>
- <div className='catalog-tile-vendor-name'>{name}</div>
- </OverlayTrigger>
- </div>
+const CatalogTileVendorName = ({vendorName, catalogItemTypeClass}) => {
+ const name = catalogItemTypeClass === catalogItemTypeClasses.SOFTWARE_PRODUCT ? vendorName : '';
+ return ( name ?
+ <OverlayTrigger placement='top' overlay={tooltip(name)}>
+ <div className='catalog-tile-vendor-name'>{name}</div>
+ </OverlayTrigger> : <div className='catalog-tile-vendor-name'>{name}</div>
);
};
const CatalogTileItemName = ({name}) => (
- <div>
- <OverlayTrigger placement='top' overlay={tooltip(name && name.toUpperCase())}>
- <div className='catalog-tile-item-name'>{name}</div>
- </OverlayTrigger>
- </div>
+ <OverlayTrigger placement='top' overlay={tooltip(name && name.toUpperCase())}>
+ <div className='catalog-tile-item-name'>{name}</div>
+ </OverlayTrigger>
);
const VersionInfo = ({version}) => (
@@ -64,7 +59,7 @@
<div className='catalog-tile-item-version' data-test-id='catalog-item-version'>
V {version}
</div>
- </div>
+ </div>
);
const EntityDetails = ({catalogItemData, catalogItemTypeClass}) => {
@@ -73,54 +68,55 @@
<div className='catalog-tile-entity-details'>
<CatalogTileVendorName catalogItemTypeClass={catalogItemTypeClass} vendorName={vendorName}/>
<CatalogTileItemName name={name}/>
- <VersionInfo version={version.label} />
- </div>
+ <VersionInfo version={version.label}/>
+ </div>
);
};
-const ItemStatusInfo = ({catalogItemTypeClass, lockingUser, itemStatus}) => {
+const ItemStatusInfo = ({catalogItemTypeClass, lockingUser, itemStatus}) => {
const status = statusBarTextMap[itemStatus];
const lockedBy = lockingUser ? ` by ${lockingUser}` : '';
const toolTipMsg = `${status}${lockedBy}`;
return (
- <div className={'catalog-tile-content ' + catalogItemTypeClass}>
+ <div className={'catalog-tile-content ' + catalogItemTypeClass}>
<div className='catalog-tile-locking-user-name'>{i18n(status)}</div>
- <OverlayTrigger placement='top' overlay={tooltip(toolTipMsg)}>
+ <OverlayTrigger placement='top' overlay={tooltip(toolTipMsg)}>
<div className='catalog-tile-check-in-status'><SVGIcon
name={itemStatus === statusEnum.CHECK_OUT_STATUS ? 'unlocked' : 'locked'}
data-test-id={itemStatus === statusEnum.CHECK_IN_STATUS ? 'catalog-item-checked-in' : 'catalog-item-checked-out'}/>
</div>
- </OverlayTrigger>
+ </OverlayTrigger>
</div>
-
+
);
};
-const CatalogItemDetails = ({catalogItemData, catalogItemTypeClass, onSelect, onMigrate}) => {
-
+const CatalogItemDetails = ({catalogItemData, catalogItemTypeClass, onSelect, onMigrate}) => {
+
let {status: itemStatus} = VersionControllerUtils.getCheckOutStatusKindByUserID(catalogItemData.status, catalogItemData.lockingUser);
-
+
return (
<CatalogTile catalogItemTypeClass={catalogItemTypeClass} onSelect={() => {
if (catalogItemData.isOldVersion && catalogItemData.isOldVersion === migrationStatusMapper.OLD_VERSION) {
onMigrate({
softwareProduct: catalogItemData
});
- } else {
+ }
+ else {
onSelect();
}
}} data-test-id={catalogItemTypeClass}>
- <div className='catalog-tile-top item-details'>
- <ItemTypeTitle catalogItemTypeClass={catalogItemTypeClass}/>
- <CatalogTileIcon catalogItemTypeClass={catalogItemTypeClass}/>
- <EntityDetails catalogItemTypeClass={catalogItemTypeClass} catalogItemData={catalogItemData} />
- <ItemStatusInfo itemStatus={itemStatus} catalogItemTypeClass={catalogItemTypeClass} lockingUser={catalogItemData.lockingUser} />
+ <div className='catalog-tile-top item-details'>
+ <ItemTypeTitle catalogItemTypeClass={catalogItemTypeClass}/>
+ <CatalogTileIcon catalogItemTypeClass={catalogItemTypeClass}/>
+ <EntityDetails catalogItemTypeClass={catalogItemTypeClass} catalogItemData={catalogItemData}/>
+ <ItemStatusInfo itemStatus={itemStatus} catalogItemTypeClass={catalogItemTypeClass} lockingUser={catalogItemData.lockingUser}/>
</div>
</CatalogTile>
);
-
+
};
CatalogItemDetails.PropTypes = {
diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogList.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogList.jsx
index 17248e3..51702e6 100644
--- a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogList.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogList.jsx
@@ -15,7 +15,7 @@
*/
import React from 'react';
import i18n from 'nfvo-utils/i18n/i18n.js';
-import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
+import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
const SoftwareProductListHeader = ({selectedVendor, onBack}) => (
<div className='vendor-page-header'>
diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogActionHelper.js
index 73a4475..0d1e399 100644
--- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogActionHelper.js
+++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogActionHelper.js
@@ -26,7 +26,7 @@
function getMessageForMigration(name) {
return (
<div>
- <div>{i18n('{name} needs to be updated. Click ‘Checkout & Update’, to proceed.',{name})}</div>
+ <div>{i18n(`${name} needs to be updated. Click ‘Checkout & Update’, to proceed.`)}</div>
<div>{i18n('Please don’t forget to submit afterwards')}</div>
</div>
);
@@ -65,7 +65,7 @@
type: modalActionTypes.GLOBAL_MODAL_WARNING,
data: {
title: 'WARNING',
- msg: i18n('{name} is locked by user {lockingUser} for self-healing',{name, lockingUser})
+ msg: i18n(`${name} is locked by user ${lockingUser} for self-healing`)
}
});
} else {
diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorItem.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorItem.jsx
index cecccdd..d3d6f9c 100644
--- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorItem.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorItem.jsx
@@ -19,7 +19,7 @@
import classnames from 'classnames';
import VSPOverlay from './VSPOverlay.jsx';
import i18n from 'nfvo-utils/i18n/i18n.js';
-import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
+import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js';
import tooltip from './Tooltip.jsx';
@@ -50,7 +50,7 @@
</div>
<OverlayTrigger placement='top' overlay={tooltip(vendorName)}>
<div className='catalog-tile-item-name'>{vendorName}</div>
- </OverlayTrigger>
+ </OverlayTrigger>
<div
className={classnames('catalog-tile-vsp-count', {active: shouldShowOverlay}, {clickable: softwareProductList.length})}
onClick={(event) => this.handleVspCountClick(event)}
@@ -63,7 +63,7 @@
</div>
</div>
</div>
-
+
{shouldShowOverlay && softwareProductList.length > 0
&& <VSPOverlay onMigrate={onMigrate} VSPList={softwareProductList} onSelectVSP={onSelectVSP} onSeeMore={() => onVendorSelect(vendor)}/>}
</CatalogTile>
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js
index 12f68a2..07d6c74 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js
@@ -22,7 +22,7 @@
import {enums} from 'sdc-app/onboarding/OnboardingConstants.js';
import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js';
-import {navigationItems, mapScreenToNavigationItem} from './SoftwareProductConstants.js';
+import {navigationItems, mapScreenToNavigationItem, onboardingMethod as onboardingMethodTypes} from './SoftwareProductConstants.js';
import SoftwareProductActionHelper from './SoftwareProductActionHelper.js';
import SoftwareProductComponentsActionHelper from './components/SoftwareProductComponentsActionHelper.js';
import SoftwareProductDependenciesActionHelper from './dependencies/SoftwareProductDependenciesActionHelper.js';
@@ -36,7 +36,7 @@
return activeItemId;
}
-const buildComponentNavigationBarGroups = ({componentId, meta}) => {
+const buildComponentNavigationBarGroups = ({componentId, meta, hasImages}) => {
const groups = ([
{
id: navigationItems.GENERAL + '|' + componentId,
@@ -64,6 +64,12 @@
disabled: false,
meta
}, {
+ id: navigationItems.IMAGES + '|' + componentId,
+ name: i18n('Images'),
+ disabled: false,
+ hidden: (!hasImages),
+ meta
+ }, {
id: navigationItems.PROCESS_DETAILS + '|' + componentId,
name: i18n('Process Details'),
disabled: false,
@@ -79,9 +85,9 @@
return groups;
};
-const buildNavigationBarProps = ({softwareProduct, meta, screen, componentId, componentsList, mapOfExpandedIds}) => {
+const buildNavigationBarProps = ({softwareProduct, meta, screen, componentId, componentsList, mapOfExpandedIds, imagesNavigationList}) => {
const {softwareProductEditor: {data: currentSoftwareProduct = {}}} = softwareProduct;
- const {id, name} = currentSoftwareProduct;
+ const {id, name, onboardingMethod} = currentSoftwareProduct;
const groups = [{
id: id,
name: name,
@@ -96,6 +102,13 @@
name: i18n('General'),
disabled: false,
meta
+ },
+ {
+ id: navigationItems.DEPLOYMENT_FLAVORS,
+ name: i18n('Deployment Flavors'),
+ disabled: false,
+ hidden: onboardingMethod !== onboardingMethodTypes.MANUAL,
+ meta
}, {
id: navigationItems.PROCESS_DETAILS,
name: i18n('Process Details'),
@@ -135,7 +148,8 @@
name: displayName,
meta,
expanded: mapOfExpandedIds[navigationItems.COMPONENTS + '|' + id] === true && screen !== enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE,
- items: buildComponentNavigationBarGroups({componentId: id, meta})
+ items: buildComponentNavigationBarGroups({componentId: id, meta,
+ hasImages : (onboardingMethod === onboardingMethodTypes.MANUAL || imagesNavigationList[id] === true)})
}))
]
}
@@ -179,17 +193,18 @@
const mapStateToProps = ({softwareProduct}, {currentScreen: {screen, props: {componentId}}}) => {
const {softwareProductEditor, softwareProductComponents, softwareProductDependencies} = softwareProduct;
const {mapOfExpandedIds = []} = softwareProductEditor;
- const {componentsList = []} = softwareProductComponents;
+ const {componentsList = [], images: {imagesNavigationList}} = softwareProductComponents;
+
const meta = buildMeta({softwareProduct, componentId, softwareProductDependencies});
return {
versionControllerProps: buildVersionControllerProps(softwareProduct),
- navigationBarProps: buildNavigationBarProps({softwareProduct, meta, screen, componentId, componentsList, mapOfExpandedIds}),
+ navigationBarProps: buildNavigationBarProps({softwareProduct, meta, screen, componentId, componentsList, mapOfExpandedIds, imagesNavigationList}),
meta
};
};
-const autoSaveBeforeNavigate = ({dispatch, screen, softwareProductId, componentId,
- meta: {isReadOnlyMode, softwareProduct, version, qdata, softwareProductDependencies,
+const autoSaveBeforeNavigate = ({dispatch, screen, softwareProductId, componentId,
+ meta: {isReadOnlyMode, softwareProduct, version, qdata, softwareProductDependencies,
currentComponentMeta: {componentData, componentQdata}}}) => {
let promise;
if (isReadOnlyMode) {
@@ -208,6 +223,7 @@
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;
@@ -242,6 +258,9 @@
case navigationItems.NETWORKS:
OnboardingActionHelper.navigateToComponentNetwork(dispatch, {softwareProductId, componentId: nextComponentId, version});
break;
+ case navigationItems.IMAGES:
+ OnboardingActionHelper.navigateToComponentImages(dispatch, {softwareProductId, componentId: nextComponentId, version});
+ break;
case navigationItems.STORAGE:
OnboardingActionHelper.navigateToComponentStorage(dispatch, {softwareProductId, componentId: nextComponentId, version});
break;
@@ -266,7 +285,7 @@
let {heatSetup, heatSetupCache} = meta;
let heatSetupPopupPromise = screen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS ?
HeatSetupActionHelper.heatSetupLeaveConfirmation(dispatch, {softwareProductId, heatSetup, heatSetupCache}) :
- Promise.resolve();
+ Promise.resolve();
let preNavigate = meta ? autoSaveBeforeNavigate({dispatch, screen, meta, softwareProductId, componentId: currentComponentId}) : Promise.resolve();
version = version || (meta ? meta.version : undefined);
Promise.all([preNavigate, heatSetupPopupPromise]).then(() => {
@@ -277,6 +296,9 @@
case navigationItems.GENERAL:
OnboardingActionHelper.navigateToSoftwareProductDetails(dispatch, {softwareProductId, version});
break;
+ case navigationItems.DEPLOYMENT_FLAVORS:
+ OnboardingActionHelper.navigateToSoftwareProductDeployment(dispatch, {softwareProductId, version});
+ break;
case navigationItems.PROCESS_DETAILS:
OnboardingActionHelper.navigateToSoftwareProductProcesses(dispatch, {softwareProductId, version});
break;
@@ -299,7 +321,7 @@
onComponentNavigate(dispatch, {id, softwareProductId, version, screen, currentComponentId});
break;
}
- }).catch(() => {});
+ }).catch((e) => {console.error(e);});
}
};
@@ -311,6 +333,7 @@
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 = () => {
@@ -335,7 +358,7 @@
OnboardingActionHelper.navigateToSoftwareProductActivityLog(dispatch, {softwareProductId, version: newVersion});
}
});
- }).catch(() => {});
+ }).catch((e) => {console.error(e);});
};
return props;
};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js
index 6f53886..d6ba86a 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js
@@ -27,6 +27,7 @@
import {actionTypes as HeatSetupActions} from 'sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupConstants.js';
import {actionTypes as featureGroupsActionConstants} from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConstants.js';
import {actionTypes as licenseAgreementActionTypes} from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js';
+import {actionTypes as componentActionTypes} from './components/SoftwareProductComponentsConstants.js';
import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
import {PRODUCT_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
@@ -57,7 +58,8 @@
vendorName: softwareProduct.vendorName,
licensingVersion: softwareProduct.licensingVersion && softwareProduct.licensingVersion.id ? softwareProduct.licensingVersion : {} ,
icon: softwareProduct.icon,
- licensingData: softwareProduct.licensingData
+ licensingData: softwareProduct.licensingData,
+ onboardingMethod: softwareProduct.onboardingMethod
});
}
@@ -249,7 +251,8 @@
processAndValidateHeatCandidate(dispatch, {softwareProductId, version}){
return validateHeatCandidate(softwareProductId, version).then(response => {
if (response.status === 'Success') {
- SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version});
+ let isFetchImageDetails = true;
+ SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version, isFetchImageDetails});
SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, {softwareProductId, version});
}
});
@@ -459,8 +462,20 @@
},
/** for the next verision */
- addComponent(dispatch) {
- return dispatch;
+ addComponent(dispatch, {softwareProductId, modalClassName}) {
+ SoftwareProductComponentsActionHelper.clearComponentCreationData(dispatch);
+ dispatch({
+ type: componentActionTypes.COMPONENT_CREATE_OPEN
+ });
+ dispatch({
+ type: modalActionTypes.GLOBAL_MODAL_SHOW,
+ data: {
+ modalComponentName: modalContentMapper.COMPONENT_CREATION,
+ modalComponentProps: {softwareProductId},
+ modalClassName,
+ title: 'Create Virtual Function Component'
+ }
+ });
},
migrateSoftwareProduct(dispatch, {softwareProduct}) {
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js
index f29b0f6..0379ee5 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js
@@ -38,11 +38,13 @@
VENDOR_SOFTWARE_PRODUCT: 'vendor-software-product',
GENERAL: 'general',
PROCESS_DETAILS: 'process-details',
- NETWORKS: 'networks',
- DEPENDENCIES: 'dependencies',
+ DEPLOYMENT_FLAVORS: 'deployment-flavor',
+ NETWORKS: 'networks',
+ IMAGES: 'images',
ATTACHMENTS: 'attachments',
ACTIVITY_LOG: 'activity-log',
COMPONENTS: 'components',
+ DEPENDENCIES: 'dependencies',
COMPUTE: 'compute',
LOAD_BALANCING: 'load-balancing',
@@ -50,6 +52,11 @@
MONITORING: 'monitoring'
});
+export const onboardingMethod = {
+ MANUAL: 'Manual',
+ HEAT: 'HEAT'
+};
+
export const forms = keyMirror({
VENDOR_SOFTWARE_PRODUCT_DETAILS: 'vendor-software-product-details',
});
@@ -61,6 +68,7 @@
[enums.SCREEN.SOFTWARE_PRODUCT_DETAILS]: navigationItems.GENERAL,
[enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS]: navigationItems.ATTACHMENTS,
[enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES]: navigationItems.PROCESS_DETAILS,
+ [enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT]: navigationItems.DEPLOYMENT_FLAVORS,
[enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS]: navigationItems.NETWORKS,
[enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG]: navigationItems.ACTIVITY_LOG,
[enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES]: navigationItems.DEPENDENCIES,
@@ -69,6 +77,7 @@
[enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE]: navigationItems.COMPUTE,
[enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING]: navigationItems.LOAD_BALANCING,
[enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK]: navigationItems.NETWORKS,
+ [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES]: navigationItems.IMAGES,
[enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE]: navigationItems.STORAGE,
[enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES]: navigationItems.PROCESS_DETAILS,
[enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING]: navigationItems.MONITORING,
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js
index 97988d8..5248c4e 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js
@@ -22,6 +22,8 @@
import SoftwareProductDetailsReducer from './details/SoftwareProductDetailsReducer.js';
import SoftwareProductProcessesListReducer from './processes/SoftwareProductProcessesListReducer.js';
import SoftwareProductProcessesEditorReducer from './processes/SoftwareProductProcessesEditorReducer.js';
+import SoftwareProductDeploymentListReducer from './deployment/SoftwareProductDeploymentListReducer.js';
+import SoftwareProductDeploymentEditorReducer from './deployment/editor/SoftwareProductDeploymentEditorReducer.js';
import SoftwareProductNetworksListReducer from './networks/SoftwareProductNetworksListReducer.js';
import SoftwareProductComponentsListReducer from './components/SoftwareProductComponentsListReducer.js';
import SoftwareProductComponentEditorReducer from './components/SoftwareProductComponentEditorReducer.js';
@@ -31,12 +33,19 @@
import {actionTypes as componentProcessesActionTypes} from './components/processes/SoftwareProductComponentProcessesConstants.js';
import SoftwareProductComponentsNICListReducer from './components/network/SoftwareProductComponentsNICListReducer.js';
import SoftwareProductComponentsNICEditorReducer from './components/network/SoftwareProductComponentsNICEditorReducer.js';
+import SoftwareProductComponentsImageListReducer from './components/images/SoftwareProductComponentsImageListReducer.js';
+import SoftwareProductComponentsImageEditorReducer from './components/images/SoftwareProductComponentsImageEditorReducer.js';
+import SoftwareProductComponentsImageNavigationReducer from './components/images/SoftwareProductComponentsImageNavigationReducer.js';
+import SoftwareProductComponentsNICCreationReducer from './components/network/NICCreation/NICCreationReducer.js';
import SoftwareProductComponentsMonitoringReducer from './components/monitoring/SoftwareProductComponentsMonitoringReducer.js';
+import SoftwareProductComponentsComputeFlavorListReducer from './components/compute/computeComponents/computeFlavor/ComputeFlavorListReducer.js';
+import SoftwareProductComponentsComputeFlavorReducer from './components/compute/computeComponents/computeFlavor/ComputeFlavorReducer.js';
import {createPlainDataReducer} from 'sdc-app/common/reducers/PlainDataReducer.js';
import SoftwareProductDependenciesReducer from './dependencies/SoftwareProductDependenciesReducer.js';
import {createJSONSchemaReducer, createComposedJSONSchemaReducer} from 'sdc-app/common/reducers/JSONSchemaReducer.js';
-import {COMPONENTS_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js';
+import {COMPONENTS_QUESTIONNAIRE, COMPONENTS_COMPUTE_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js';
import {NIC_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js';
+import {IMAGE_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageConstants.js';
export default combineReducers({
softwareProductAttachments: combineReducers({
@@ -51,6 +60,10 @@
processesEditor: createPlainDataReducer(SoftwareProductProcessesEditorReducer),
processToDelete: (state = false, action) => action.type === processesActionTypes.SOFTWARE_PRODUCT_PROCESS_DELETE_CONFIRM ? action.processToDelete : state
}),
+ softwareProductDeployment: combineReducers({
+ deploymentFlavors: SoftwareProductDeploymentListReducer,
+ deploymentFlavorEditor: createPlainDataReducer(SoftwareProductDeploymentEditorReducer)
+ }),
softwareProductNetworks: combineReducers({
networksList: SoftwareProductNetworksListReducer
}),
@@ -65,7 +78,17 @@
}),
network: combineReducers({
nicList: SoftwareProductComponentsNICListReducer,
- nicEditor: createPlainDataReducer(createComposedJSONSchemaReducer(NIC_QUESTIONNAIRE, SoftwareProductComponentsNICEditorReducer))
+ nicEditor: createPlainDataReducer(createComposedJSONSchemaReducer(NIC_QUESTIONNAIRE, SoftwareProductComponentsNICEditorReducer)),
+ nicCreation: createPlainDataReducer(SoftwareProductComponentsNICCreationReducer)
+ }),
+ images: combineReducers({
+ imagesList: SoftwareProductComponentsImageListReducer,
+ imagesNavigationList: SoftwareProductComponentsImageNavigationReducer,
+ imageEditor: createPlainDataReducer(createComposedJSONSchemaReducer(IMAGE_QUESTIONNAIRE, SoftwareProductComponentsImageEditorReducer))
+ }),
+ computeFlavor: combineReducers({
+ computesList: SoftwareProductComponentsComputeFlavorListReducer,
+ computeEditor: createPlainDataReducer(createComposedJSONSchemaReducer(COMPONENTS_COMPUTE_QUESTIONNAIRE, SoftwareProductComponentsComputeFlavorReducer)),
}),
monitoring: SoftwareProductComponentsMonitoringReducer
}),
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupView.jsx
index 0d8bc58..901a583 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupView.jsx
@@ -14,14 +14,14 @@
* permissions and limitations under the License.
*/
import React, {Component} from 'react';
-import Button from 'react-bootstrap/lib/Button.js';
+import Button from 'sdc-ui/lib/react/Button.js';
import Tooltip from 'react-bootstrap/lib/Tooltip.js';
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js';
import FormControl from 'react-bootstrap/lib/FormControl.js';
import i18n from 'nfvo-utils/i18n/i18n.js';
import SelectInput from 'nfvo-components/input/SelectInput.jsx';
import Icon from 'nfvo-components/icon/Icon.jsx';
-import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
+import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
import {fileTypes} from './HeatSetupConstants.js';
import {tabsMapping} from '../SoftwareProductAttachmentsConstants.js';
import {sortable} from 'react-sortable';
@@ -76,8 +76,8 @@
<div className='modules-list-wrapper'>
<div className='modules-list-header'>
<div className='modules-list-controllers'>
- {!isBaseExist && <Button bsStyle='link' onClick={onBaseAdd} disabled={unassigned.length === 0}>{i18n('Add Base')}</Button>}
- <Button bsStyle='link' onClick={onModuleAdd} disabled={unassigned.length === 0}>{i18n('Add Module')}</Button>
+ {!isBaseExist && <Button btnType='link' onClick={onBaseAdd} disabled={unassigned.length === 0}>{i18n('Add Base')}</Button>}
+ <Button btnType='link' onClick={onModuleAdd} disabled={unassigned.length === 0}>{i18n('Add Module')}</Button>
</div>
</div>
<ul>{listItems}</ul>
@@ -102,7 +102,7 @@
return (
<div className='go-to-validation-button-wrapper'>
<div className='all-files-assigned'>{i18n(displayText)}</div>
- {heatDataExist && <div className={'link'} onClick={onClick} data-test-id='go-to-validation'>{i18n('Proceed To Validation')}<SVGIcon name='angle-right'/></div>}
+ {heatDataExist && <div className={'link'} onClick={onClick} data-test-id='go-to-validation'>{i18n('Proceed To Validation')}<SVGIcon name='angleRight'/></div>}
</div>
);
};
@@ -212,7 +212,7 @@
data-test-id={isBase ? 'base-name' : 'module-name'}/>}
</div>
</div>
- <SVGIcon name='trash-o' onClick={() => onModuleDelete(name)} data-test-id='module-delete'/>
+ <SVGIcon name='trashO' onClick={() => onModuleDelete(name)} data-test-id='module-delete'/>
</div>
<div className='modules-list-item-selectors'>
<SelectWithFileType
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationView.jsx
index 25ad90f..f2d5de4 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationView.jsx
@@ -17,7 +17,7 @@
import classNames from 'classnames';
import Collapse from 'react-bootstrap/lib/Collapse.js';
import Icon from 'nfvo-components/icon/Icon.jsx';
-import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
+import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
import i18n from 'nfvo-utils/i18n/i18n.js';
import {mouseActions, errorLevels, nodeFilters} from './HeatValidationConstants.js';
@@ -68,7 +68,7 @@
isFolder &&
<div onClick={() => toggleExpanded(path)}
className='tree-node-expander'>
- <SVGIcon name={!node.expanded ? 'chevron-up' : 'chevron-down'} data-test-id='validation-tree-block-toggle'/>
+ <SVGIcon name={!node.expanded ? 'chevronUp' : 'chevronDown'} data-test-id='validation-tree-block-toggle'/>
</div>
}
{
@@ -205,23 +205,19 @@
key={error.name + error.errorMessage + error.parentName + rand}
className='error-item' data-test-id='validation-error'>
{error.level === errorLevels.WARNING ?
- <SVGIcon name='exclamation-triangle-line' iconClassName='large' /> : <Icon image='error-lg' /> }
+ <SVGIcon name='exclamationTriangleLine' iconClassName='large' /> : <Icon image='error-lg' /> }
<span className='error-item-file-type'>
{
(this.props.selectedNode === nodeFilters.ALL) ?
<span>
<span className='error-file-name'>
- {i18n('{errorName}:', {
- errorName: error.name
- })}
+ {i18n(`${error.name}`)}
</span>
<span>
- {i18n('{message}', {message: error.errorMessage})}
+ {i18n(error.errorMessage)}
</span>
</span> :
- i18n('{errorMsg}', {
- errorMsg: error.errorMessage
- })
+ i18n(error.errorMesage)
}
</span>
</div>
@@ -249,7 +245,7 @@
<div className={'error-text ' + (size ? size : '')} data-test-id='validation-error-count'>{errors.errorCount}</div>
</div>}
{(errors.warningCount > 0) && <div className='counter'>
- <SVGIcon name='exclamation-triangle-line' iconClassName={size} />
+ <SVGIcon name='exclamationTriangleLine' iconClassName={size} />
<div className={'warning-text ' + (size ? size : '')} data-test-id='validation-warning-count'>{errors.warningCount}</div>
</div>}
</div>);
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentEditorReducer.js
index 41e7556..b13bde0 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentEditorReducer.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentEditorReducer.js
@@ -17,6 +17,24 @@
export default (state = {}, action) => {
switch (action.type) {
+ case actionTypes.COMPONENT_CREATE_OPEN:
+ return {
+ ...state,
+ formName: forms.CREATE_FORM,
+ formReady: null,
+ genericFieldInfo: {
+ 'displayName' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'required', data: true}, {type: 'validateName', data: true}, {type: 'maxLength', data: 25}]
+ },
+ 'description' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'maxLength', data: 1000}]
+ }
+ }
+ };
case actionTypes.COMPONENT_LOAD:
return {
...state,
@@ -34,6 +52,11 @@
errorText: '',
validations: []
},
+ 'nfcFunction' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'maxLength', data: 30}]
+ },
'description' : {
isValid: true,
errorText: '',
@@ -41,6 +64,27 @@
}
}
};
+ case actionTypes.COMPONENT_UPDATE:
+ return {
+ ...state,
+ data: action.component
+ };
+ case actionTypes.COMPONENT_QUESTIONNAIRE_UPDATE:
+ return {
+ ...state,
+ qdata: action.payload.qdata || state.qdata,
+ qschema: action.payload.qschema || state.qschema
+ };
+ case actionTypes.COMPONENT_DATA_CHANGED:
+ return {
+ ...state,
+ data: {
+ ...state.data,
+ ...action.deltaData
+ }
+ };
+ case actionTypes.COMPONENT_DATA_CLEAR:
+ return {};
default:
return state;
}
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponents.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponents.js
new file mode 100644
index 0000000..61aebdf
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponents.js
@@ -0,0 +1,65 @@
+import {connect} from 'react-redux';
+import React from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+
+import SoftwareProductComponentsList from './SoftwareProductComponentsList.js';
+import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js';
+import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js';
+import SoftwareProductComponentsActionHelper from '../components/SoftwareProductComponentsActionHelper.js';
+import {onboardingMethod} from '../SoftwareProductConstants.js';
+import ConfirmationModalConstants from 'nfvo-components/modal/GlobalModalConstants.js';
+
+const generateMessage = (name) => {
+ return i18n(`Are you sure you want to delete ${name}?`);
+};
+
+const mapStateToProps = ({softwareProduct}) => {
+ let {softwareProductEditor: {data: currentSoftwareProduct}, softwareProductComponents} = softwareProduct;
+ let {componentsList} = softwareProductComponents;
+ let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct);
+
+ return {
+ currentSoftwareProduct,
+ isReadOnlyMode,
+ componentsList,
+ isManual: currentSoftwareProduct.onboardingMethod === onboardingMethod.MANUAL
+
+ };
+};
+
+class SoftwareProductComponentsView extends React.Component {
+ render() {
+ let {currentSoftwareProduct, isReadOnlyMode, componentsList, isManual, onDeleteComponent} = this.props;
+ return (
+ <SoftwareProductComponentsList
+ isReadOnlyMode={isReadOnlyMode}
+ componentsList={componentsList}
+ onDeleteComponent={onDeleteComponent}
+ isManual={isManual}
+ currentSoftwareProduct={currentSoftwareProduct}/>);
+ }
+
+}
+
+const mapActionToProps = (dispatch) => {
+ return {
+ onComponentSelect: ({id: softwareProductId, componentId, version}) => {
+ OnboardingActionHelper.navigateToSoftwareProductComponentGeneralAndUpdateLeftPanel(dispatch, {softwareProductId, componentId, version });
+ },
+ onAddComponent: (softwareProductId) => SoftwareProductComponentsActionHelper.addComponent(dispatch, {softwareProductId}),
+ onDeleteComponent: (component, softwareProductId, version) => dispatch({
+ type: ConfirmationModalConstants.GLOBAL_MODAL_WARNING,
+ data:{
+ msg: generateMessage(component.displayName),
+ onConfirmed: ()=>SoftwareProductComponentsActionHelper.deleteComponent(dispatch,
+ {
+ softwareProductId,
+ componentId: component.id,
+ version
+ })
+ }
+ })
+ };
+};
+
+export default connect(mapStateToProps, mapActionToProps, null, {withRef: true})(SoftwareProductComponentsView);
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js
index 4e526d3..71dc832 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js
@@ -18,6 +18,8 @@
import {actionTypes, COMPONENTS_QUESTIONNAIRE} from './SoftwareProductComponentsConstants.js';
import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
+import SoftwareProductComponentsImageActionHelper from './images/SoftwareProductComponentsImageActionHelper.js';
+import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
function baseUrl(softwareProductId, version) {
const versionId = version.id;
@@ -46,17 +48,53 @@
name: vspComponent.name,
displayName: vspComponent.displayName,
vfcCode: vspComponent.vfcCode,
+ nfcFunction: vspComponent.nfcFunction,
description: vspComponent.description
});
}
+function deleteSoftwareProductComponent(softwareProductId, componentId, version) {
+ return RestAPIUtil.destroy(`${baseUrl(softwareProductId, version)}/${componentId}`,);
+}
+
+
+function postSoftwareProductComponent(softwareProductId, vspComponent, version) {
+
+ return RestAPIUtil.post(`${baseUrl(softwareProductId, version)}`, {
+ name: vspComponent.displayName,
+ displayName: vspComponent.displayName,
+ description: vspComponent.description
+ });
+}
+
+
const SoftwareProductComponentsActionHelper = {
- fetchSoftwareProductComponents(dispatch, {softwareProductId, version}) {
+ fetchSoftwareProductComponents(dispatch, {softwareProductId, version, isFetchImageDetails = false}) {
return fetchSoftwareProductComponents(softwareProductId, version).then(response => {
- dispatch({
- type: actionTypes.COMPONENTS_LIST_UPDATE,
- componentsList: response.results
- });
+ let componentImagesCalls = [];
+ if (isFetchImageDetails && response.listCount) {
+ response.results.map(component => {
+ let componentId = component.id;
+ componentImagesCalls[componentImagesCalls.length] =
+ SoftwareProductComponentsImageActionHelper.fetchImagesList(dispatch, {
+ softwareProductId,
+ componentId,
+ version
+ });
+
+ });
+ return Promise.all(componentImagesCalls).then(() => {
+ dispatch({
+ type: actionTypes.COMPONENTS_LIST_UPDATE,
+ componentsList: response.results
+ });
+ });
+ } else {
+ dispatch({
+ type: actionTypes.COMPONENTS_LIST_UPDATE,
+ componentsList: response.results
+ });
+ }
});
},
@@ -110,7 +148,45 @@
type: actionTypes.COMPONENTS_LIST_UPDATE,
componentsList: []
});
- }
+ },
+
+ createSoftwareProductComponent(dispatch,{softwareProductId, componentData, version}) {
+ SoftwareProductComponentsActionHelper.closeComponentCreationModal(dispatch);
+ /* for mock only */
+
+ dispatch({
+ type: actionTypes.COMPONENTS_LIST_UPDATE,
+ componentsList: [{id: '123', ...componentData}]
+ });
+
+ postSoftwareProductComponent(softwareProductId, componentData, version).then(() => {
+ SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version});
+ });
+ },
+
+ clearComponentCreationData(dispatch) {
+ dispatch({
+ type: actionTypes.COMPONENT_DATA_CLEAR
+ });
+ },
+
+ closeComponentCreationModal(dispatch) {
+ dispatch({
+ type: modalActionTypes.GLOBAL_MODAL_CLOSE
+ });
+ SoftwareProductComponentsActionHelper.clearComponentCreationData(dispatch);
+ },
+
+ deleteComponent(dispatch, {softwareProductId, componentId, version}) {
+ deleteSoftwareProductComponent(softwareProductId, componentId, version);
+ dispatch({
+ type: actionTypes.COMPONENT_DELETE,
+ componentId: componentId
+ });
+ },
+
+
+
};
export default SoftwareProductComponentsActionHelper;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js
index 9307b09..35633b6 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js
@@ -18,7 +18,13 @@
export const actionTypes = keyMirror({
COMPONENTS_LIST_UPDATE: null,
COMPONENTS_LIST_EDIT: null,
- COMPONENT_LOAD: null
+ COMPONENT_UPDATE: null,
+ COMPONENT_DATA_CHANGED: null,
+ COMPONENT_DATA_CLEAR: null,
+ COMPONENT_QUESTIONNAIRE_UPDATE: null,
+ COMPONENT_DELETE: null,
+ COMPONENT_LOAD: null,
+ COMPONENT_CREATE_OPEN: null
});
export const storageConstants = keyMirror({
@@ -30,16 +36,20 @@
export const forms = keyMirror({
ALL_SPC_FORMS: null,
- NIC_EDIT_FORM: null
+ NIC_EDIT_FORM: null,
+ CREATE_FORM: null,
+ IMAGE_EDIT_FORM: null
});
export const COMPONENTS_QUESTIONNAIRE = 'component';
+export const COMPONENTS_COMPUTE_QUESTIONNAIRE = 'compute';
export const navigationItems = keyMirror({
STORAGE: 'Storage',
PROCESS_DETAILS: 'Process Details',
MONITORING: 'Monitoring',
NETWORK: 'Network',
+ IMAGES: 'Images',
COMPUTE: 'Compute',
LOAD_BALANCING: 'High Availability & Load Balancing'
});
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsList.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsList.js
index f789a92..bd4c2fa 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsList.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsList.js
@@ -14,21 +14,16 @@
* permissions and limitations under the License.
*/
import {connect} from 'react-redux';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+
import SoftwareProductComponentsListView from './SoftwareProductComponentsListView.jsx';
import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js';
-import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js';
+import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js';
+import SoftwareProductComponentsActionHelper from '../components/SoftwareProductComponentsActionHelper.js';
+import {actionTypes as globalModalActions} from 'nfvo-components/modal/GlobalModalConstants.js';
-
-const mapStateToProps = ({softwareProduct}) => {
- let {softwareProductEditor: {data: currentSoftwareProduct}, softwareProductComponents} = softwareProduct;
- let {componentsList} = softwareProductComponents;
- let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct);
-
- return {
- currentSoftwareProduct,
- isReadOnlyMode,
- componentsList
- };
+const generateMessage = (name) => {
+ return i18n(`Are you sure you want to delete ${name}?`);
};
@@ -36,8 +31,21 @@
return {
onComponentSelect: ({id: softwareProductId, componentId, version}) => {
OnboardingActionHelper.navigateToSoftwareProductComponentGeneralAndUpdateLeftPanel(dispatch, {softwareProductId, componentId, version });
- }
+ },
+ onAddComponent: (softwareProductId) => SoftwareProductActionHelper.addComponent(dispatch, {softwareProductId, modalClassName: 'create-vfc-modal'}),
+ onDeleteComponent: (component, softwareProductId, version) => dispatch({
+ type: globalModalActions.GLOBAL_MODAL_WARNING,
+ data:{
+ msg: generateMessage(component.displayName),
+ onConfirmed: ()=>SoftwareProductComponentsActionHelper.deleteComponent(dispatch,
+ {
+ softwareProductId,
+ componentId: component.id,
+ version
+ })
+ }
+ })
};
};
-export default connect(mapStateToProps, mapActionToProps, null, {withRef: true})(SoftwareProductComponentsListView);
+export default connect(null, mapActionToProps, null, {withRef: true})(SoftwareProductComponentsListView);
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListReducer.js
index c7aaca5..92211e0 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListReducer.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListReducer.js
@@ -22,6 +22,8 @@
case actionTypes.COMPONENTS_LIST_EDIT:
const indexForEdit = state.findIndex(component => component.id === action.component.id);
return [...state.slice(0, indexForEdit), action.component, ...state.slice(indexForEdit + 1)];
+ case actionTypes.COMPONENT_DELETE:
+ return state.filter(component => component.id !== action.componentId);
default:
return state;
}
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListView.jsx
index c28831f..a2a1964 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListView.jsx
@@ -40,11 +40,11 @@
};
render() {
- let {componentsList = []} = this.props;
+ let {componentsList = [], isManual} = this.props;
return (
<div className=''>
{
- componentsList.length > 0 && this.renderComponents()
+ (componentsList.length > 0 || isManual) && this.renderComponents()
}
</div>
);
@@ -52,15 +52,16 @@
renderComponents() {
const {localFilter} = this.state;
- let {isReadOnlyMode} = this.props;
-
+ const {isManual, onAddComponent, isReadOnlyMode, currentSoftwareProduct: {id: softwareProductId}, componentsList } = this.props;
return (
<ListEditorView
title={i18n('Virtual Function Components')}
filterValue={localFilter}
placeholder={i18n('Filter Components')}
onFilter={value => this.setState({localFilter: value})}
- isReadOnlyMode={isReadOnlyMode}
+ isReadOnlyMode={isReadOnlyMode || !!this.filterList().length}
+ plusButtonTitle={i18n('Add Component')}
+ onAdd={isManual && componentsList.length === 0 ? () => onAddComponent(softwareProductId) : false}
twoColumns>
{this.filterList().map(component => this.renderComponentsListItem(component))}
</ListEditorView>
@@ -69,11 +70,12 @@
renderComponentsListItem(component) {
let {id: componentId, name, displayName, description = ''} = component;
- let {currentSoftwareProduct: {id, version}, onComponentSelect} = this.props;
+ let {currentSoftwareProduct: {id, version}, onComponentSelect, isManual, isReadOnlyMode, onDeleteComponent} = this.props;
return (
<ListEditorItemView
key={name + Math.floor(Math.random() * (100 - 1) + 1).toString()}
className='list-editor-item-view'
+ onDelete={isManual && !isReadOnlyMode ? () => onDeleteComponent(component, id, version) : false}
onSelect={() => onComponentSelect({id, componentId, version})}>
<ListEditorItemViewField>
<div className='name'>{displayName}</div>
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/ComputeFlavorActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/ComputeFlavorActionHelper.js
new file mode 100644
index 0000000..02c09fb
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/ComputeFlavorActionHelper.js
@@ -0,0 +1,169 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js';
+import Configuration from 'sdc-app/config/Configuration.js';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import {actionTypes} from './computeComponents/computeFlavor/ComputeFlavorConstants.js';
+import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js';
+import {actionTypes as globalModalActionTypes, modalSizes} from 'nfvo-components/modal/GlobalModalConstants.js';
+import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
+import {COMPONENTS_COMPUTE_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js';
+
+function baseUrl(softwareProductId, componentId, version) {
+ const versionId = version.id;
+ const restPrefix = Configuration.get('restPrefix');
+ return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${versionId}/components/${componentId}/compute-flavors`;
+}
+
+function baseUrlVSPLevel(softwareProductId, version){
+ const versionId = version.id;
+ const restPrefix = Configuration.get('restPrefix');
+ return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${versionId}/compute-flavors`;
+}
+
+function fetchComputesList(softwareProductId, componentId, version){
+ return RestAPIUtil.fetch(`${baseUrl(softwareProductId, componentId, version)}`);
+}
+
+function fetchComputesListForVSP(softwareProductId, version){
+ return RestAPIUtil.fetch(`${baseUrlVSPLevel(softwareProductId, version)}`);
+}
+
+function fetchCompute(softwareProductId, componentId, computeId, version) {
+ return RestAPIUtil.fetch(`${baseUrl(softwareProductId, componentId, version)}/${computeId}`);
+}
+
+function fetchComputeQuestionnaire({softwareProductId, componentId, computeId, version}) {
+ return RestAPIUtil.fetch(`${baseUrl(softwareProductId, componentId, version)}/${computeId}/questionnaire`);
+}
+
+function postCompute({softwareProductId, componentId, compute, version}) {
+ return RestAPIUtil.post(baseUrl(softwareProductId, componentId, version), compute);
+}
+
+function putCompute({softwareProductId, componentId, compute, version}) {
+ const computeData = {
+ name: compute.name,
+ description: compute.description
+ };
+ return RestAPIUtil.put(`${baseUrl(softwareProductId, componentId, version)}/${compute.id}`, computeData);
+}
+
+function putComputeQuestionnaire({softwareProductId, componentId, computeId, qdata, version}) {
+ return RestAPIUtil.put(`${baseUrl(softwareProductId, componentId, version)}/${computeId}/questionnaire`, qdata);
+}
+
+function deleteCompute({softwareProductId, componentId, computeId, version}) {
+ return RestAPIUtil.destroy(`${baseUrl(softwareProductId, componentId, version)}/${computeId}`);
+}
+
+
+const ComputeFlavorActionHelper = {
+ openComputeEditor(dispatch, {props}) {
+ dispatch({
+ type: actionTypes.computeEditor.LOAD_EDITOR_DATA,
+ compute: props.compute || {}
+ });
+ dispatch({
+ type: globalModalActionTypes.GLOBAL_MODAL_SHOW,
+ data: {
+ modalComponentName: modalContentMapper.COMPONENT_COMPUTE_FLAVOR_EDITOR,
+ modalClassName: `compute-flavor-editor-modal-${props.compute ? 'edit' : 'create'}`,
+ modalComponentProps: {...props, size: props.compute ? modalSizes.LARGE : undefined, dialogClassName:'compute-flavor-editor-modal'},
+ title: `${props.compute ? i18n('Edit Compute Flavor') : i18n('Create New Compute Flavor')}`
+ }
+ });
+ },
+
+ closeComputeEditor(dispatch){
+ dispatch({
+ type: globalModalActionTypes.GLOBAL_MODAL_CLOSE
+ });
+ dispatch({
+ type: actionTypes.computeEditor.CLEAR_DATA
+ });
+ },
+
+ fetchComputesList(dispatch, {softwareProductId, componentId, version}) {
+ return fetchComputesList(softwareProductId, componentId, version).then(response => dispatch({
+ type: actionTypes.COMPUTE_FLAVORS_LIST_LOADED,
+ response
+ }));
+ },
+
+ fetchComputesListForVSP(dispatch, {softwareProductId, version}) {
+ return fetchComputesListForVSP(softwareProductId, version).then(response => dispatch({
+ type: actionTypes.COMPUTE_FLAVORS_LIST_LOADED,
+ response
+ }));
+ },
+
+ loadComputeData({softwareProductId, componentId, computeId, version}) {
+ return fetchCompute(softwareProductId, componentId, computeId, version);
+ },
+
+ loadComputeQuestionnaire(dispatch, {softwareProductId, componentId, computeId, version}) {
+ return fetchComputeQuestionnaire({softwareProductId, componentId, computeId, version}).then(response =>
+ ValidationHelper.qDataLoaded(dispatch, {qName: COMPONENTS_COMPUTE_QUESTIONNAIRE ,response: {
+ qdata: response.data ? JSON.parse(response.data) : {},
+ qschema: JSON.parse(response.schema)
+ }})
+ );
+ },
+
+ loadCompute(dispatch, {softwareProductId, componentId, version, computeId, isReadOnlyMode}){
+ return ComputeFlavorActionHelper.loadComputeData({softwareProductId, componentId, computeId, version}).then(({data}) =>
+ ComputeFlavorActionHelper.loadComputeQuestionnaire(dispatch, {softwareProductId, componentId, computeId, version}).then(() =>
+ ComputeFlavorActionHelper.openComputeEditor(dispatch, {props: {softwareProductId, componentId, version, isReadOnlyMode, compute: {id: computeId, ...data}}})
+ ));
+ },
+
+ saveComputeDataAndQuestionnaire(dispatch, {softwareProductId, componentId, data: compute, qdata, version}) {
+ ComputeFlavorActionHelper.closeComputeEditor(dispatch);
+ if(compute.id) {
+ return Promise.all([
+ putComputeQuestionnaire({softwareProductId, componentId, computeId: compute.id, qdata, version}),
+ putCompute({softwareProductId, componentId, compute, version}).then(() => {
+ dispatch({
+ type: actionTypes.COMPUTE_LIST_EDIT,
+ compute
+ });
+ })
+ ]);
+ }
+ else {
+ return postCompute({softwareProductId, componentId, compute, version}).then(response =>
+ dispatch({
+ type: actionTypes.ADD_COMPUTE,
+ compute: {
+ ...compute,
+ id: response.id,
+ componentId
+ }
+ })
+ );
+ }
+ },
+
+ deleteCompute(dispatch, {softwareProductId, componentId, computeId, version}) {
+ return deleteCompute({softwareProductId, componentId, computeId, version}).then(() => dispatch({
+ type: actionTypes.DELETE_COMPUTE,
+ computeId
+ }));
+ }
+};
+
+export default ComputeFlavorActionHelper;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentCompute.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentCompute.js
index e97477b..bb8df29 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentCompute.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentCompute.js
@@ -19,18 +19,23 @@
import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js';
import {COMPONENTS_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js';
import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
+import {onboardingMethod} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
-const mapStateToProps = ({softwareProduct}) => {
+const mapStateToProps = ({softwareProduct, currentScreen: {props: {softwareProductId, componentId}}}) => {
let {softwareProductEditor: {data: currentVSP}, softwareProductComponents} = softwareProduct;
- let {componentEditor: {qdata, dataMap, qgenericFieldInfo}} = softwareProductComponents;
+ let {componentEditor: {qdata, dataMap, qgenericFieldInfo}, computeFlavor: {computesList: computeFlavorsList}} = softwareProductComponents;
let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentVSP);
return {
qdata,
dataMap,
qgenericFieldInfo,
- isReadOnlyMode
+ isReadOnlyMode,
+ softwareProductId,
+ componentId,
+ computeFlavorsList,
+ isManual: currentVSP.onboardingMethod === onboardingMethod.MANUAL
};
};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentComputeView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentComputeView.jsx
index 8c197f0..dd524a3 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentComputeView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentComputeView.jsx
@@ -15,9 +15,9 @@
*/
import React from 'react';
import Form from 'nfvo-components/input/validation/Form.jsx';
-import VmSizing from './computeComponents/VmSizing.jsx';
import NumberOfVms from './computeComponents/NumberOfVms.jsx';
import GuestOs from './computeComponents/GuestOs.jsx';
+import ComputeFlavors from './computeComponents/ComputeFlavors.js';
import Validator from 'nfvo-utils/Validator.js';
class SoftwareProductComponentComputeView extends React.Component {
@@ -26,13 +26,15 @@
dataMap: React.PropTypes.object,
qgenericFieldInfo: React.PropTypes.object,
isReadOnlyMode: React.PropTypes.bool,
+ isManual: React.PropTypes.bool,
onQDataChanged: React.PropTypes.func.isRequired,
qValidateData: React.PropTypes.func.isRequired,
onSubmit: React.PropTypes.func.isRequired
};
render() {
- let {qdata, dataMap, qgenericFieldInfo, isReadOnlyMode, onQDataChanged, qValidateData, onSubmit} = this.props;
+ let {softwareProductId, componentId, version, qdata, dataMap, qgenericFieldInfo, isReadOnlyMode, onQDataChanged, qValidateData,
+ onSubmit, computeFlavorsList, isManual} = this.props;
return (
<div className='vsp-component-questionnaire-view'>
@@ -44,11 +46,12 @@
onSubmit={() => onSubmit({qdata})}
className='component-questionnaire-validation-form'
isReadOnlyMode={isReadOnlyMode} >
- <VmSizing onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qgenericFieldInfo} />
<NumberOfVms onQDataChanged={onQDataChanged} dataMap={dataMap}
qgenericFieldInfo={qgenericFieldInfo} qValidateData={qValidateData}
customValidations={{'compute/numOfVMs/maximum' : this.validateMax, 'compute/numOfVMs/minimum': this.validateMin}} />
<GuestOs onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qgenericFieldInfo} />
+ <ComputeFlavors computeFlavorsList={computeFlavorsList} softwareProductId={softwareProductId} componentId={componentId}
+ version={version} isReadOnlyMode={isReadOnlyMode} isManual={isManual}/>
</Form> }
</div>
);
@@ -60,12 +63,24 @@
validateMin(value, state) {
let maxVal = state.dataMap['compute/numOfVMs/maximum'];
- return Validator.validateItem(value,maxVal,'maximum');
+ // we are allowed to have an empty maxval, that will allow all minvals.
+ // if we do not have a minval than there is no point to check it either.
+ if (value === undefined || maxVal === undefined) {
+ return { isValid: true, errorText: '' };
+ } else {
+ return Validator.validateItem(value, maxVal,'maximum');
+ }
}
validateMax(value, state) {
let minVal = state.dataMap['compute/numOfVMs/minimum'];
- return Validator.validateItem(value,minVal,'minimum');
+ if (minVal === undefined ) {
+ // having no minimum is the same as 0, maximum value doesn't need to be checked
+ // against it.
+ return { isValid: true, errorText: '' };
+ } else {
+ return Validator.validateItem(value,minVal,'minimum');
+ }
}
}
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/ComputeFlavors.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/ComputeFlavors.js
new file mode 100644
index 0000000..c72d42c
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/ComputeFlavors.js
@@ -0,0 +1,116 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import React from 'react';
+import {connect} from 'react-redux';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx';
+import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx';
+import ComputeFlavorActionHelper from 'sdc-app/onboarding/softwareProduct/components/compute/ComputeFlavorActionHelper.js';
+import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
+
+const mapActionsToProps = (dispatch, {softwareProductId, componentId, version}) => {
+ return {
+ onAddComputeClick: (isReadOnlyMode) => ComputeFlavorActionHelper.openComputeEditor(dispatch, {props: {softwareProductId, componentId, isReadOnlyMode, version}}),
+ onEditCompute: ({computeId, isReadOnlyMode}) => ComputeFlavorActionHelper.loadCompute(dispatch, {softwareProductId, componentId, version, computeId, isReadOnlyMode}),
+ onDeleteCompute: ({id, name}) => dispatch({
+ type: modalActionTypes.GLOBAL_MODAL_WARNING,
+ data:{
+ msg: i18n(`Are you sure you want to delete "${name}"?`),
+ onConfirmed: () => ComputeFlavorActionHelper.deleteCompute(dispatch, {softwareProductId, componentId, computeId: id, version})
+ }
+ })
+ };
+};
+
+const computeItemPropType = React.PropTypes.shape({
+ id: React.PropTypes.string,
+ name: React.PropTypes.string,
+ description: React.PropTypes.string
+});
+
+class ComputeFlavors extends React.Component {
+
+ static propTypes = {
+ isReadOnlyMode: React.PropTypes.bool,
+ isManual: React.PropTypes.bool,
+ onAddComputeClick: React.PropTypes.func,
+ computeFlavorsList: React.PropTypes.arrayOf(computeItemPropType)
+ };
+
+ state = {
+ localFilter: ''
+ };
+
+ render() {
+ const {localFilter} = this.state;
+ const {isReadOnlyMode, isManual, onAddComputeClick, onEditCompute, onDeleteCompute} = this.props;
+ return (
+ <div className='computes-list'>
+ <ListEditorView
+ title={i18n('Computes')}
+ plusButtonTitle={i18n('Add Compute')}
+ onAdd={isManual ? () => onAddComputeClick(isReadOnlyMode) : null}
+ isReadOnlyMode={isReadOnlyMode}
+ onFilter={isManual ? value => this.setState({localFilter: value}) : null}
+ filterValue={localFilter}
+ twoColumns>
+ {this.filterList().map(computeItem =>
+ <ComputeItem key={computeItem.id}
+ computeItem={computeItem} isReadOnlyMode={isReadOnlyMode} isManual={isManual}
+ onEditCompute={onEditCompute} onDeleteCompute={onDeleteCompute}/>)
+ }
+ </ListEditorView>
+ </div>
+ );
+ }
+
+ filterList() {
+ const {computeFlavorsList = []} = this.props;
+
+ const {localFilter} = this.state;
+ if (localFilter.trim()) {
+ const filter = new RegExp(escape(localFilter), 'i');
+ return computeFlavorsList.filter(({name = '', description = ''}) => {
+ return escape(name).match(filter) || escape(description).match(filter);
+ });
+ }
+ else {
+ return computeFlavorsList;
+ }
+ }
+}
+
+const ComputeItem = ({computeItem, isReadOnlyMode, isManual, onEditCompute, onDeleteCompute}) => {
+ const {id, name, description} = computeItem;
+ return (
+ <ListEditorItemView
+ key={'item_' + id}
+ className='list-editor-item-view'
+ isReadOnlyMode={isReadOnlyMode}
+ onSelect={() => onEditCompute({computeId: id, isReadOnlyMode})}
+ onDelete={isManual ? () => onDeleteCompute({id, name}) : null}>
+
+ <div className='list-editor-item-view-field'>
+ <div className='name'>{name}</div>
+ </div>
+ <div className='list-editor-item-view-field'>
+ <div className='description'>{description}</div>
+ </div>
+ </ListEditorItemView>
+ );
+};
+
+export default connect(null, mapActionsToProps, null, {withRef: true})(ComputeFlavors);
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/GuestOs.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/GuestOs.jsx
index 7a730d6..16bf599 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/GuestOs.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/GuestOs.jsx
@@ -24,17 +24,6 @@
return(
<div>
<GridSection title={i18n('Guest OS')} >
- <GridItem colSpan={2}>
- <Input
- data-test-id='guestOS-name'
- label={i18n('Guest OS')}
- type='text'
- onChange={(tools) => onQDataChanged({'compute/guestOS/name' : tools})}
- isValid={qgenericFieldInfo['compute/guestOS/name'].isValid}
- errorText={qgenericFieldInfo['compute/guestOS/name'].errorText}
- value={dataMap['compute/guestOS/name']} />
- </GridItem>
- <GridItem colSpan={2}/>
<GridItem>
<div className='vertical-flex'>
<label key='label' className='control-label'>{i18n('OS Bit Size')}</label>
@@ -58,6 +47,16 @@
<GridItem colSpan={2}/>
<GridItem colSpan={2}>
<Input
+ data-test-id='guestOS-name'
+ label={i18n('Guest OS')}
+ type='textarea'
+ onChange={(tools) => onQDataChanged({'compute/guestOS/name' : tools})}
+ isValid={qgenericFieldInfo['compute/guestOS/name'].isValid}
+ errorText={qgenericFieldInfo['compute/guestOS/name'].errorText}
+ value={dataMap['compute/guestOS/name']} />
+ </GridItem>
+ <GridItem colSpan={2}>
+ <Input
data-test-id='guestOS-tools'
type='textarea'
label={i18n('Guest OS Tools:')}
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/NumberOfVms.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/NumberOfVms.jsx
index efeedc6..ddde439 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/NumberOfVms.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/NumberOfVms.jsx
@@ -45,44 +45,6 @@
errorText={qgenericFieldInfo['compute/numOfVMs/maximum'].errorText}
value={dataMap['compute/numOfVMs/maximum']} />
</GridItem>
- <GridItem>
- <Input
- data-test-id='numOfVMs-CpuOverSubscriptionRatio'
- label={i18n('CPU Oversubscription Ratio')}
- type='select'
- groupClassName='bootstrap-input-options'
- className='input-options-select'
- isValid={qgenericFieldInfo['compute/numOfVMs/CpuOverSubscriptionRatio'].isValid}
- errorText={qgenericFieldInfo['compute/numOfVMs/CpuOverSubscriptionRatio'].errorText}
- value={dataMap['compute/numOfVMs/CpuOverSubscriptionRatio']}
- onChange={(e) => {
- const selectedIndex = e.target.selectedIndex;
- const val = e.target.options[selectedIndex].value;
- onQDataChanged({'compute/numOfVMs/CpuOverSubscriptionRatio' : val});}
- }>
- <option key='placeholder' value=''>{i18n('Select...')}</option>
- {qgenericFieldInfo['compute/numOfVMs/CpuOverSubscriptionRatio'].enum.map(cpuOSR => <option value={cpuOSR.enum} key={cpuOSR.enum}>{cpuOSR.title}</option>)}
- </Input>
- </GridItem>
- <GridItem>
- <Input
- data-test-id='numOfVMs-MemoryRAM'
- type='select'
- label={i18n('Memory - RAM')}
- groupClassName='bootstrap-input-options'
- className='input-options-select'
- isValid={qgenericFieldInfo['compute/numOfVMs/MemoryRAM'].isValid}
- errorText={qgenericFieldInfo['compute/numOfVMs/MemoryRAM'].errorText}
- value={dataMap['compute/numOfVMs/MemoryRAM']}
- onChange={(e) => {
- const selectedIndex = e.target.selectedIndex;
- const val = e.target.options[selectedIndex].value;
- onQDataChanged({'compute/numOfVMs/MemoryRAM' : val});}
- }>
- <option key='placeholder' value=''>{i18n('Select...')}</option>
- {qgenericFieldInfo['compute/numOfVMs/MemoryRAM'].enum.map(mRAM => <option value={mRAM.enum} key={mRAM.enum}>{mRAM.title}</option>)}
- </Input>
- </GridItem>
</GridSection>
);
};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/VmSizing.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/VmSizing.jsx
deleted file mode 100644
index 39f8480..0000000
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/VmSizing.jsx
+++ /dev/null
@@ -1,68 +0,0 @@
-/*!
- * Copyright (C) 2017 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.
- */
-import React from 'react';
-import i18n from 'nfvo-utils/i18n/i18n.js';
-import Input from 'nfvo-components/input/validation/Input.jsx';
-import GridSection from 'nfvo-components/grid/GridSection.jsx';
-import GridItem from 'nfvo-components/grid/GridItem.jsx';
-const VmSizing = ({qgenericFieldInfo, dataMap, onQDataChanged}) => {
- return(
- <GridSection title={i18n('VM Sizing')}>
- <GridItem>
- <Input
- data-test-id='numOfCPUs'
- type='number'
- label={i18n('Number of CPUs')}
- onChange={(tools) => onQDataChanged({'compute/vmSizing/numOfCPUs' : tools})}
- isValid={qgenericFieldInfo['compute/vmSizing/numOfCPUs'].isValid}
- errorText={qgenericFieldInfo['compute/vmSizing/numOfCPUs'].errorText}
- value={dataMap['compute/vmSizing/numOfCPUs']} />
- </GridItem>
- <GridItem>
- <Input
- data-test-id='fileSystemSizeGB'
- type='number'
- label={i18n('File System Size (GB)')}
- onChange={(tools) => onQDataChanged({'compute/vmSizing/fileSystemSizeGB' : tools})}
- isValid={qgenericFieldInfo['compute/vmSizing/fileSystemSizeGB'].isValid}
- errorText={qgenericFieldInfo['compute/vmSizing/fileSystemSizeGB'].errorText}
- value={dataMap['compute/vmSizing/fileSystemSizeGB']} />
- </GridItem>
- <GridItem>
- <Input
- data-test-id='persistentStorageVolumeSize'
- type='number'
- label={i18n('Persistent Storage/Volume Size (GB)')}
- onChange={(tools) => onQDataChanged({'compute/vmSizing/persistentStorageVolumeSize' : tools})}
- isValid={qgenericFieldInfo['compute/vmSizing/persistentStorageVolumeSize'].isValid}
- errorText={qgenericFieldInfo['compute/vmSizing/persistentStorageVolumeSize'].errorText}
- value={dataMap['compute/vmSizing/persistentStorageVolumeSize']} />
- </GridItem>
- <GridItem>
- <Input
- data-test-id='IOOperationsPerSec'
- type='number'
- label={i18n('I/O Operations (per second)')}
- onChange={(tools) => onQDataChanged({'compute/vmSizing/IOOperationsPerSec' : tools})}
- isValid={qgenericFieldInfo['compute/vmSizing/IOOperationsPerSec'].isValid}
- errorText={qgenericFieldInfo['compute/vmSizing/IOOperationsPerSec'].errorText}
- value={dataMap['compute/vmSizing/IOOperationsPerSec']} />
- </GridItem>
- </GridSection>
- );
-};
-
-export default VmSizing;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorConstants.js
new file mode 100644
index 0000000..41728ee
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorConstants.js
@@ -0,0 +1,32 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+
+import keyMirror from 'nfvo-utils/KeyMirror.js';
+
+export const COMPUTE_FLAVOR_FORM = 'COMPUTE_FLAVOR_FORM';
+
+export const actionTypes = keyMirror({
+ ADD_COMPUTE: null,
+ COMPUTE_FLAVORS_LIST_LOADED: null,
+ COMPUTE_LIST_EDIT: null,
+ EDIT_COMPUTE_FLAVOR: null,
+ DELETE_COMPUTE: null,
+ CONFIRM_DELETE_COMPUTE: null,
+ computeEditor: {
+ LOAD_EDITOR_DATA: null,
+ CLEAR_DATA: null
+ }
+});
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditor.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditor.js
new file mode 100644
index 0000000..caec070
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditor.js
@@ -0,0 +1,55 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import {connect} from 'react-redux';
+import ComputeFlavorEditorView from './ComputeFlavorEditorView.jsx';
+import {COMPUTE_FLAVOR_FORM} from './ComputeFlavorConstants.js';
+import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js';
+import ComputeFlavorActionHelper from 'sdc-app/onboarding/softwareProduct/components/compute/ComputeFlavorActionHelper.js';
+import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
+import {COMPONENTS_COMPUTE_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js';
+import {onboardingMethod} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
+
+export const mapStateToProps = ({softwareProduct: {softwareProductEditor, softwareProductComponents: {computeFlavor: {computeEditor = {}}}}}) => {
+ const {data: currentSoftwareProduct = {}} = softwareProductEditor;
+ const isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct);
+ let {data , qdata, qgenericFieldInfo, dataMap, genericFieldInfo, formReady} = computeEditor;
+ let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo);
+
+ return {
+ data,
+ qdata,
+ qgenericFieldInfo,
+ dataMap,
+ genericFieldInfo,
+ isReadOnlyMode,
+ isFormValid,
+ formReady,
+ isManual: currentSoftwareProduct.onboardingMethod === onboardingMethod.MANUAL
+ };
+};
+
+
+const mapActionsToProps = (dispatch, {softwareProductId, componentId, version}) => {
+ return {
+ onDataChanged: deltaData => ValidationHelper.dataChanged(dispatch, {deltaData, formName: COMPUTE_FLAVOR_FORM}),
+ onQDataChanged: deltaData => ValidationHelper.qDataChanged(dispatch, {deltaData, qName: COMPONENTS_COMPUTE_QUESTIONNAIRE}),
+ onCancel: () => ComputeFlavorActionHelper.closeComputeEditor(dispatch),
+ onSubmit: ({data, qdata}) => ComputeFlavorActionHelper.saveComputeDataAndQuestionnaire(dispatch, {softwareProductId, componentId, data, qdata, version}),
+ onValidateForm: () => ValidationHelper.validateForm(dispatch, COMPUTE_FLAVOR_FORM)
+ };
+};
+
+export default connect(mapStateToProps, mapActionsToProps)(ComputeFlavorEditorView);
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditorView.jsx
new file mode 100644
index 0000000..8f8a504
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditorView.jsx
@@ -0,0 +1,96 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import React from 'react';
+import Form from 'nfvo-components/input/validation/Form.jsx';
+import Input from 'nfvo-components/input/validation/Input.jsx';
+import GridSection from 'nfvo-components/grid/GridSection.jsx';
+import GridItem from 'nfvo-components/grid/GridItem.jsx';
+import VmSizing from './VmSizing.jsx';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+
+class ComputeEditorView extends React.Component {
+
+ static propTypes = {
+ data: React.PropTypes.object,
+ qdata: React.PropTypes.object,
+ qschema: React.PropTypes.object,
+ isReadOnlyMode: React.PropTypes.bool,
+ isManual: React.PropTypes.bool,
+ onDataChanged: React.PropTypes.func.isRequired,
+ onQDataChanged: React.PropTypes.func.isRequired,
+ onSubmit: React.PropTypes.func.isRequired,
+ onCancel: React.PropTypes.func.isRequired
+ };
+
+ render() {
+ let {data = {}, qdata = {}, qgenericFieldInfo, dataMap, genericFieldInfo, isReadOnlyMode, isManual, isFormValid, formReady,
+ onDataChanged, onQDataChanged, onSubmit, onCancel, onValidateForm} = this.props;
+ const {id, name, description} = data;
+ const edittingComputeMode = Boolean(id);
+
+ return (
+ <div className='vsp-component-computeFlavor-view'>
+ {genericFieldInfo && <Form
+ ref={(form) => {
+ this.form = form;
+ }}
+ hasButtons={true}
+ onSubmit={ () => onSubmit({data, qdata}) }
+ onReset={ () => onCancel() }
+ labledButtons={true}
+ isReadOnlyMode={isReadOnlyMode}
+ isValid={isFormValid}
+ formReady={formReady}
+ onValidateForm={() => onValidateForm() }
+ className='component-questionnaire-validation-form'
+ submitButtonText={edittingComputeMode ? i18n('Save') : i18n('Create')}>
+ <GridSection>
+ <GridItem colSpan={edittingComputeMode ? 2 : 4}>
+ <Input
+ disabled={!isManual}
+ data-test-id='name'
+ type='text'
+ label={i18n('Flavor Name')}
+ value={name}
+ onChange={name => onDataChanged({name})}
+ isValid={genericFieldInfo['name'].isValid}
+ errorText={genericFieldInfo['name'].errorText}
+ isRequired/>
+ </GridItem>
+ <GridItem colSpan={edittingComputeMode ? 2 : 4}>
+ <Input
+ data-test-id='description'
+ type='textarea'
+ label={i18n('Description')}
+ value={description}
+ onChange={description => onDataChanged({description})}
+ isValid={genericFieldInfo['description'].isValid}
+ errorText={genericFieldInfo['description'].errorText}/>
+ </GridItem>
+ </GridSection>
+ {edittingComputeMode && <VmSizing qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged}/>}
+ </Form>
+ }
+ </div>
+ );
+ }
+
+ save(){
+ return this.form.handleFormSubmit(new Event('dummy'));
+ }
+}
+
+export default ComputeEditorView;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorListReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorListReducer.js
new file mode 100644
index 0000000..6c02f36
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorListReducer.js
@@ -0,0 +1,33 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+
+import {actionTypes} from './ComputeFlavorConstants.js';
+
+export default (state = [], action) => {
+ switch (action.type) {
+ case actionTypes.COMPUTE_FLAVORS_LIST_LOADED:
+ return [...action.response.results];
+ case actionTypes.ADD_COMPUTE:
+ return [...state, action.compute];
+ case actionTypes.COMPUTE_LIST_EDIT:
+ const indexForEdit = state.findIndex(({id}) => id === action.compute.id);
+ return [...state.slice(0, indexForEdit), action.compute, ...state.slice(indexForEdit + 1)];
+ case actionTypes.DELETE_COMPUTE:
+ return state.filter(({id}) => id !== action.computeId);
+ default:
+ return state;
+ }
+};
\ No newline at end of file
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorReducer.js
new file mode 100644
index 0000000..a476f85
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorReducer.js
@@ -0,0 +1,45 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import {actionTypes, COMPUTE_FLAVOR_FORM} from './ComputeFlavorConstants.js';
+
+export default (state = {}, action) => {
+ switch (action.type) {
+ case actionTypes.computeEditor.LOAD_EDITOR_DATA:
+ return {
+ ...state,
+ formName: COMPUTE_FLAVOR_FORM,
+ data: action.compute,
+ formReady: null,
+ genericFieldInfo: {
+ name: {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'required', data: true }]
+ },
+ description: {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'maxLength', data: 300}]
+ }
+ }
+ };
+ case actionTypes.computeEditor.CLEAR_DATA:
+ return {};
+ default:
+ return state;
+ }
+};
+
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/VmSizing.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/VmSizing.jsx
new file mode 100644
index 0000000..8b30468
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/VmSizing.jsx
@@ -0,0 +1,106 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import React from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import Input from 'nfvo-components/input/validation/Input.jsx';
+import GridSection from 'nfvo-components/grid/GridSection.jsx';
+import GridItem from 'nfvo-components/grid/GridItem.jsx';
+const VmSizing = ({qgenericFieldInfo, dataMap, onQDataChanged}) => {
+ return(
+ <GridSection title={i18n('VM Sizing')}>
+ <GridItem>
+ <Input
+ data-test-id='numOfCPUs'
+ type='number'
+ label={i18n('Number of CPUs')}
+ onChange={(tools) => onQDataChanged({'vmSizing/numOfCPUs' : tools})}
+ isValid={qgenericFieldInfo['vmSizing/numOfCPUs'].isValid}
+ errorText={qgenericFieldInfo['vmSizing/numOfCPUs'].errorText}
+ value={dataMap['vmSizing/numOfCPUs']} />
+ </GridItem>
+ <GridItem>
+ <Input
+ data-test-id='fileSystemSizeGB'
+ type='number'
+ label={i18n('File System Size (GB)')}
+ onChange={(tools) => onQDataChanged({'vmSizing/fileSystemSizeGB' : tools})}
+ isValid={qgenericFieldInfo['vmSizing/fileSystemSizeGB'].isValid}
+ errorText={qgenericFieldInfo['vmSizing/fileSystemSizeGB'].errorText}
+ value={dataMap['vmSizing/fileSystemSizeGB']} />
+ </GridItem>
+ <GridItem>
+ <Input
+ data-test-id='persistentStorageVolumeSize'
+ type='number'
+ label={i18n('Persistent Storage/Volume Size (GB)')}
+ onChange={(tools) => onQDataChanged({'vmSizing/persistentStorageVolumeSize' : tools})}
+ isValid={qgenericFieldInfo['vmSizing/persistentStorageVolumeSize'].isValid}
+ errorText={qgenericFieldInfo['vmSizing/persistentStorageVolumeSize'].errorText}
+ value={dataMap['vmSizing/persistentStorageVolumeSize']} />
+ </GridItem>
+ <GridItem>
+ <Input
+ data-test-id='ioOperationsPerSec'
+ type='number'
+ label={i18n('I/O Operations (per second)')}
+ onChange={(tools) => onQDataChanged({'vmSizing/ioOperationsPerSec' : tools})}
+ isValid={qgenericFieldInfo['vmSizing/ioOperationsPerSec'].isValid}
+ errorText={qgenericFieldInfo['vmSizing/ioOperationsPerSec'].errorText}
+ value={dataMap['vmSizing/ioOperationsPerSec']} />
+ </GridItem>
+ <GridItem>
+ <Input
+ data-test-id='numOfVMs-cpuOverSubscriptionRatio'
+ label={i18n('CPU Oversubscription Ratio')}
+ type='select'
+ groupClassName='bootstrap-input-options'
+ className='input-options-select'
+ isValid={qgenericFieldInfo['vmSizing/cpuOverSubscriptionRatio'].isValid}
+ errorText={qgenericFieldInfo['vmSizing/cpuOverSubscriptionRatio'].errorText}
+ value={dataMap['vmSizing/cpuOverSubscriptionRatio']}
+ onChange={(e) => {
+ const selectedIndex = e.target.selectedIndex;
+ const val = e.target.options[selectedIndex].value;
+ onQDataChanged({'vmSizing/cpuOverSubscriptionRatio' : val});}
+ }>
+ <option key='placeholder' value=''>{i18n('Select...')}</option>
+ {qgenericFieldInfo['vmSizing/cpuOverSubscriptionRatio'].enum.map(cpuOSR => <option value={cpuOSR.enum} key={cpuOSR.enum}>{cpuOSR.title}</option>)}
+ </Input>
+ </GridItem>
+ <GridItem>
+ <Input
+ data-test-id='numOfVMs-memoryRAM'
+ type='select'
+ label={i18n('Memory - RAM')}
+ groupClassName='bootstrap-input-options'
+ className='input-options-select'
+ isValid={qgenericFieldInfo['vmSizing/memoryRAM'].isValid}
+ errorText={qgenericFieldInfo['vmSizing/memoryRAM'].errorText}
+ value={dataMap['vmSizing/memoryRAM']}
+ onChange={(e) => {
+ const selectedIndex = e.target.selectedIndex;
+ const val = e.target.options[selectedIndex].value;
+ onQDataChanged({'vmSizing/memoryRAM' : val});}
+ }>
+ <option key='placeholder' value=''>{i18n('Select...')}</option>
+ {qgenericFieldInfo['vmSizing/memoryRAM'].enum.map(mRAM => <option value={mRAM.enum} key={mRAM.enum}>{mRAM.title}</option>)}
+ </Input>
+ </GridItem>
+ </GridSection>
+ );
+};
+
+export default VmSizing;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreation.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreation.js
new file mode 100644
index 0000000..e85b6b6
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreation.js
@@ -0,0 +1,50 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+
+import {connect} from 'react-redux';
+import SoftwareProductComponentCreationView from './SoftwareProductComponentCreationView.jsx';
+import SoftwareProductComponentsActionHelper from '../SoftwareProductComponentsActionHelper.js';
+import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
+import {forms} from '../SoftwareProductComponentsConstants.js';
+
+export const mapStateToProps = ({softwareProduct}) => {
+ let {softwareProductComponents: {componentEditor: {data, genericFieldInfo, formReady}}, softwareProductEditor: {data: {version}}} = softwareProduct;
+ let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo);
+ return {
+ data,
+ genericFieldInfo,
+ formReady,
+ isFormValid,
+ version
+ };
+};
+
+
+const mapActionsToProps = (dispatch, {softwareProductId}) => {
+ return {
+ onDataChanged: (deltaData) => ValidationHelper.dataChanged(dispatch, {deltaData, formName: forms.CREATE_FORM}),
+ //onDataChanged: deltaData => SoftwareProductComponentsActionHelper.componentDataChanged(dispatch, {deltaData}),
+ onSubmit: (componentData, version) => {
+ return SoftwareProductComponentsActionHelper.createSoftwareProductComponent(dispatch,
+ {softwareProductId, componentData, version});
+ },
+ onCancel: () => SoftwareProductComponentsActionHelper.closeComponentCreationModal(dispatch),
+ onValidateForm: (formName) => ValidationHelper.validateForm(dispatch, formName)
+ };
+
+};
+
+export default connect(mapStateToProps, mapActionsToProps)(SoftwareProductComponentCreationView);
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreationView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreationView.jsx
new file mode 100644
index 0000000..55bcc81
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreationView.jsx
@@ -0,0 +1,79 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+
+import React from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+
+import Form from 'nfvo-components/input/validation/Form.jsx';
+import Input from 'nfvo-components/input/validation/Input.jsx';
+import GridSection from 'nfvo-components/grid/GridSection.jsx';
+import GridItem from 'nfvo-components/grid/GridItem.jsx';
+import {forms} from '../SoftwareProductComponentsConstants.js';
+
+class ComponentCreationView extends React.Component {
+ render() {
+ let {data = {}, onDataChanged, onCancel, genericFieldInfo} = this.props;
+ let {displayName, description} = data;
+ return(
+ <div>
+ {
+ genericFieldInfo && <Form
+ ref='validationForm'
+ hasButtons={true}
+ onSubmit={ () => this.submit() }
+ onReset={ () => onCancel() }
+ submitButtonText={i18n('Create')}
+ labledButtons={true}
+ isValid={this.props.isFormValid}
+ formReady={this.props.formReady}
+ onValidateForm={() => this.props.onValidateForm(forms.CREATE_FORM) }
+ className='entitlement-pools-form'>
+ <GridSection>
+ <GridItem colSpan={4}>
+ <Input
+ data-test-id='name'
+ onChange={displayName => onDataChanged({displayName})}
+ label={i18n('Name')}
+ isRequired={true}
+ isValid={genericFieldInfo.displayName.isValid}
+ errorText={genericFieldInfo.displayName.errorText}
+ value={displayName}
+ type='text'/>
+ </GridItem>
+ <GridItem colSpan={4}>
+ <Input
+ label={i18n('Description')}
+ onChange={description => onDataChanged({description})}
+ value={description}
+ isValid={genericFieldInfo.description.isValid}
+ errorText={genericFieldInfo.description.errorText}
+ data-test-id='description'
+ type='textarea'/>
+ </GridItem>
+ </GridSection>
+ </Form>
+ }
+ </div>
+ );
+ }
+
+ submit() {
+ const {onSubmit, data, version} = this.props;
+ onSubmit(data, version);
+ }
+}
+
+export default ComponentCreationView;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneral.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneral.js
index 34374aa..7b41350 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneral.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneral.js
@@ -22,6 +22,7 @@
import {forms, COMPONENTS_QUESTIONNAIRE} from '../SoftwareProductComponentsConstants.js';
+import {onboardingMethod} from '../../SoftwareProductConstants.js';
export const mapStateToProps = ({softwareProduct}) => {
@@ -34,6 +35,7 @@
componentData,
qdata,
isReadOnlyMode,
+ isManual: currentVSP.onboardingMethod === onboardingMethod.MANUAL,
genericFieldInfo,
qGenericFieldInfo,
dataMap,
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneralView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneralView.jsx
index e4595f9..6aa51d1 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneralView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneralView.jsx
@@ -21,7 +21,7 @@
import GridSection from 'nfvo-components/grid/GridSection.jsx';
import GridItem from 'nfvo-components/grid/GridItem.jsx';
-const GeneralSection = ({onDataChanged, displayName, vfcCode, description, isReadOnlyMode, genericFieldInfo}) => (
+const GeneralSection = ({onDataChanged, displayName, vfcCode, nfcFunction, description, isReadOnlyMode, genericFieldInfo, isManual}) => (
<GridSection title={i18n('General')}>
{/* disabled until backend will be ready to implement it
<div className='validation-input-wrapper'>
@@ -37,9 +37,9 @@
data-test-id='name'
label={i18n('Name')}
value={displayName}
- disabled={true}
+ disabled={!isManual || isReadOnlyMode}
type='text'/>
- <Input
+ {!isManual && <Input
data-test-id='vfcCode'
label={i18n('Naming Code')}
value={vfcCode}
@@ -47,6 +47,15 @@
errorText={genericFieldInfo.vfcCode.errorText}
onChange={vfcCode => onDataChanged({vfcCode})}
disabled={isReadOnlyMode}
+ type='text'/> }
+ <Input
+ data-test-id='nfcFunction'
+ label={i18n('Function')}
+ value={nfcFunction}
+ isValid={genericFieldInfo.nfcFunction.isValid}
+ errorText={genericFieldInfo.nfcFunction.errorText}
+ onChange={nfcFunction => onDataChanged({nfcFunction})}
+ disabled={isReadOnlyMode}
type='text'/>
</GridItem>
<GridItem colSpan={2}>
@@ -63,7 +72,7 @@
</GridItem>
<GridItem />
</GridSection>
- );
+);
const HypervisorSection = ({dataMap, onQDataChanged, qgenericFieldInfo}) => (
<GridSection title={i18n('Hypervisor')}>
@@ -110,64 +119,26 @@
);
const ImageSection = ({dataMap, onQDataChanged, qgenericFieldInfo}) => (
- <GridSection title={i18n('Image')}>
- <GridItem>
- <Input
- data-test-id='format'
- label={i18n('Image format')}
- type='select'
- className='input-options-select'
- groupClassName='bootstrap-input-options'
- isValid={qgenericFieldInfo['general/image/format'].isValid}
- errorText={qgenericFieldInfo['general/image/format'].errorText}
- value={dataMap['general/image/format']}
- onChange={(e) => {
- const selectedIndex = e.target.selectedIndex;
- const val = e.target.options[selectedIndex].value;
- onQDataChanged({'general/image/format' : val});}
- }>
- <option key='placeholder' value=''>{i18n('Select...')}</option>
- {qgenericFieldInfo['general/image/format'].enum.map(hv => <option value={hv.enum} key={hv.enum}>{hv.title}</option>)}
- </Input>
- </GridItem>
- <GridItem>
- <Input
- data-test-id='providedBy'
- label={i18n('Image provided by')}
- type='select'
- className='input-options-select'
- groupClassName='bootstrap-input-options'
- isValid={qgenericFieldInfo['general/image/providedBy'].isValid}
- errorText={qgenericFieldInfo['general/image/providedBy'].errorText}
- value={dataMap['general/image/providedBy']}
- onChange={(e) => {
- const selectedIndex = e.target.selectedIndex;
- const val = e.target.options[selectedIndex].value;
- onQDataChanged({'general/image/providedBy' : val});}
- }>
- <option key='placeholder' value=''>{i18n('Select...')}</option>
- {qgenericFieldInfo['general/image/providedBy'].enum.map(hv => <option value={hv.enum} key={hv.enum}>{hv.title}</option>)}
- </Input>
- </GridItem>
+ <GridSection title={i18n('Disk')}>
<GridItem>
<Input
data-test-id='bootDiskSizePerVM'
- onChange={(bootDiskSizePerVM) => onQDataChanged({'general/image/bootDiskSizePerVM' : bootDiskSizePerVM})}
+ onChange={(bootDiskSizePerVM) => onQDataChanged({'general/disk/bootDiskSizePerVM' : bootDiskSizePerVM})}
label={i18n('Size of boot disk per VM (GB)')}
type='number'
- isValid={qgenericFieldInfo['general/image/bootDiskSizePerVM'].isValid}
- errorText={qgenericFieldInfo['general/image/bootDiskSizePerVM'].errorText}
- value={dataMap['general/image/bootDiskSizePerVM']}/>
+ isValid={qgenericFieldInfo['general/disk/bootDiskSizePerVM'].isValid}
+ errorText={qgenericFieldInfo['general/disk/bootDiskSizePerVM'].errorText}
+ value={dataMap['general/disk/bootDiskSizePerVM']}/>
</GridItem>
<GridItem>
<Input
data-test-id='ephemeralDiskSizePerVM'
- onChange={(ephemeralDiskSizePerVM) => onQDataChanged({'general/image/ephemeralDiskSizePerVM' : ephemeralDiskSizePerVM})}
+ onChange={(ephemeralDiskSizePerVM) => onQDataChanged({'general/disk/ephemeralDiskSizePerVM' : ephemeralDiskSizePerVM})}
label={i18n('Size of ephemeral disk per VM (GB)')}
type='number'
- isValid={qgenericFieldInfo['general/image/ephemeralDiskSizePerVM'].isValid}
- errorText={qgenericFieldInfo['general/image/ephemeralDiskSizePerVM'].errorText}
- value={dataMap['general/image/ephemeralDiskSizePerVM']}/>
+ isValid={qgenericFieldInfo['general/disk/ephemeralDiskSizePerVM'].isValid}
+ errorText={qgenericFieldInfo['general/disk/ephemeralDiskSizePerVM'].errorText}
+ value={dataMap['general/disk/ephemeralDiskSizePerVM']}/>
</GridItem>
</GridSection>
);
@@ -257,7 +228,7 @@
class SoftwareProductComponentsGeneralView extends React.Component {
render() {
- let {onQDataChanged, onDataChanged, genericFieldInfo, dataMap, qGenericFieldInfo, componentData: {displayName, vfcCode, description}, isReadOnlyMode} = this.props;
+ let {isManual, onQDataChanged, onDataChanged, genericFieldInfo, dataMap, qGenericFieldInfo, componentData: {displayName, vfcCode, nfcFunction, description}, isReadOnlyMode} = this.props;
return(
<div className='vsp-components-general'>
<div className='general-data'>
@@ -271,7 +242,9 @@
onDataChanged={onDataChanged}
displayName={displayName}
vfcCode={vfcCode}
+ nfcFunction={nfcFunction}
description={description}
+ isManual={isManual}
isReadOnlyMode={isReadOnlyMode}
genericFieldInfo={genericFieldInfo}/>
<HypervisorSection onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qGenericFieldInfo}/>
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageActionHelper.js
new file mode 100644
index 0000000..3419828
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageActionHelper.js
@@ -0,0 +1,169 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
+import Configuration from 'sdc-app/config/Configuration.js';
+import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js';
+import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
+import {IMAGE_QUESTIONNAIRE} from './SoftwareProductComponentsImageConstants.js';
+import {actionTypes} from './SoftwareProductComponentsImageConstants.js';
+
+function baseUrl(softwareProductId, version, componentId) {
+ const versionId = version.id;
+ const restPrefix = Configuration.get('restPrefix');
+ return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${versionId}/components/${componentId}/images`;
+}
+
+function fetchImagesList({softwareProductId, componentId, version}) {
+ return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}`);
+}
+
+function fetchImage({softwareProductId, componentId, imageId, version}) {
+ return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}/${imageId}`);
+}
+
+function destroyImage({softwareProductId, componentId, version, imageId}) {
+ return RestAPIUtil.destroy(`${baseUrl(softwareProductId, version, componentId)}/${imageId}`);
+}
+
+function createImage({softwareProductId, componentId, version, data}) {
+ return RestAPIUtil.post(baseUrl(softwareProductId, version, componentId), {
+ fileName: data.fileName
+ });
+}
+
+function fetchImageQuestionnaire({softwareProductId, componentId, imageId, version}) {
+ return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}/${imageId}/questionnaire`);
+}
+
+function saveImage({softwareProductId, version, componentId, image: {id, fileName}}) {
+ return RestAPIUtil.put(`${baseUrl(softwareProductId, version, componentId)}/${id}`,{
+ fileName
+ });
+
+}
+
+function saveImageQuestionnaire({softwareProductId, componentId, version, imageId, qdata}) {
+ return RestAPIUtil.put(`${baseUrl(softwareProductId, version, componentId)}/${imageId}/questionnaire`, qdata);
+}
+
+const SoftwareProductComponentImagesActionHelper = {
+ fetchImagesList(dispatch, {softwareProductId, componentId, version}) {
+ dispatch({
+ type: actionTypes.IMAGES_LIST_UPDATE,
+ response: []
+ });
+
+ return fetchImagesList({softwareProductId, componentId, version}).then((response) => {
+ dispatch({
+ type: actionTypes.IMAGES_LIST_UPDATE,
+ response: response.results,
+ componentId : componentId
+ });
+ });
+ },
+
+ deleteImage(dispatch, {softwareProductId, componentId, version, imageId}) {
+ return destroyImage({softwareProductId, componentId, version, imageId}).then(() => {
+ return SoftwareProductComponentImagesActionHelper.fetchImagesList(dispatch, {softwareProductId, componentId, version});
+ });
+ },
+
+ loadImageData({softwareProductId, componentId, imageId, version}) {
+ return fetchImage({softwareProductId, componentId, imageId, version});
+ },
+
+ openEditImageEditor(dispatch, {image, softwareProductId, componentId, version, isReadOnlyMode, modalClassName}) {
+ return SoftwareProductComponentImagesActionHelper.loadImageData({softwareProductId, componentId, imageId: image.id, version}).then(({data}) => {
+ SoftwareProductComponentImagesActionHelper.loadImageQuestionnaire(dispatch, {
+ softwareProductId,
+ componentId,
+ imageId: image.id,
+ version
+ }).then(() => {
+ SoftwareProductComponentImagesActionHelper.openImageEditor(dispatch, {
+ softwareProductId,
+ componentId,
+ version,
+ isReadOnlyMode,
+ modalClassName,
+ image,
+ data
+ });
+ });
+ });
+ },
+
+ openImageEditor(dispatch, {image = {}, data = {}, softwareProductId, componentId, version, isReadOnlyMode}) {
+
+ let title = (image && image.id) ? i18n('Edit Image') : i18n('Create New Image');
+ let className = (image && image.id) ? 'image-edit-editor-model' : 'image-new-editor-modal';
+
+ dispatch({
+ type: actionTypes.ImageEditor.OPEN,
+ image: {...data, id: image.id}
+ });
+
+ dispatch({
+ type: modalActionTypes.GLOBAL_MODAL_SHOW,
+ data: {
+ modalComponentName: modalContentMapper.SOFTWARE_PRODUCT_COMPONENT_IMAGE_EDITOR,
+ title: title,
+ modalComponentProps: {softwareProductId, componentId, version, isReadOnlyMode, dialogClassName:className}
+ }
+ });
+ },
+
+ closeImageEditor(dispatch) {
+
+ dispatch({
+ type: modalActionTypes.GLOBAL_MODAL_CLOSE
+ });
+
+ dispatch({
+ type: actionTypes.ImageEditor.CLOSE
+ });
+ },
+
+ loadImageQuestionnaire(dispatch, {softwareProductId, componentId, imageId, version}) {
+ return fetchImageQuestionnaire({softwareProductId, componentId, imageId, version}).then((response) => {
+ ValidationHelper.qDataLoaded(dispatch, {qName: IMAGE_QUESTIONNAIRE ,response: {
+ qdata: response.data ? JSON.parse(response.data) : {},
+ qschema: JSON.parse(response.schema)
+ }});
+ });
+ },
+
+ saveImageDataAndQuestionnaire(dispatch, {softwareProductId, componentId, version, data, qdata}) {
+ SoftwareProductComponentImagesActionHelper.closeImageEditor(dispatch);
+ if (data !== null && data.id) {
+ // editor in edit mode
+ return Promise.all([
+ saveImageQuestionnaire({softwareProductId, version, componentId, imageId: data.id, qdata}),
+ saveImage({softwareProductId, version, componentId, image: data}).then(() => {
+ return SoftwareProductComponentImagesActionHelper.fetchImagesList(dispatch, {softwareProductId, componentId, version});
+ })
+ ]);
+ } else {
+ // editor in create mode
+ createImage({softwareProductId, componentId, version, data}).then(() => {
+ return SoftwareProductComponentImagesActionHelper.fetchImagesList(dispatch, {softwareProductId, componentId, version});
+ });
+ }
+ }
+};
+export default SoftwareProductComponentImagesActionHelper;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageConstants.js
new file mode 100644
index 0000000..6b6c9a3
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageConstants.js
@@ -0,0 +1,27 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import keyMirror from 'nfvo-utils/KeyMirror.js';
+
+export const actionTypes = keyMirror({
+ IMAGES_LIST_UPDATE: null,
+
+ ImageEditor: {
+ CLOSE: null,
+ OPEN: null
+ }
+});
+
+export const IMAGE_QUESTIONNAIRE = 'image';
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditor.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditor.js
new file mode 100644
index 0000000..49d891c
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditor.js
@@ -0,0 +1,63 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import {connect} from 'react-redux';
+import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
+import SoftwareProductComponentsImageActionHelper from './SoftwareProductComponentsImageActionHelper.js';
+import SoftwareProductComponentsImageEditorView from './SoftwareProductComponentsImageEditorView.jsx';
+import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js';
+import {onboardingMethod as onboardingMethodTypes} from '../../SoftwareProductConstants.js';
+import {forms} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js';
+import {IMAGE_QUESTIONNAIRE} from './SoftwareProductComponentsImageConstants.js';
+
+export const mapStateToProps = ({softwareProduct}) => {
+
+ let {softwareProductEditor: {data:currentSoftwareProduct = {}, isValidityData = true}, softwareProductComponents} = softwareProduct;
+
+ let {images: {imageEditor = {}}} = softwareProductComponents;
+ let {data, qdata, genericFieldInfo, qgenericFieldInfo, dataMap, formReady} = imageEditor;
+ let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct);
+ let {version, onboardingMethod} = currentSoftwareProduct;
+ let isManual = onboardingMethod === onboardingMethodTypes.MANUAL;
+ let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo) && ValidationHelper.checkFormValid(qgenericFieldInfo);
+
+ return {
+ version,
+ currentSoftwareProduct,
+ isValidityData,
+ data,
+ qdata,
+ dataMap,
+ isFormValid,
+ formReady,
+ genericFieldInfo,
+ qgenericFieldInfo,
+ isReadOnlyMode,
+ isManual: isManual
+ };
+};
+
+const mapActionsToProps = (dispatch, {softwareProductId, componentId, version}) => {
+ return {
+ onDataChanged: (deltaData) => ValidationHelper.dataChanged(dispatch, {deltaData, formName: forms.IMAGE_EDIT_FORM}),
+ onSubmit: ({data, qdata}) => SoftwareProductComponentsImageActionHelper.saveImageDataAndQuestionnaire(dispatch, {softwareProductId, componentId, version, data, qdata}),
+ onCancel: () => SoftwareProductComponentsImageActionHelper.closeImageEditor(dispatch),
+ onValidateForm: () => ValidationHelper.validateForm(dispatch, forms.IMAGE_EDIT_FORM),
+ onQDataChanged: (deltaData) => ValidationHelper.qDataChanged(dispatch, {deltaData,
+ qName: IMAGE_QUESTIONNAIRE}),
+ };
+};
+
+export default connect(mapStateToProps, mapActionsToProps)(SoftwareProductComponentsImageEditorView);
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorReducer.js
new file mode 100644
index 0000000..0ab785a
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorReducer.js
@@ -0,0 +1,42 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import {actionTypes} from './SoftwareProductComponentsImageConstants.js';
+import {forms} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js';
+
+export default (state = {}, action) => {
+ switch (action.type) {
+ case actionTypes.ImageEditor.CLOSE:
+ return {};
+ case actionTypes.ImageEditor.OPEN:
+ return {
+ ...state,
+ data: {
+ ...action.image
+ },
+ genericFieldInfo: {
+ 'fileName' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'required', data: true}, {type: 'validateName', data: true}]
+ }
+ },
+ formName: forms.IMAGE_EDIT_FORM
+ };
+ default:
+ return state;
+ }
+};
+
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorView.jsx
new file mode 100644
index 0000000..300f8ed
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorView.jsx
@@ -0,0 +1,71 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import React from 'react';
+
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import Form from 'nfvo-components/input/validation/Form.jsx';
+
+import FileDetails from './imagesEditorComponents/FileDetails.jsx';
+import ImageDetails from './imagesEditorComponents/ImageDetails.jsx';
+
+class SoftwareProductComponentsImageEditorView extends React.Component {
+ static propTypes = {
+ onDataChanged: React.PropTypes.func.isRequired,
+ onSubmit: React.PropTypes.func.isRequired,
+ onCancel: React.PropTypes.func.isRequired
+ };
+
+ render() {
+ let {onCancel, onValidateForm, isReadOnlyMode, isFormValid, formReady, data = {}, genericFieldInfo, qgenericFieldInfo, dataMap, onDataChanged, isManual, onQDataChanged} = this.props;
+ let {id, fileName} = data;
+ let editingMode = Boolean(id);
+ return (
+ <div>
+ {genericFieldInfo && <Form
+ ref={(form) => { this.form = form; }}
+ hasButtons={true}
+ onSubmit={ () => this.submit() }
+ onReset={ () => onCancel() }
+ labledButtons={true}
+ isReadOnlyMode={isReadOnlyMode}
+ isValid={isFormValid}
+ formReady={formReady}
+ submitButtonText={editingMode ? i18n('Save') : i18n('Create')}
+ onValidateForm={() => onValidateForm() }
+ className='vsp-components-image-editor'>
+ <div className='editor-data'>
+ <FileDetails
+ editingMode={editingMode}
+ genericFieldInfo={genericFieldInfo}
+ qgenericFieldInfo={qgenericFieldInfo}
+ fileName={fileName}
+ onDataChanged={onDataChanged}
+ isManual={isManual}
+ dataMap={dataMap}
+ onQDataChanged={onQDataChanged}/>
+ {editingMode && <ImageDetails dataMap={dataMap}qgenericFieldInfo={qgenericFieldInfo} onQDataChanged={onQDataChanged}/>}
+ </div>
+ </Form>}
+ </div>
+ );
+ }
+ submit() {
+ let {data, qdata, onSubmit, version} = this.props;
+ onSubmit({data, qdata, version});
+ }
+}
+
+export default SoftwareProductComponentsImageEditorView;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageList.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageList.js
new file mode 100644
index 0000000..86c4e07
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageList.js
@@ -0,0 +1,88 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import {connect} from 'react-redux';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+
+import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js';
+import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
+import SoftwareProductComponentsImageListView from './SoftwareProductComponentsImageListView.jsx';
+import ImageHelper from './SoftwareProductComponentsImageActionHelper.js';
+import SoftwareProductComponentsImagesActionHelper from './SoftwareProductComponentsImageActionHelper.js';
+import SoftwareProductComponentsActionHelper from '../SoftwareProductComponentsActionHelper.js';
+import {COMPONENTS_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js';
+import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
+
+import {onboardingMethod as onboardingMethodTypes} from '../../SoftwareProductConstants.js';
+
+export const mapStateToProps = ({softwareProduct}) => {
+
+ let {softwareProductEditor: {data: currentSoftwareProduct = {}, isValidityData = true}, softwareProductComponents} = softwareProduct;
+ let {images: {imagesList = []}, componentEditor: {data: componentData, qdata, dataMap, qgenericFieldInfo}} = softwareProductComponents;
+ let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct);
+ let {version, onboardingMethod} = currentSoftwareProduct;
+ let isManual = onboardingMethod === onboardingMethodTypes.MANUAL;
+
+ return {
+ version,
+ componentData,
+ qdata,
+ dataMap,
+ qgenericFieldInfo,
+ isValidityData,
+ imagesList,
+ isReadOnlyMode,
+ isManual : isManual
+ };
+};
+
+const mapActionsToProps = (dispatch, {softwareProductId, componentId}) => {
+ return {
+ onQDataChanged: (deltaData) => ValidationHelper.qDataChanged(dispatch, {deltaData,
+ qName: COMPONENTS_QUESTIONNAIRE}),
+ onAddImage: (version, isReadOnlyMode) => {
+ SoftwareProductComponentsImagesActionHelper.openImageEditor(dispatch,
+ {isReadOnlyMode, softwareProductId,
+ componentId, version}
+ );},
+ onDeleteImage: ((image, version) => {
+ let shortenedFileName = (image.fileName.length > 40) ? image.fileName.substr(0,40) + '...' : image.fileName;
+ dispatch({
+ type: modalActionTypes.GLOBAL_MODAL_WARNING,
+ data: {
+ msg: i18n(`Are you sure you want to delete "${shortenedFileName}"?`),
+ onConfirmed: () => ImageHelper.deleteImage(dispatch, {
+ softwareProductId,
+ componentId,
+ version,
+ imageId: image.id
+ })
+ }
+ });
+ }),
+ onEditImageClick: (image, version, isReadOnlyMode) => {
+ SoftwareProductComponentsImagesActionHelper.openEditImageEditor(dispatch, {
+ image, isReadOnlyMode, softwareProductId, componentId, version, modalClassName: 'image-modal-edit'}
+ );
+ },
+ onSubmit: ({qdata}) => { return SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire(dispatch,
+ {softwareProductId,
+ vspComponentId: componentId,
+ qdata});
+ }
+ };
+};
+
+export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(SoftwareProductComponentsImageListView);
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListReducer.js
new file mode 100644
index 0000000..5dd2fb6
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListReducer.js
@@ -0,0 +1,26 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import {actionTypes} from './SoftwareProductComponentsImageConstants.js';
+
+export default (state = [], action) => {
+ switch (action.type) {
+
+ case actionTypes.IMAGES_LIST_UPDATE:
+ return [...action.response];
+ default:
+ return state;
+ }
+};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListView.jsx
new file mode 100644
index 0000000..ccf5b9d
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListView.jsx
@@ -0,0 +1,132 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import React from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import Form from 'nfvo-components/input/validation/Form.jsx';
+
+import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx';
+import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx';
+import ListEditorItemViewField from 'nfvo-components/listEditor/ListEditorItemViewField.jsx';
+import Input from'nfvo-components/input/validation/Input.jsx';
+
+class SoftwareProductComponentsImageListView extends React.Component {
+ state = {
+ localFilter: ''
+ };
+
+ render() {
+ let {dataMap, onQDataChanged, isReadOnlyMode, qgenericFieldInfo} = this.props;
+ return(
+ <div className='vsp-components-image'>
+ <div className='image-data'>
+ <div>
+ { qgenericFieldInfo && <Form
+ formReady={null}
+ isValid={true}
+ onSubmit={() => this.save()}
+ isReadOnlyMode={isReadOnlyMode}
+ hasButtons={false}>
+
+ <h3 className='section-title'>{i18n('Image')}</h3>
+ <div className='rows-section'>
+ <div className='row-flex-components'>
+ <div className='single-col'>
+ <Input
+ data-test-id='providedBy'
+ label={i18n('Image provided by')}
+ type='select'
+ isValid={qgenericFieldInfo['general/image/providedBy'].isValid}
+ errorText={qgenericFieldInfo['general/image/providedBy'].errorText}
+ value={dataMap['general/image/providedBy']}
+ onChange={(e) => {
+ const selectedIndex = e.target.selectedIndex;
+ const val = e.target.options[selectedIndex].value;
+ onQDataChanged({'general/image/providedBy' : val});}
+ }>
+ <option key='placeholder' value=''>{i18n('Select...')}</option>
+ { qgenericFieldInfo['general/image/providedBy'].enum.map(proto =>
+ <option value={proto.enum} key={proto.enum}>{proto.title}</option>) }
+ </Input>
+ </div>
+ <div className='empty-two-col' />
+ </div>
+ </div>
+
+ </Form> }
+ </div>
+ </div>
+ {this.renderImagesList()}
+ </div>
+ );
+ };
+
+ renderImagesList() {
+ const {localFilter} = this.state;
+ let {isReadOnlyMode, onAddImage, isManual, version} = this.props;
+
+ return (
+ <ListEditorView
+ title={i18n('Images')}
+ filterValue={localFilter}
+ placeholder={i18n('Filter Images by Name')}
+ isReadOnlyMode={isReadOnlyMode}
+ onFilter={value => this.setState({localFilter: value})}
+ onAdd={isManual ? () => onAddImage(version, isReadOnlyMode) : null}
+ plusButtonTitle={i18n('Add Image')}
+ twoColumns>
+ {this.filterList().map(image => this.renderImagesListItem(image, isReadOnlyMode))}
+ </ListEditorView>
+ );
+ };
+
+
+ renderImagesListItem(image, isReadOnlyMode) {
+ let {id, fileName} = image;
+ let {onEditImageClick, version, isManual, onDeleteImage} = this.props;
+ return (
+ <ListEditorItemView
+ key={id}
+ isReadOnlyMode={isReadOnlyMode}
+ onSelect={() => onEditImageClick(image, version, isReadOnlyMode)}
+ onDelete={isManual ? () => onDeleteImage(image, version) : null}>
+
+ <ListEditorItemViewField>
+ <div className='image-filename-cell'><span className='image-filename'>{fileName}</span></div>
+ </ListEditorItemViewField>
+ </ListEditorItemView>
+ );
+ }
+
+ filterList() {
+ let {imagesList} = this.props;
+ let {localFilter} = this.state;
+ if (localFilter.trim()) {
+ const filter = new RegExp(escape(localFilter), 'i');
+ return imagesList.filter(({fileName = ''}) => {
+ return escape(fileName).match(filter);
+ });
+ }
+ else {
+ return imagesList;
+ }
+ }
+
+ save() {
+ let {onSubmit, qdata} = this.props;
+ return onSubmit({qdata});
+ }
+}
+export default SoftwareProductComponentsImageListView;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageNavigationReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageNavigationReducer.js
new file mode 100644
index 0000000..20d1f5d
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageNavigationReducer.js
@@ -0,0 +1,32 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import {actionTypes} from './SoftwareProductComponentsImageConstants.js';
+
+export default (state = {}, action) => {
+ switch (action.type) {
+
+ case actionTypes.IMAGES_LIST_UPDATE:
+ if (action.componentId) {
+ return {
+ ...state,
+ [action.componentId] : (action.response && action.response.length > 0)
+ };
+ }
+ return state;
+ default:
+ return state;
+ }
+};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/FileDetails.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/FileDetails.jsx
new file mode 100644
index 0000000..ca58b69
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/FileDetails.jsx
@@ -0,0 +1,48 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import React from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import Input from 'nfvo-components/input/validation/Input.jsx';
+import GridSection from 'nfvo-components/grid/GridSection.jsx';
+import GridItem from 'nfvo-components/grid/GridItem.jsx';
+import {forms} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js';
+
+import Format from './Format.jsx';
+import Version from './Version.jsx';
+
+const FileDetails = ({editingMode, fileName, onDataChanged, isManual, dataMap, onQDataChanged, genericFieldInfo, qgenericFieldInfo}) => {
+ let fileNameCols = (editingMode) ? 3 : 4;
+ return(
+ <GridSection>
+ <GridItem colSpan={fileNameCols}>
+ <Input
+ disabled={!isManual}
+ onChange={fileName => onDataChanged({fileName}, forms.IMAGE_EDIT_FORM)}
+ label={i18n('Image Name')}
+ data-test-id='image-filename'
+ value={fileName}
+ isValid={genericFieldInfo.fileName.isValid}
+ errorText={genericFieldInfo.fileName.errorText}
+ isRequired={true}
+ type='text'
+ className='image-filename'/>
+ </GridItem>
+ {editingMode && <Version isManual={isManual} dataMap={dataMap} qgenericFieldInfo={qgenericFieldInfo} onQDataChanged={onQDataChanged}/>}
+ {editingMode && <Format isManual={isManual} qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged}/>}
+ </GridSection>
+ );
+};
+export default FileDetails;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/Format.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/Format.jsx
new file mode 100644
index 0000000..1f71c6b
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/Format.jsx
@@ -0,0 +1,47 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import React from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import Input from 'nfvo-components/input/validation/Input.jsx';
+import GridItem from 'nfvo-components/grid/GridItem.jsx';
+
+
+const Format = ({isManual, dataMap, qgenericFieldInfo, onQDataChanged}) => {
+ return(
+ <GridItem colSpan={2}>
+ <Input
+ disabled={!isManual}
+ data-test-id='image-format'
+ type='select'
+ label={i18n('Format')}
+ className='input-options-select'
+ groupClassName='bootstrap-input-options'
+ isValid={qgenericFieldInfo['format'].isValid}
+ errorText={qgenericFieldInfo['format'].errorText}
+ value={dataMap['format']}
+ onChange={(e) => {
+ const selectedIndex = e.target.selectedIndex;
+ const val = e.target.options[selectedIndex].value;
+ onQDataChanged({'format' : val});}
+ }>
+ <option key='placeholder' value=''>{i18n('Select...')}</option>
+ {qgenericFieldInfo['format'].enum.map(hv => <option value={hv.enum} key={hv.enum}>{hv.title}</option>)}
+ </Input>
+ </GridItem>
+ );
+};
+export default Format;
+
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/ImageDetails.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/ImageDetails.jsx
new file mode 100644
index 0000000..24e54bb
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/ImageDetails.jsx
@@ -0,0 +1,39 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import React from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import Input from 'nfvo-components/input/validation/Input.jsx';
+import GridSection from 'nfvo-components/grid/GridSection.jsx';
+import GridItem from 'nfvo-components/grid/GridItem.jsx';
+
+const ImageDetails = ({dataMap, qgenericFieldInfo, onQDataChanged}) => {
+ return(
+ <GridSection title={i18n('Image Details')}>
+ <GridItem colSpan={2}>
+ <Input
+ data-test-id='image-md5'
+ className='image-md5'
+ type='text'
+ label={i18n('md5')}
+ onChange={(md5) => onQDataChanged({'md5' : md5})}
+ isValid={qgenericFieldInfo['md5'].isValid}
+ errorText={qgenericFieldInfo['md5'].errorText}
+ value={dataMap['md5']}/>
+ </GridItem>
+ </GridSection>
+ );
+};
+export default ImageDetails;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/Version.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/Version.jsx
new file mode 100644
index 0000000..3cac9a5
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/Version.jsx
@@ -0,0 +1,39 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import React from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import Input from 'nfvo-components/input/validation/Input.jsx';
+import GridItem from 'nfvo-components/grid/GridItem.jsx';
+
+
+const Version = ({isManual, dataMap, qgenericFieldInfo, onQDataChanged}) => {
+ return(
+ <GridItem colSpan={1}>
+ <Input
+ disabled={!isManual}
+ data-test-id='image-version'
+ type='text'
+ className='image-version'
+ label={i18n('Version')}
+ onChange={(version) => onQDataChanged({'version' : version})}
+ isValid={qgenericFieldInfo['version'].isValid}
+ errorText={qgenericFieldInfo['version'].errorText}
+ value={dataMap['version']}/>
+ </GridItem>
+ );
+};
+export default Version;
+
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/loadBalancing/SoftwareProductComponentLoadBalancingRefView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/loadBalancing/SoftwareProductComponentLoadBalancingRefView.jsx
index dc86771..9ae9e35 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/loadBalancing/SoftwareProductComponentLoadBalancingRefView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/loadBalancing/SoftwareProductComponentLoadBalancingRefView.jsx
@@ -14,7 +14,7 @@
* permissions and limitations under the License.
*/
import React from 'react';
-import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
+import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
import i18n from 'nfvo-utils/i18n/i18n.js';
import Form from 'nfvo-components/input/validation/Form.jsx';
@@ -56,7 +56,7 @@
<div className={expanded ? 'title' : 'title add-padding'}
data-test-id={`btn-${item.key}`}
onClick={() => toggle(item.key)}>
- <SVGIcon name={expanded ? 'chevron-up' : 'chevron-down'}/>
+ <SVGIcon name={expanded ? 'chevronUp' : 'chevronDown'}/>
<span className='title-text'>{i18n(item.description)}</span>
{item.added && <div className='new-line'>{i18n(item.added)}</div>}
</div>
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.js
index 293e252..730beba 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.js
@@ -25,20 +25,19 @@
export const mapStateToProps = ({softwareProduct}) => {
let {softwareProductEditor: {data:currentVSP = {}}, softwareProductComponents: {monitoring}} = softwareProduct;
- let {trapFilename, pollFilename} = monitoring;
+ let filenames = monitoring;
let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentVSP);
return {
isReadOnlyMode,
- trapFilename,
- pollFilename
+ filenames
};
};
const mapActionsToProps = (dispatch, {softwareProductId, version, componentId}) => {
return {
onDropMibFileToUpload: (formData, type) =>
- SoftwareProductComponentsMonitoringAction.uploadSnmpFile(dispatch, {
+ SoftwareProductComponentsMonitoringAction.uploadFile(dispatch, {
softwareProductId,
version,
componentId,
@@ -46,7 +45,7 @@
type
}),
- onDeleteSnmpFile: type => SoftwareProductComponentsMonitoringAction.deleteSnmpFile(dispatch, {
+ onDeleteFile: type => SoftwareProductComponentsMonitoringAction.deleteFile(dispatch, {
softwareProductId,
version,
componentId,
@@ -57,7 +56,7 @@
type: modalActionTypes.GLOBAL_MODAL_ERROR,
data: {
title: i18n('Upload Failed'),
- msg: i18n('Expected "zip" file. Please check the provided file type.')
+ msg: i18n('Expected "zip" file. Please check the provided file type.')
}
}),
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringActionHelper.js
index 64403fa..3db708b 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringActionHelper.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringActionHelper.js
@@ -16,23 +16,13 @@
import i18n from 'nfvo-utils/i18n/i18n.js';
import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js';
import Configuration from 'sdc-app/config/Configuration.js';
-import SoftwareProductComponentsMonitoringConstants, {actionTypes} from './SoftwareProductComponentsMonitoringConstants.js';
+import {actionTypes} from './SoftwareProductComponentsMonitoringConstants.js';
import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
-const UPLOAD = true;
-
function baseUrl(vspId, version, componentId) {
const versionId = version.id;
const restPrefix = Configuration.get('restPrefix');
- return `${restPrefix}/v1.0/vendor-software-products/${vspId}/versions/${versionId}/components/${componentId}/monitors`;
-}
-
-function snmpTrapUrl(vspId, version, componentId, isUpload) {
- return `${baseUrl(vspId, version, componentId)}/snmp-trap${isUpload ? '/upload' : ''}`;
-}
-
-function snmpPollUrl(vspId, version, componentId, isUpload) {
- return `${baseUrl(vspId, version, componentId)}/snmp${isUpload ? '/upload' : ''}`;
+ return `${restPrefix}/v1.0/vendor-software-products/${vspId}/versions/${versionId}/components/${componentId}/uploads`;
}
let onInvalidFileSizeUpload = (dispatch) => dispatch({
@@ -43,62 +33,42 @@
}
});
-let uploadSnmpTrapFile = (dispatch, {softwareProductId, version, componentId, formData}) => {
- RestAPIUtil.post(snmpTrapUrl(softwareProductId, version, componentId, UPLOAD), formData).then(()=> dispatch({
- type: actionTypes.SNMP_TRAP_UPLOADED, data: {filename: formData.get('upload').name}
+let uploadFile = (dispatch, {softwareProductId, version, componentId, formData, type}) => {
+ return RestAPIUtil.post(`${baseUrl(softwareProductId, version, componentId)}/types/${type}`, formData).then(()=> dispatch({
+ type: actionTypes.MONITOR_UPLOADED, data: {filename: formData.get('upload').name, type : type}
}));
};
-let uploadSnmpPollFile = (dispatch, {softwareProductId, version, componentId, formData}) => {
- RestAPIUtil.post(snmpPollUrl(softwareProductId, version, componentId, UPLOAD), formData).then(()=> dispatch({
- type: actionTypes.SNMP_POLL_UPLOADED, data: {filename: formData.get('upload').name}
+let deleteFile = (dispatch, {softwareProductId, version, componentId, type}) => {
+ return RestAPIUtil.destroy(`${baseUrl(softwareProductId, version, componentId)}/types/${type}`).then(()=> dispatch({
+ type: actionTypes.MONITOR_DELETED,
+ data : { type: type}
}));
};
-let deleteSnmpTrapFile = (dispatch, {softwareProductId, version, componentId}) => {
- RestAPIUtil.destroy(snmpTrapUrl(softwareProductId, version, componentId, !UPLOAD)).then(()=> dispatch({
- type: actionTypes.SNMP_TRAP_DELETED
- }));
-};
-
-let deleteSnmpPollFile = (dispatch, {softwareProductId, version, componentId}) => {
- RestAPIUtil.destroy(snmpPollUrl(softwareProductId, version, componentId, !UPLOAD)).then(()=> dispatch({
- type: actionTypes.SNMP_POLL_DELETED
- }));
-};
const SoftwareProductComponentsMonitoringAction = {
fetchExistingFiles(dispatch, {softwareProductId, version, componentId}){
- RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}/snmp`).then(response =>
+ return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}`).then(response =>
dispatch({
- type: actionTypes.SNMP_FILES_DATA_CHANGE,
- data: {trapFilename: response.snmpTrap, pollFilename: response.snmpPoll}
+ type: actionTypes.MONITOR_FILES_DATA_CHANGE,
+ data: response
})
);
},
- uploadSnmpFile(dispatch, {softwareProductId, version, componentId, formData, type}){
+ uploadFile(dispatch, {softwareProductId, version, componentId, formData, type}){
if (formData.get('upload').size) {
- if (type === SoftwareProductComponentsMonitoringConstants.SNMP_TRAP) {
- uploadSnmpTrapFile(dispatch, {softwareProductId, version, componentId, formData});
- }
- else {
- uploadSnmpPollFile(dispatch, {softwareProductId, version, componentId, formData});
- }
+ return uploadFile(dispatch, {softwareProductId, version, componentId, formData, type});
}
else {
onInvalidFileSizeUpload(dispatch);
}
},
- deleteSnmpFile(dispatch, {softwareProductId, version, componentId, type}){
- if (type === SoftwareProductComponentsMonitoringConstants.SNMP_TRAP) {
- deleteSnmpTrapFile(dispatch, {softwareProductId, version, componentId});
- }
- else {
- deleteSnmpPollFile(dispatch, {softwareProductId, version, componentId});
- }
+ deleteFile(dispatch, {softwareProductId, version, componentId, type}){
+ return deleteFile(dispatch, {softwareProductId, version, componentId, type});
}
};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringConstants.js
index d908d36..bf2cbd2 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringConstants.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringConstants.js
@@ -14,20 +14,31 @@
* permissions and limitations under the License.
*/
import keyMirror from 'nfvo-utils/KeyMirror.js';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+
export const actionTypes = keyMirror({
-
- SNMP_FILES_DATA_CHANGE: null,
-
- SNMP_TRAP_UPLOADED: null,
- SNMP_POLL_UPLOADED: null,
-
- SNMP_TRAP_DELETED: null,
- SNMP_POLL_DELETED: null
+ MONITOR_FILES_DATA_CHANGE: null,
+ MONITOR_UPLOADED: null,
+ MONITOR_DELETED: null
});
-export default keyMirror({
- SNMP_TRAP: null,
- SNMP_POLL: null
-});
+export const fileTypes = {
+ SNMP_TRAP: 'SNMP_TRAP',
+ SNMP_POLL: 'SNMP_POLL',
+ VES_EVENT: 'VES_EVENTS'
+};
+
+export const type2Name = {
+ SNMP_TRAP: 'snmpTrap',
+ SNMP_POLL: 'snmpPoll',
+ VES_EVENTS: 'vesEvent'
+};
+
+
+export const type2Title = {
+ SNMP_TRAP : i18n('SNMP Trap'),
+ SNMP_POLL : i18n('SNMP Poll'),
+ VES_EVENTS: i18n('VES')
+};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringReducer.js
index 54513b9..f5cfe6f 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringReducer.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringReducer.js
@@ -13,35 +13,21 @@
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
-import {actionTypes} from './SoftwareProductComponentsMonitoringConstants.js';
+import {actionTypes, type2Name} from './SoftwareProductComponentsMonitoringConstants.js';
export default (state = {}, action) => {
switch (action.type) {
- case actionTypes.SNMP_FILES_DATA_CHANGE:
+ case actionTypes.MONITOR_FILES_DATA_CHANGE:
+ return action.data;
+ case actionTypes.MONITOR_UPLOADED:
return {
...state,
- trapFilename: action.data.trapFilename,
- pollFilename: action.data.pollFilename
+ [type2Name[action.data.type]]: action.data.filename
};
- case actionTypes.SNMP_TRAP_UPLOADED:
+ case actionTypes.MONITOR_DELETED:
return {
...state,
- trapFilename: action.data.filename
- };
- case actionTypes.SNMP_POLL_UPLOADED:
- return {
- ...state,
- pollFilename: action.data.filename
- };
- case actionTypes.SNMP_TRAP_DELETED:
- return {
- ...state,
- trapFilename: undefined
- };
- case actionTypes.SNMP_POLL_DELETED:
- return {
- ...state,
- pollFilename: undefined
+ [type2Name[action.data.type]]: undefined
};
default:
return state;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringView.jsx
index 329cc70..2ad48ec 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringView.jsx
@@ -19,14 +19,15 @@
import ButtonToolbar from 'react-bootstrap/lib/ButtonToolbar.js';
import Button from 'react-bootstrap/lib/Button.js';
import i18n from 'nfvo-utils/i18n/i18n.js';
-import SoftwareProductComponentsMonitoringConstants from './SoftwareProductComponentsMonitoringConstants.js';
+import {fileTypes, type2Title, type2Name} from './SoftwareProductComponentsMonitoringConstants.js';
+
+
class SoftwareProductComponentsMonitoringView extends Component {
static propTypes = {
isReadOnlyMode: PropTypes.bool,
- trapFilename: PropTypes.string,
- pollFilename: PropTypes.string,
+ filenames: PropTypes.object,
softwareProductId: PropTypes.string,
onDropMibFileToUpload: PropTypes.func,
@@ -38,26 +39,24 @@
};
+
+
render() {
return (
<div className='vsp-component-monitoring'>
- {this.renderDropzoneWithType(SoftwareProductComponentsMonitoringConstants.SNMP_TRAP)}
- {this.renderDropzoneWithType(SoftwareProductComponentsMonitoringConstants.SNMP_POLL)}
+ {this.renderDropzoneWithType(fileTypes.VES_EVENT)}
+ {this.renderDropzoneWithType(fileTypes.SNMP_TRAP)}
+ {this.renderDropzoneWithType(fileTypes.SNMP_POLL)}
</div>
);
}
renderDropzoneWithType(type) {
- let {isReadOnlyMode, trapFilename, pollFilename} = this.props;
- let fileName;
- if (type === SoftwareProductComponentsMonitoringConstants.SNMP_TRAP) {
- fileName = trapFilename;
- }
- else {
- fileName = pollFilename;
- }
+ let {isReadOnlyMode, filenames} = this.props;
+ let fileByType = type2Name[type];
+ let fileName = (filenames) ? filenames[fileByType] : undefined;
let refAndName = `fileInput${type.toString()}`;
- let typeDisplayName = this.getFileTypeDisplayName(type);
+ let typeDisplayName = type2Title[type];
return (
<Dropzone
className={`snmp-dropzone ${this.state.dragging ? 'active-dragging' : ''}`}
@@ -97,7 +96,7 @@
<ButtonToolbar>
<ButtonGroup>
<Button disabled>{filename}</Button>
- <Button className='delete-button' onClick={()=>this.props.onDeleteSnmpFile(type)}>X</Button>
+ <Button className='delete-button' onClick={()=>this.props.onDeleteFile(type)}>X</Button>
</ButtonGroup>
</ButtonToolbar>
);
@@ -126,11 +125,6 @@
this.props.onFileUploadError();
}
}
-
- getFileTypeDisplayName(type) {
- return type === SoftwareProductComponentsMonitoringConstants.SNMP_TRAP ? 'SNMP Trap' : 'SNMP Poll';
- }
-
}
export default SoftwareProductComponentsMonitoringView;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreation.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreation.js
new file mode 100644
index 0000000..865367a
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreation.js
@@ -0,0 +1,51 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import {connect} from 'react-redux';
+import NICCreationActionHelper from './NICCreationActionHelper.js';
+import NICCreationView from './NICCreationView.jsx';
+import SoftwareProductComponentsNetworkActionHelper from '../SoftwareProductComponentsNetworkActionHelper.js';
+import {networkTypes, NIC_CREATION_FORM_NAME} from '../SoftwareProductComponentsNetworkConstants.js';
+import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
+
+export const mapStateToProps = ({softwareProduct}) => {
+ let {softwareProductEditor: {data:currentSoftwareProduct = {}}, softwareProductComponents} = softwareProduct;
+ let {network: {nicCreation = {}}} = softwareProductComponents;
+ let {data, genericFieldInfo, formReady} = nicCreation;
+ data = {...data, networkType: networkTypes.EXTERNAL};
+ let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo);
+
+ return {
+ currentSoftwareProduct,
+ data,
+ genericFieldInfo,
+ isFormValid,
+ formReady
+ };
+};
+
+const mapActionsToProps = (dispatch) => {
+ return {
+ onDataChanged: deltaData => ValidationHelper.dataChanged(dispatch, {deltaData, formName: NIC_CREATION_FORM_NAME}),
+ onCancel: () => NICCreationActionHelper.close(dispatch),
+ onSubmit: ({nic, softwareProductId, componentId, version}) => {
+ NICCreationActionHelper.close(dispatch);
+ SoftwareProductComponentsNetworkActionHelper.createNIC(dispatch, {nic, softwareProductId, componentId, version});
+ },
+ onValidateForm: () => ValidationHelper.validateForm(dispatch, NIC_CREATION_FORM_NAME)
+ };
+};
+
+export default connect(mapStateToProps, mapActionsToProps)(NICCreationView);
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationActionHelper.js
new file mode 100644
index 0000000..ad28c86
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationActionHelper.js
@@ -0,0 +1,47 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import {actionTypes} from '../SoftwareProductComponentsNetworkConstants';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
+import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js';
+
+export default {
+
+ open(dispatch, {softwareProductId, componentId, modalClassName}) {
+ dispatch({
+ type: actionTypes.NICCreation.OPEN
+ });
+
+ dispatch({
+ type: modalActionTypes.GLOBAL_MODAL_SHOW,
+ data: {
+ modalComponentName: modalContentMapper.NIC_CREATION,
+ title: i18n('Create NEW NIC'),
+ modalClassName,
+ modalComponentProps: {softwareProductId, componentId}
+ }
+ });
+ },
+
+ close(dispatch){
+ dispatch({
+ type: modalActionTypes.GLOBAL_MODAL_CLOSE
+ });
+ dispatch({
+ type: actionTypes.NICCreation.CLEAR_DATA
+ });
+ }
+};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationReducer.js
new file mode 100644
index 0000000..c7e2495
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationReducer.js
@@ -0,0 +1,49 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import {actionTypes, NIC_CREATION_FORM_NAME} from '../SoftwareProductComponentsNetworkConstants.js';
+
+export default (state = {}, action) => {
+ switch (action.type) {
+ case actionTypes.NICCreation.OPEN:
+ return {
+ ...state,
+ data: {},
+ formName: NIC_CREATION_FORM_NAME,
+ formReady: null,
+ genericFieldInfo: {
+ 'description' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'maxLength', data: 1000}]
+ },
+ 'name' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'required', data : true}]
+ },
+ 'networkDescription' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'maxLength', data: 50}]
+ }
+ }
+ };
+ case actionTypes.NICCreation.CLEAR_DATA:
+ return {};
+ default:
+ return state;
+ }
+};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationView.jsx
new file mode 100644
index 0000000..3cb731a
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationView.jsx
@@ -0,0 +1,123 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import React from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import Input from 'nfvo-components/input/validation/Input.jsx';
+import Form from 'nfvo-components/input/validation/Form.jsx';
+import GridSection from 'nfvo-components/grid/GridSection.jsx';
+import GridItem from 'nfvo-components/grid/GridItem.jsx';
+
+const NICPropType = React.PropTypes.shape({
+ id: React.PropTypes.string,
+ name: React.PropTypes.string,
+ description: React.PropTypes.string,
+ networkId: React.PropTypes.string
+});
+
+class NICCreationView extends React.Component {
+
+ static propTypes = {
+ data: NICPropType,
+ onDataChanged: React.PropTypes.func.isRequired,
+ onSubmit: React.PropTypes.func.isRequired,
+ onCancel: React.PropTypes.func.isRequired
+ };
+
+ render() {
+ let {data = {}, onDataChanged, genericFieldInfo, isFormValid, onValidateForm, formReady} = this.props;
+ let {name, description, networkDescription} = data;
+ return (
+ <div>
+ {genericFieldInfo && <Form
+ ref={(form) => this.form = form}
+ hasButtons={true}
+ onSubmit={ () => this.submit() }
+ submitButtonText={data.id ? i18n('Save') : i18n('Create')}
+ onReset={ () => this.props.onCancel() }
+ labledButtons={true}
+ isValid={isFormValid}
+ onValidateForm={() => onValidateForm()}
+ formReady={formReady} >
+ <GridSection>
+ <GridItem colSpan={4}>
+ <Input
+ value={name}
+ label={i18n('Name')}
+ data-test-id='nic-name'
+ onChange={name => onDataChanged({name})}
+ isRequired={true}
+ type='text'
+ isValid={genericFieldInfo['name'].isValid}
+ errorText={genericFieldInfo['name'].errorText}
+ className='field-section'/>
+ <Input
+ value={description}
+ label={i18n('Description')}
+ data-test-id='nic-description'
+ onChange={description => onDataChanged({description})}
+ isValid={genericFieldInfo['description'].isValid}
+ errorText={genericFieldInfo['description'].errorText}
+ type='textarea'
+ className='field-section'/>
+ </GridItem>
+ </GridSection>
+ <GridSection title={i18n('Network')}>
+ <GridItem colSpan={2}>
+ <div className='form-group'>
+ <label className='control-label'>{i18n('Network Type')}</label>
+ <div className='network-type-radio'>
+ <Input
+ label={i18n('Internal')}
+ disabled
+ checked={false}
+ data-test-id='nic-internal'
+ className='network-radio disabled'
+ type='radio'/>
+ <Input
+ label={i18n('External')}
+ disabled
+ checked={true}
+ data-test-id='nic-external'
+ className='network-radio disabled'
+ type='radio'/>
+ </div>
+ </div>
+ </GridItem>
+ <GridItem colSpan={2}>
+ <Input
+ value={networkDescription}
+ label={i18n('Network Description')}
+ data-test-id='nic-network-description'
+ onChange={networkDescription => onDataChanged({networkDescription})}
+ isValid={genericFieldInfo['networkDescription'].isValid}
+ errorText={genericFieldInfo['networkDescription'].errorText}
+ type='text'
+ className='field-section'/>
+ </GridItem>
+ </GridSection>
+ </Form>}
+ </div>
+ );
+ }
+
+
+ submit() {
+ const {data: nic, softwareProductId, componentId, currentSoftwareProduct} = this.props;
+ this.props.onSubmit({nic, softwareProductId, componentId, version: currentSoftwareProduct.version});
+ }
+}
+
+export default NICCreationView;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditor.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditor.js
index 7cf1f01..b47c7e0 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditor.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditor.js
@@ -20,6 +20,7 @@
import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
import {forms} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js';
import {NIC_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js';
+import {onboardingMethod as onboardingMethodTypes} from '../../SoftwareProductConstants.js';
export const mapStateToProps = ({softwareProduct}) => {
@@ -28,6 +29,7 @@
let {network: {nicEditor = {}}} = softwareProductComponents;
let {data, qdata, genericFieldInfo, qgenericFieldInfo, dataMap, formReady} = nicEditor;
let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct);
+ let {onboardingMethod} = currentSoftwareProduct;
let protocols = [];
if(qdata && qdata.protocols && qdata.protocols.protocols && qdata.protocols.protocols.length){
protocols = qdata.protocols.protocols;
@@ -47,7 +49,8 @@
genericFieldInfo,
qgenericFieldInfo,
isReadOnlyMode,
- protocols
+ protocols,
+ isManual: onboardingMethod === onboardingMethodTypes.MANUAL
};
};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorReducer.js
index b3c9fe5..dd37135 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorReducer.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorReducer.js
@@ -18,7 +18,7 @@
export default (state = {}, action) => {
switch (action.type) {
- case actionTypes.NICEditor.OPEN:
+ case actionTypes.NICEditor.FILL_DATA:
return {
...state,
data: action.nic,
@@ -31,12 +31,17 @@
'name' : {
isValid: true,
errorText: '',
+ validations: [{type: 'required', data : true}]
+ },
+ 'networkDescription' : {
+ isValid: true,
+ errorText: '',
validations: []
}
},
formName: forms.NIC_EDIT_FORM
};
- case actionTypes.NICEditor.CLOSE:
+ case actionTypes.NICEditor.CLEAR_DATA:
return {};
default:
return state;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorView.jsx
index aad06c8..8a4c55a 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorView.jsx
@@ -28,8 +28,9 @@
class SoftwareProductComponentsNetworkEditorView extends React.Component {
render() {
- let {onCancel, onValidateForm, isReadOnlyMode, isFormValid, formReady, data = {}, qgenericFieldInfo, dataMap, onDataChanged, protocols, onQDataChanged} = this.props;
- let {name, description, networkName} = data;
+ let {onCancel, onValidateForm, isReadOnlyMode, isFormValid, formReady, data = {}, qgenericFieldInfo,
+ dataMap, onDataChanged, protocols, onQDataChanged, isManual, genericFieldInfo} = this.props;
+ let {name, description, networkName, networkType, networkDescription} = data;
let netWorkValues = [{
enum: networkName,
title: networkName
@@ -48,10 +49,10 @@
onValidateForm={() => onValidateForm() }
className='vsp-components-network-editor'>
<div className='editor-data'>
- <NameAndPurpose name={name} description={description} onDataChanged={onDataChanged} isReadOnlyMode={isReadOnlyMode}/>
+ <NameAndPurpose isManual={isManual} name={name} description={description} onDataChanged={onDataChanged} isReadOnlyMode={isReadOnlyMode} genericFieldInfo={genericFieldInfo} />
<Protocols protocols={protocols} qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged} />
<IpConfig dataMap={dataMap} onQDataChanged={onQDataChanged} />
- <Network networkValues={netWorkValues} />
+ <Network networkDescription={networkDescription} onDataChanged={onDataChanged} networkValues={netWorkValues} isReadOnlyMode={isReadOnlyMode} networkType={networkType} />
<Sizing qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged} />
<InFlowTraffic qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged} />
<OutFlowTraffic qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged} />
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.js
index bc06146..a3cfe65 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.js
@@ -15,8 +15,11 @@
*/
import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js';
import Configuration from 'sdc-app/config/Configuration.js';
+import i18n from 'nfvo-utils/i18n/i18n.js';
import {actionTypes} from './SoftwareProductComponentsNetworkConstants.js';
+import {actionTypes as GlobalModalActions} from 'nfvo-components/modal/GlobalModalConstants.js';
+import {modalContentMapper as modalPagesMapper} from 'sdc-app/common/modal/ModalContentMapper.js';
import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
import {NIC_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js';
@@ -26,6 +29,14 @@
return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${versionId}/components/${componentId}/nics`;
}
+function createNIC({nic, vspId, componentId, version}) {
+ return RestAPIUtil.post(baseUrl(vspId, version, componentId), {
+ name: nic.name,
+ description: nic.description,
+ networkDescription: nic.networkDescription,
+ networkType: nic.networkType
+ });
+}
function fetchNICQuestionnaire({softwareProductId, version, componentId, nicId}) {
return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}/${nicId}/questionnaire`);
@@ -39,11 +50,16 @@
return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}`);
}
-function saveNIC({softwareProductId, version, componentId, nic: {id, name, description, networkId}}) {
+function deleteNIC({softwareProductId, componentId, nicId, version}) {
+ return RestAPIUtil.destroy(`${baseUrl(softwareProductId, version, componentId)}/${nicId}`);
+}
+function saveNIC({softwareProductId, version, componentId, nic: {id, name, description, networkId, networkType, networkDescription}}) {
return RestAPIUtil.put(`${baseUrl(softwareProductId, version, componentId)}/${id}`,{
name,
description,
- networkId
+ networkId,
+ networkDescription,
+ networkType
});
}
@@ -62,23 +78,45 @@
});
},
- openNICEditor(dispatch, {nic = {}, data = {}}) {
+ openNICEditor(dispatch, {nic = {}, data = {}, softwareProductId, componentId, isReadOnlyMode, modalClassName}) {
dispatch({
- type: actionTypes.NICEditor.OPEN,
+ type: actionTypes.NICEditor.FILL_DATA,
nic: {...data, id: nic.id}
});
+ dispatch({
+ type: GlobalModalActions.GLOBAL_MODAL_SHOW,
+ data: {
+ modalClassName,
+ modalComponentProps: {softwareProductId, componentId, isReadOnlyMode},
+ modalComponentName: modalPagesMapper.NIC_EDITOR,
+ title: i18n('Edit NIC')
+ }
+ });
},
closeNICEditor(dispatch) {
dispatch({
- type: actionTypes.NICEditor.CLOSE
+ type: GlobalModalActions.GLOBAL_MODAL_CLOSE
+ });
+ dispatch({
+ type: actionTypes.NICEditor.CLEAR_DATA
});
},
+ createNIC(dispatch, {nic, softwareProductId, componentId, version}){
+ return createNIC({nic, vspId: softwareProductId, componentId, version}).then(() => {
+ return SoftwareProductComponentNetworkActionHelper.fetchNICsList(dispatch, {softwareProductId, componentId, version});
+ });
+ },
loadNICData({softwareProductId, version, componentId, nicId}) {
return fetchNIC({softwareProductId, version, componentId, nicId});
},
+ deleteNIC(dispatch, {softwareProductId, componentId, nicId, version}) {
+ return deleteNIC({softwareProductId, componentId, nicId, version}).then(() => {
+ return SoftwareProductComponentNetworkActionHelper.fetchNICsList(dispatch, {softwareProductId, componentId, version});
+ });
+ },
loadNICQuestionnaire(dispatch, {softwareProductId, version, componentId, nicId}) {
return fetchNICQuestionnaire({softwareProductId, version, componentId, nicId}).then((response) => {
ValidationHelper.qDataLoaded(dispatch, {qName: NIC_QUESTIONNAIRE ,response: {
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js
index 39c55d8..8ef8fe8 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js
@@ -20,9 +20,19 @@
NIC_LIST_UPDATE: null,
NICEditor: {
+ FILL_DATA: null,
+ CLEAR_DATA: null,
+ },
+ NICCreation: {
OPEN: null,
- CLOSE: null
- }
+ CLEAR_DATA: null,
+ DATA_CHANGED: null
+ },
});
+export const networkTypes = {
+ EXTERNAL: 'External',
+ INTERNAL: 'Internal'
+};
export const NIC_QUESTIONNAIRE = 'nic';
+export const NIC_CREATION_FORM_NAME = 'nicCreation';
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkList.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkList.js
index c2bd8ce..0fa877e 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkList.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkList.js
@@ -14,6 +14,7 @@
* permissions and limitations under the License.
*/
import {connect} from 'react-redux';
+import i18n from 'nfvo-utils/i18n/i18n.js';
import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js';
import SoftwareProductComponentsActionHelper from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js';
@@ -21,16 +22,17 @@
import SoftwareProductComponentsNetworkActionHelper from './SoftwareProductComponentsNetworkActionHelper.js';
import {COMPONENTS_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js';
import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
+import {actionTypes as GlobalModalActions} from 'nfvo-components/modal/GlobalModalConstants.js';
+import NICCreationActionHelper from './NICCreation/NICCreationActionHelper.js';
+import {onboardingMethod as onboardingMethodTypes} from '../../SoftwareProductConstants.js';
export const mapStateToProps = ({softwareProduct}) => {
let {softwareProductEditor: {data: currentSoftwareProduct = {}, isValidityData = true}, softwareProductComponents} = softwareProduct;
- let {network: {nicEditor = {}, nicList = []}, componentEditor: {data: componentData, qdata, dataMap, qgenericFieldInfo}} = softwareProductComponents;
- let {data} = nicEditor;
+ let {network: {nicList = []}, componentEditor: {data: componentData, qdata, dataMap, qgenericFieldInfo}} = softwareProductComponents;
let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct);
- let {version} = currentSoftwareProduct;
- let isModalInEditMode = true;
+ let {version, onboardingMethod} = currentSoftwareProduct;
return {
version,
@@ -40,9 +42,8 @@
qgenericFieldInfo,
isValidityData,
nicList,
- isDisplayModal: Boolean(data),
- isModalInEditMode,
- isReadOnlyMode
+ isReadOnlyMode,
+ isManual: onboardingMethod === onboardingMethodTypes.MANUAL
};
};
@@ -51,7 +52,16 @@
return {
onQDataChanged: (deltaData) => ValidationHelper.qDataChanged(dispatch, {deltaData,
qName: COMPONENTS_QUESTIONNAIRE}),
- onEditNicClick: (nic, version) => {
+ onAddNic: () => NICCreationActionHelper.open(dispatch, {softwareProductId, componentId, modalClassName: 'network-nic-modal-create'}),
+ onDeleteNic: (nic, version) => dispatch({
+ type: GlobalModalActions.GLOBAL_MODAL_WARNING,
+ data:{
+ msg: i18n(`Are you sure you want to delete "${nic.name}"?`),
+ onConfirmed: () => SoftwareProductComponentsNetworkActionHelper.deleteNIC(dispatch, {softwareProductId,
+ componentId, nicId: nic.id, version})
+ }
+ }),
+ onEditNicClick: (nic, version, isReadOnlyMode) => {
Promise.all([
SoftwareProductComponentsNetworkActionHelper.loadNICData({
softwareProductId,
@@ -66,7 +76,8 @@
nicId: nic.id
})
]).then(
- ([{data}]) => SoftwareProductComponentsNetworkActionHelper.openNICEditor(dispatch, {nic, data})
+ ([{data}]) => SoftwareProductComponentsNetworkActionHelper.openNICEditor(dispatch, {nic, data,
+ isReadOnlyMode, softwareProductId, componentId, modalClassName: 'network-nic-modal-edit'})
);
},
onSubmit: ({qdata, version}) => { return SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire(dispatch,
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkListView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkListView.jsx
index f715016..5a159b4 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkListView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkListView.jsx
@@ -21,9 +21,7 @@
import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx';
import ListEditorItemViewField from 'nfvo-components/listEditor/ListEditorItemViewField.jsx';
import Input from'nfvo-components/input/validation/Input.jsx';
-import Modal from 'nfvo-components/modal/Modal.jsx';
-import SoftwareProductComponentsNICEditor from './SoftwareProductComponentsNICEditor.js';
class SoftwareProductComponentsNetworkView extends React.Component {
@@ -32,7 +30,7 @@
};
render() {
- let {dataMap, qgenericFieldInfo, onQDataChanged, isModalInEditMode, isDisplayModal, softwareProductId, componentId, isReadOnlyMode} = this.props;
+ let {dataMap, qgenericFieldInfo, onQDataChanged, isReadOnlyMode} = this.props;
return(
<div className='vsp-components-network'>
@@ -85,26 +83,14 @@
</div>
{this.renderNicList()}
</div>
- <Modal show={isDisplayModal} bsSize='large' animation={true} className='network-nic-modal'>
- <Modal.Header>
- <Modal.Title>{isModalInEditMode ? i18n('Edit NIC') : i18n('Create New NIC')}</Modal.Title>
- </Modal.Header>
- <Modal.Body>
- {
- <SoftwareProductComponentsNICEditor
- softwareProductId={softwareProductId}
- componentId={componentId}
- isReadOnlyMode={isReadOnlyMode}/>
- }
- </Modal.Body>
- </Modal>
+
</div>
);
}
renderNicList() {
const {localFilter} = this.state;
- let {isReadOnlyMode} = this.props;
+ let {isReadOnlyMode, onAddNic, isManual} = this.props;
return (
<ListEditorView
title={i18n('Interfaces')}
@@ -112,6 +98,8 @@
placeholder={i18n('Filter NICs by Name')}
isReadOnlyMode={isReadOnlyMode}
onFilter={value => this.setState({localFilter: value})}
+ onAdd={isManual ? onAddNic : null}
+ plusButtonTitle={i18n('Add NIC')}
twoColumns>
{this.filterList().map(nic => this.renderNicListItem(nic, isReadOnlyMode))}
</ListEditorView>
@@ -120,25 +108,26 @@
renderNicListItem(nic, isReadOnlyMode) {
let {id, name, description, networkName = ''} = nic;
- let {onEditNicClick, version} = this.props;
+ let {onEditNicClick, version, isManual, onDeleteNic} = this.props;
return (
<ListEditorItemView
key={id}
isReadOnlyMode={isReadOnlyMode}
- onSelect={() => onEditNicClick(nic, version)}>
+ onSelect={() => onEditNicClick(nic, version, isReadOnlyMode)}
+ onDelete={isManual ? () => onDeleteNic(nic, version) : null}>
<ListEditorItemViewField>
<div className='name'>{name}</div>
</ListEditorItemViewField>
<ListEditorItemViewField>
- <div className='details'>
- <div className='title'>{i18n('Purpose of NIC')}</div>
- <div className='description'>{description}</div>
+ <div className={isManual ? 'details-col' : 'details'}>
+ <div className={isManual ? 'manual-title' : 'title'}>{i18n('Purpose of NIC')}</div>
+ <div className={isManual ? 'description' : ''}>{description ? description : i18n('N/A')}</div>
</div>
- <div className='details'>
+ {!isManual && <div className='details'>
<div className='title'>{i18n('Network')}</div>
<div className='artifact-name'>{networkName}</div>
- </div>
+ </div>}
</ListEditorItemViewField>
</ListEditorItemView>
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/NameAndPurpose.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/NameAndPurpose.jsx
index 3dc153d..bc692e7 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/NameAndPurpose.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/NameAndPurpose.jsx
@@ -19,7 +19,7 @@
import GridSection from 'nfvo-components/grid/GridSection.jsx';
import GridItem from 'nfvo-components/grid/GridItem.jsx';
-const NameAndPurpose = ({onDataChanged, isReadOnlyMode, name, description}) => {
+const NameAndPurpose = ({onDataChanged, genericFieldInfo, isReadOnlyMode, name, description, isManual}) => {
return (
<GridSection>
@@ -28,7 +28,11 @@
label={i18n('Name')}
value={name}
data-test-id='nic-name'
- disabled={true}
+ disabled={!isManual}
+ isRequired={true}
+ onChange={name => onDataChanged({name})}
+ isValid={genericFieldInfo['name'].isValid}
+ errorText={genericFieldInfo['name'].errorText}
type='text' />
</GridItem>
<GridItem colSpan={2}>
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Network.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Network.jsx
index 43afdbe..8d9b79e 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Network.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Network.jsx
@@ -18,15 +18,17 @@
import Input from 'nfvo-components/input/validation/Input.jsx';
import GridSection from 'nfvo-components/grid/GridSection.jsx';
import GridItem from 'nfvo-components/grid/GridItem.jsx';
+import { networkTypes } from '../SoftwareProductComponentsNetworkConstants.js';
-const Network = ({networkValues}) => {
+const Network = ({networkValues, networkType, networkDescription, onDataChanged, isReadOnlyMode}) => {
+ const isExternal = networkType === networkTypes.EXTERNAL;
return (
<GridSection title={i18n('Network')}>
<GridItem>
<Input
label={i18n('Internal')}
disabled
- checked={true}
+ checked={!isExternal}
data-test-id='nic-internal'
className='network-radio disabled'
type='radio'/>
@@ -35,12 +37,21 @@
<Input
label={i18n('External')}
disabled
- checked={false}
+ checked={isExternal}
data-test-id='nic-external'
className='network-radio disabled'
type='radio'/>
</GridItem>
<GridItem colSpan={2}>
+ {isExternal ?
+ <Input
+ label={i18n('Network Description')}
+ value={networkDescription}
+ data-test-id='nic-network-description'
+ onChange={networkDescription => onDataChanged({networkDescription})}
+ disabled={isReadOnlyMode}
+ type='text'/>
+ :
<Input
label={i18n('Network')}
data-test-id='nic-network'
@@ -48,8 +59,8 @@
className='input-options-select'
groupClassName='bootstrap-input-options'
disabled={true} >
- {networkValues.map(val => <option key={val.enum} value={val.enum}>{val.title}</option>)}
- </Input>
+ {networkValues.map(val => <option key={val.enum} value={val.enum}>{val.title}</option>)}
+ </Input>}
</GridItem>
</GridSection>
);
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesList.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesList.js
index a8cb709..8262011 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesList.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesList.js
@@ -47,7 +47,7 @@
onDeleteProcessClick: (process, version) => dispatch({
type: modalActionTypes.GLOBAL_MODAL_WARNING,
data:{
- msg: i18n('Are you sure you want to delete "{name}"?', {name: process.name}),
+ msg: i18n(`Are you sure you want to delete "${process.name}"?`),
onConfirmed: ()=> SoftwareProductComponentProcessesActionHelper.deleteProcess(dispatch,
{process, softwareProductId, version, componentId})
}
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentsProcessesListView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentsProcessesListView.jsx
index 650d6d5..93d5ce8 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentsProcessesListView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentsProcessesListView.jsx
@@ -44,7 +44,7 @@
return (
<div className='vsp-processes-page'>
<div className='software-product-view'>
- <div className='software-product-landing-view-right-side flex-column'>
+ <div className='software-product-landing-view-right-side vsp-components-processes-page flex-column'>
{this.renderEditor()}
{this.renderProcessList()}
</div>
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationActionHelper.js
index 3b434e3..a22b517 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationActionHelper.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationActionHelper.js
@@ -17,7 +17,7 @@
import Configuration from 'sdc-app/config/Configuration.js';
import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js';
-import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
+import {actionTypes as modalActionTypes, modalSizes} from 'nfvo-components/modal/GlobalModalConstants.js';
import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js';
import {actionTypes} from './SoftwareProductCreationConstants.js';
import i18n from 'nfvo-utils/i18n/i18n.js';
@@ -48,9 +48,10 @@
type: modalActionTypes.GLOBAL_MODAL_SHOW,
data: {
modalComponentName: modalContentMapper.SOFTWARE_PRODUCT_CREATION,
- title: i18n('New Software Product'),
+ title: i18n('New Software Product'),
modalComponentProps: {
- vendorId
+ vendorId,
+ size: modalSizes.LARGE
}
}
});
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationReducer.js
index f7a7385..a7db2b2 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationReducer.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationReducer.js
@@ -15,6 +15,7 @@
*/
import {actionTypes, SP_CREATION_FORM_NAME} from './SoftwareProductCreationConstants.js';
+
export default (state = {}, action) => {
switch (action.type) {
case actionTypes.OPEN:
@@ -50,6 +51,11 @@
isValid: true,
errorText: '',
validations: [{type: 'required', data: true}, {type: 'maxLength', data: 25}, {type: 'validateName', data: true}]
+ },
+ 'onboardingMethod' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'requiredChooseOption', data: true}]
}
},
showModal: true
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx
index 11b6968..11f3543 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx
@@ -18,10 +18,14 @@
import Validator from 'nfvo-utils/Validator.js';
import Input from 'nfvo-components/input/validation/Input.jsx';
import Form from 'nfvo-components/input/validation/Form.jsx';
+import GridSection from 'nfvo-components/grid/GridSection.jsx';
+import GridItem from 'nfvo-components/grid/GridItem.jsx';
+
import {SP_CREATION_FORM_NAME} from './SoftwareProductCreationConstants.js';
import sortByStringProperty from 'nfvo-utils/sortByStringProperty.js';
import SoftwareProductCategoriesHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductCategoriesHelper.js';
+import {onboardingMethod as onboardingMethodConst} from '../SoftwareProductConstants.js';
const SoftwareProductPropType = React.PropTypes.shape({
id: React.PropTypes.string,
@@ -46,7 +50,7 @@
render() {
let {softwareProductCategories, data = {}, onDataChanged, onCancel, genericFieldInfo, disableVendor} = this.props;
- let {name, description, vendorId, subCategory} = data;
+ let {name, description, vendorId, subCategory, onboardingMethod} = data;
const vendorList = this.getVendorList();
return (
@@ -58,10 +62,11 @@
onReset={() => onCancel() }
labledButtons={true}
isValid={this.props.isFormValid}
+ submitButtonText={i18n('Create')}
formReady={this.props.formReady}
onValidateForm={() => this.validate() }>
- <div className='software-product-form-row'>
- <div className='software-product-inline-section'>
+ <GridSection>
+ <GridItem colSpan='2'>
<Input
value={name}
label={i18n('Name')}
@@ -76,6 +81,7 @@
label={i18n('Vendor')}
type='select'
value={vendorId}
+ overlayPos='bottom'
isRequired={true}
disabled={disableVendor}
onChange={e => this.onSelectVendor(e)}
@@ -108,8 +114,8 @@
</optgroup>)
}
</Input>
- </div>
- <div className='software-product-inline-section'>
+ </GridItem>
+ <GridItem colSpan='2' stretch>
<Input
value={description}
label={i18n('Description')}
@@ -120,9 +126,10 @@
errorText={genericFieldInfo.description.errorText}
type='textarea'
className='field-section'
- data-test-id='new-vsp-description' />
- </div>
- </div>
+ data-test-id='new-vsp-description'/>
+ </GridItem>
+ </GridSection>
+ <OnboardingProcedure genericFieldInfo={genericFieldInfo} onboardingMethod={onboardingMethod} onDataChanged={onDataChanged} />
</Form>}
</div>
);
@@ -174,4 +181,33 @@
}
}
+const OnboardingProcedure = ({onboardingMethod, onDataChanged, genericFieldInfo}) => {
+ return(
+ <GridSection title={i18n('Onboarding procedure')}>
+ <GridItem colSpan={4}>
+ <Input
+ label={i18n('HEAT file')}
+ overlayPos='top'
+ isValid={genericFieldInfo.onboardingMethod.isValid}
+ checked={onboardingMethod === onboardingMethodConst.HEAT}
+ errorText={genericFieldInfo.onboardingMethod.errorText}
+ onChange={() => onDataChanged({onboardingMethod:'HEAT'},SP_CREATION_FORM_NAME)}
+ type='radio'
+ data-test-id='new-vsp-creation-procedure-heat' />
+ </GridItem>
+ <GridItem colSpan={4}>
+ <Input
+ label={i18n('Manual')}
+ overlayPos='bottom'
+ checked={onboardingMethod === onboardingMethodConst.MANUAL}
+ isValid={genericFieldInfo.onboardingMethod.isValid}
+ errorText={genericFieldInfo.onboardingMethod.errorText}
+ onChange={() => onDataChanged({onboardingMethod:'Manual'},SP_CREATION_FORM_NAME)}
+ type='radio'
+ data-test-id='new-vsp-creation-procedure-manual' />
+ </GridItem>
+ </GridSection>
+ );
+};
+
export default SoftwareProductCreationView;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesView.jsx
index da975a7..2e0cd34 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesView.jsx
@@ -60,6 +60,7 @@
<div className='software-product-dependencies-title'>{i18n('Dependencies')}</div>
<SelectActionTable
columns={['Source', 'Relation Type', 'Target']}
+ numOfIcons={2}
isReadOnlyMode={isReadOnlyMode}
onAdd={canAdd ? onAddDependency : undefined}
onAddItem={i18n('Add Rule')}>
@@ -68,7 +69,8 @@
key={dependency.id}
onDelete={() => onDataChanged(softwareProductDependencies.filter(currentDependency => currentDependency.id !== dependency.id))}
overlayMsg={i18n('There is a loop between selections')}
- hasError={dependency.hasCycle}>
+ hasError={dependency.hasCycle}
+ hasErrorIndication>
<SelectActionTableCell
options={this.filterSources({componentsOptions, sourceToTargetMapping, selectedSourceId: dependency.sourceId, selectedTargetId: dependency.targetId})}
selected={dependency.sourceId}
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeployment.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeployment.js
new file mode 100644
index 0000000..98f773b
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeployment.js
@@ -0,0 +1,52 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import {connect} from 'react-redux';
+import SoftwareProductDeploymentView from './SoftwareProductDeploymentView.jsx';
+import SoftwareProductDeploymentActionHelper from './SoftwareProductDeploymentActionHelper.js';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
+import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js';
+
+export function mapStateToProps({softwareProduct}) {
+ let {softwareProductEditor: {data: currentSoftwareProduct = {}},softwareProductComponents: {componentsList}, softwareProductDeployment: {deploymentFlavors}} = softwareProduct;
+ let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct);
+ return {
+ isReadOnlyMode,
+ deploymentFlavors,
+ componentsList
+ };
+}
+
+function mapActionToProps(dispatch, {softwareProductId, version}) {
+ let modalClassName = 'deployment-flavor-editor';
+ return {
+ onAddDeployment: componentsList => SoftwareProductDeploymentActionHelper.openDeploymentFlavorEditor(dispatch, {softwareProductId, modalClassName, componentsList, version}),
+ onDeleteDeployment: ({id, model}) => dispatch({
+ type: modalActionTypes.GLOBAL_MODAL_WARNING,
+ data:{
+ msg: i18n(`Are you sure you want to delete "${model}"?`),
+ onConfirmed: () => SoftwareProductDeploymentActionHelper.deleteDeploymentFlavor(dispatch, {softwareProductId, deploymentFlavorId: id, version})
+ }
+ }),
+ onEditDeployment: (deploymentFlavor, componentsList) =>
+ SoftwareProductDeploymentActionHelper.fetchDeploymentFlavor({softwareProductId, deploymentFlavorId: deploymentFlavor.id, version}).then(response =>
+ SoftwareProductDeploymentActionHelper
+ .openDeploymentFlavorEditor(dispatch, {softwareProductId, componentsList, modalClassName, deploymentFlavor: {...response.data, id: response.id}, isEdit: true, version}),
+ )
+ };
+}
+
+export default connect(mapStateToProps, mapActionToProps, null, {withRef: true})(SoftwareProductDeploymentView);
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentActionHelper.js
new file mode 100644
index 0000000..bd802b3
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentActionHelper.js
@@ -0,0 +1,101 @@
+import {actionTypes} from './SoftwareProductDeploymentConstants.js';
+import {actionTypes as GlobalModalActions} from 'nfvo-components/modal/GlobalModalConstants.js';
+import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js';
+import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js';
+import Configuration from 'sdc-app/config/Configuration.js';
+import pickBy from 'lodash/pickBy';
+
+function baseUrl(vspId, version) {
+ const versionId = version.id;
+ const restPrefix = Configuration.get('restPrefix');
+ return `${restPrefix}/v1.0/vendor-software-products/${vspId}/versions/${versionId}/deployment-flavors`;
+}
+
+function fetchDeploymentFlavorsList({softwareProductId, version}) {
+ return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}`);
+}
+
+function fetchDeploymentFlavor({softwareProductId, deploymentFlavorId, version}) {
+ return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}/${deploymentFlavorId}`);
+}
+
+function deleteDeploymentFlavor({softwareProductId, deploymentFlavorId, version}) {
+ return RestAPIUtil.destroy(`${baseUrl(softwareProductId, version)}/${deploymentFlavorId}`);
+}
+
+function createDeploymentFlavor({softwareProductId, data, version}) {
+ return RestAPIUtil.post(`${baseUrl(softwareProductId, version)}`, data);
+}
+
+function editDeploymentFlavor({softwareProductId, deploymentFlavorId, data, version}) {
+ return RestAPIUtil.put(`${baseUrl(softwareProductId, version)}/${deploymentFlavorId}`, data);
+}
+
+const SoftwareProductDeploymentActionHelper = {
+ fetchDeploymentFlavorsList(dispatch, {softwareProductId, version}) {
+ return fetchDeploymentFlavorsList({softwareProductId, version}).then(response => {
+ dispatch({
+ type: actionTypes.FETCH_SOFTWARE_PRODUCT_DEPLOYMENT_FLAVORS,
+ deploymentFlavors: response.results
+ });
+ });
+ },
+
+ fetchDeploymentFlavor({softwareProductId, deploymentFlavorId, version}) {
+ return fetchDeploymentFlavor({softwareProductId, deploymentFlavorId, version});
+ },
+
+ deleteDeploymentFlavor(dispatch, {softwareProductId, deploymentFlavorId, version}) {
+ return deleteDeploymentFlavor({softwareProductId, deploymentFlavorId, version}).then(() => {
+ return SoftwareProductDeploymentActionHelper.fetchDeploymentFlavorsList(dispatch, {softwareProductId, version});
+ });
+ },
+
+ createDeploymentFlavor(dispatch, {softwareProductId, data, version}) {
+ return createDeploymentFlavor({softwareProductId, data, version}).then(() => {
+ return SoftwareProductDeploymentActionHelper.fetchDeploymentFlavorsList(dispatch, {softwareProductId, version});
+ });
+ },
+
+ editDeploymentFlavor(dispatch, {softwareProductId, deploymentFlavorId, data, version}) {
+ let dataWithoutId = pickBy(data, (val, key) => key !== 'id');
+ return editDeploymentFlavor({softwareProductId, deploymentFlavorId, data: dataWithoutId, version}).then(() => {
+ return SoftwareProductDeploymentActionHelper.fetchDeploymentFlavorsList(dispatch, {softwareProductId, version});
+ });
+ },
+
+ closeDeploymentFlavorEditor(dispatch) {
+ dispatch({
+ type: actionTypes.deploymentFlavorEditor.SOFTWARE_PRODUCT_DEPLOYMENT_CLEAR_DATA
+ });
+ dispatch({
+ type: GlobalModalActions.GLOBAL_MODAL_CLOSE
+ });
+ },
+
+ openDeploymentFlavorEditor(dispatch, {softwareProductId, modalClassName, deploymentFlavor = {}, componentsList, isEdit = false, version}) {
+ let alteredDeploymentFlavor = {...deploymentFlavor};
+ if (componentsList.length) {
+ alteredDeploymentFlavor = {...alteredDeploymentFlavor, componentComputeAssociations: deploymentFlavor.componentComputeAssociations ?
+ [{...deploymentFlavor.componentComputeAssociations[0], componentId: componentsList[0].id}]
+ :
+ [{componentId: componentsList[0].id, computeFlavorId: null}]
+ };
+ }
+ dispatch({
+ type: actionTypes.deploymentFlavorEditor.SOFTWARE_PRODUCT_DEPLOYMENT_FILL_DATA,
+ deploymentFlavor: alteredDeploymentFlavor
+ });
+ dispatch({
+ type: GlobalModalActions.GLOBAL_MODAL_SHOW,
+ data: {
+ modalComponentName: modalContentMapper.DEPLOYMENT_FLAVOR_EDITOR,
+ modalComponentProps: {softwareProductId, version},
+ modalClassName,
+ title: isEdit ? 'Edit Deployment Flavor' : 'Create a New Deployment Flavor'
+ }
+ });
+ },
+};
+
+export default SoftwareProductDeploymentActionHelper;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentConstants.js
new file mode 100644
index 0000000..51469b4
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentConstants.js
@@ -0,0 +1,28 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import keyMirror from 'nfvo-utils/KeyMirror.js';
+
+export const actionTypes = keyMirror({
+ FETCH_SOFTWARE_PRODUCT_DEPLOYMENT_FLAVORS: null,
+
+ deploymentFlavorEditor: {
+ DATA_CHANGED: null,
+ SOFTWARE_PRODUCT_DEPLOYMENT_FILL_DATA: null,
+ SOFTWARE_PRODUCT_DEPLOYMENT_CLEAR_DATA: null
+ }
+});
+
+export const DEPLOYMENT_FLAVORS_FORM_NAME = 'DEPLOYMENT_FLAVORS_FORM_NAME';
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentListReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentListReducer.js
new file mode 100644
index 0000000..8eb91e8
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentListReducer.js
@@ -0,0 +1,25 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import {actionTypes} from './SoftwareProductDeploymentConstants.js';
+
+export default (state = [], action) => {
+ switch (action.type) {
+ case actionTypes.FETCH_SOFTWARE_PRODUCT_DEPLOYMENT_FLAVORS:
+ return [...action.deploymentFlavors];
+ default:
+ return state;
+ }
+};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentView.jsx
new file mode 100644
index 0000000..81477ec
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentView.jsx
@@ -0,0 +1,94 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import React from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+
+import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx';
+import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx';
+import ListEditorItemViewField from 'nfvo-components/listEditor/ListEditorItemViewField.jsx';
+
+export default class SoftwareProductDeployment extends React.Component {
+ state = {
+ localFilter: ''
+ };
+
+ static propTypes = {
+ onAddDeployment: React.PropTypes.func.isRequired,
+ onDeleteDeployment: React.PropTypes.func.isRequired,
+ onEditDeployment: React.PropTypes.func.isRequired,
+ isReadOnlyMode: React.PropTypes.bool.isRequired
+ };
+
+ render() {
+ return (
+ <div>
+ {this.renderList()}
+ </div>
+ );
+ }
+
+ renderList() {
+ let {onAddDeployment, isReadOnlyMode, componentsList} = this.props;
+ return (
+ <ListEditorView
+ plusButtonTitle={i18n('Add Deployment Flavor')}
+ filterValue={this.state.localFilter}
+ placeholder={i18n('Filter Deployment')}
+ onAdd={() => onAddDeployment(componentsList)}
+ isReadOnlyMode={isReadOnlyMode}
+ title={i18n('Deployment Flavors')}
+ onFilter={value => this.setState({localFilter: value})}
+ twoColumns>
+ {this.filterList().map(deploymentFlavor => this.renderListItem(deploymentFlavor, isReadOnlyMode))}
+ </ListEditorView>
+ );
+ }
+
+ renderListItem(deploymentFlavor, isReadOnlyMode) {
+ let {id, model, description} = deploymentFlavor;
+ let {onEditDeployment, onDeleteDeployment, componentsList} = this.props;
+ return (
+ <ListEditorItemView
+ key={id}
+ className='list-editor-item-view'
+ isReadOnlyMode={isReadOnlyMode}
+ onSelect={() => onEditDeployment(deploymentFlavor, componentsList)}
+ onDelete={() => onDeleteDeployment(deploymentFlavor)}>
+ <ListEditorItemViewField>
+ <div className='model'>{model}</div>
+ </ListEditorItemViewField>
+ <ListEditorItemViewField>
+ <div className='description'>{description}</div>
+ </ListEditorItemViewField>
+ </ListEditorItemView>
+ );
+ }
+
+ filterList() {
+ let {deploymentFlavors} = this.props;
+ let {localFilter} = this.state;
+
+ if (localFilter.trim()) {
+ const filter = new RegExp(escape(localFilter), 'i');
+ return deploymentFlavors.filter(({model = '', description = ''}) => {
+ return escape(model).match(filter) || escape(description).match(filter);
+ });
+ }
+ else {
+ return deploymentFlavors;
+ }
+ }
+}
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditor.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditor.js
new file mode 100644
index 0000000..6b924a2
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditor.js
@@ -0,0 +1,88 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import {connect} from 'react-redux';
+import SoftwareProductDeploymentEditorView from './SoftwareProductDeploymentEditorView.jsx';
+import SoftwareProdcutDeploymentActionHelper from '../SoftwareProductDeploymentActionHelper.js';
+import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js';
+import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
+
+import {DEPLOYMENT_FLAVORS_FORM_NAME} from '../SoftwareProductDeploymentConstants.js';
+
+export function mapStateToProps({licenseModel, softwareProduct}) {
+ let {
+ softwareProductEditor: {
+ data: currentSoftwareProduct = {}
+ },
+ softwareProductComponents: {
+ componentsList,
+ computeFlavor: {
+ computesList
+ }
+ },
+ softwareProductDeployment: {
+ deploymentFlavors,
+ deploymentFlavorEditor: {
+ data = {},
+ genericFieldInfo,
+ formReady
+ }
+ }
+ } = softwareProduct;
+
+ let {
+ featureGroup: {
+ featureGroupsList
+ }
+ } = licenseModel;
+
+ let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct);
+ let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo);
+ let selectedFeatureGroupsIds = currentSoftwareProduct.licensingData ? currentSoftwareProduct.licensingData.featureGroups || [] : [];
+ let selectedFeatureGroupsList = featureGroupsList
+ .filter(featureGroup => selectedFeatureGroupsIds.includes(featureGroup.id))
+ .map(featureGroup => ({value: featureGroup.id, label: featureGroup.name}));
+
+ let DFNames = {};
+
+ deploymentFlavors.map(deployment => {
+ DFNames[deployment.model] = deployment.id;
+ });
+
+ return {
+ data,
+ selectedFeatureGroupsList,
+ genericFieldInfo,
+ DFNames,
+ isFormValid,
+ formReady,
+ isReadOnlyMode,
+ componentsList,
+ computesList,
+ isEdit: Boolean(data.id)
+ };
+}
+
+function mapActionsToProps(dispatch, {softwareProductId, version}) {
+ return {
+ onDataChanged: (deltaData, customValidations) => ValidationHelper.dataChanged(dispatch, {deltaData, formName: DEPLOYMENT_FLAVORS_FORM_NAME, customValidations}),
+ onClose: () => SoftwareProdcutDeploymentActionHelper.closeDeploymentFlavorEditor(dispatch),
+ onCreate: data => SoftwareProdcutDeploymentActionHelper.createDeploymentFlavor(dispatch, {softwareProductId, data, version}),
+ onEdit: data => SoftwareProdcutDeploymentActionHelper.editDeploymentFlavor(dispatch, {softwareProductId, deploymentFlavorId: data.id, data, version}),
+ onValidateForm: () => ValidationHelper.validateForm(dispatch, DEPLOYMENT_FLAVORS_FORM_NAME)
+ };
+}
+
+export default connect(mapStateToProps, mapActionsToProps)(SoftwareProductDeploymentEditorView);
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorReducer.js
new file mode 100644
index 0000000..70836e8
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorReducer.js
@@ -0,0 +1,44 @@
+/*!
+ * Copyright (C) 2017 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.
+ */
+import {actionTypes, DEPLOYMENT_FLAVORS_FORM_NAME} from '../SoftwareProductDeploymentConstants.js';;
+
+export default (state = {}, action) => {
+ switch (action.type) {
+ case actionTypes.deploymentFlavorEditor.SOFTWARE_PRODUCT_DEPLOYMENT_FILL_DATA:
+ return {
+ ...state,
+ data: action.deploymentFlavor,
+ formReady: null,
+ formName: DEPLOYMENT_FLAVORS_FORM_NAME,
+ genericFieldInfo: {
+ 'description' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'maxLength', data: 500}]
+ },
+ 'model' : {
+ isValid: true,
+ errorText: '',
+ validations: [{type: 'required', data: true}]
+ }
+ }
+ };
+ case actionTypes.deploymentFlavorEditor.SOFTWARE_PRODUCT_DEPLOYMENT_CLEAR_DATA:
+ return {};
+ default:
+ return state;
+ }
+};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorView.jsx
new file mode 100644
index 0000000..2d621cd
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorView.jsx
@@ -0,0 +1,137 @@
+import React from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import Input from 'nfvo-components/input/validation/Input.jsx';
+import Form from 'nfvo-components/input/validation/Form.jsx';
+import GridSection from 'nfvo-components/grid/GridSection.jsx';
+import GridItem from 'nfvo-components/grid/GridItem.jsx';
+import SelectInput from 'nfvo-components/input/SelectInput.jsx';
+import SelectActionTable from 'nfvo-components/table/SelectActionTable.jsx';
+import SelectActionTableRow from 'nfvo-components/table/SelectActionTableRow.jsx';
+import SelectActionTableCell from 'nfvo-components/table/SelectActionTableCell.jsx';
+import Validator from 'nfvo-utils/Validator.js';
+
+export default class SoftwareProductDeploymentEditorView extends React.Component {
+ render() {
+ let {data, isEdit, onClose, onDataChanged, isReadOnlyMode, selectedFeatureGroupsList, componentsList, computesList, genericFieldInfo} = this.props;
+ let {model, description, featureGroupId, componentComputeAssociations = []} = data;
+ let featureGroupsExist = selectedFeatureGroupsList.length > 0;
+ return (
+ <div>
+ {genericFieldInfo && <Form
+ ref='validationForm'
+ hasButtons={true}
+ labledButtons={true}
+ isReadOnlyMode={isReadOnlyMode}
+ onSubmit={ () => this.submit() }
+ submitButtonText={isEdit ? i18n('Save') : i18n('Create')}
+ onReset={ () => onClose() }
+ onValidateForm={() => this.validate() }
+ isValid={this.props.isFormValid}
+ formReady={this.props.formReady}
+ className='vsp-deployment-editor'>
+ <GridSection>
+ <GridItem colSpan={1}>
+ <Input
+ onChange={model => onDataChanged({model}, {model: model => this.validateName(model)})}
+ label={i18n('Model')}
+ value={model}
+ data-test-id='deployment-model'
+ isValid={genericFieldInfo.model.isValid}
+ errorText={genericFieldInfo.model.errorText}
+ isRequired={true}
+ type='text'/>
+ </GridItem>
+ <GridItem colSpan={3}>
+ <Input
+ onChange={description => onDataChanged({description})}
+ label={i18n('Description')}
+ value={description}
+ data-test-id='deployment-description'
+ isValid={genericFieldInfo.description.isValid}
+ errorText={genericFieldInfo.description.errorText}
+ type='text'/>
+ </GridItem>
+ </GridSection>
+ <GridSection className={`deployment-feature-groups-section${!featureGroupsExist ? ' no-feature-groups' : ''}`} title={i18n('License Details')}>
+ <GridItem colSpan={1}>
+ <SelectInput
+ data-test-id='deployment-feature-groups'
+ label={i18n('Feature Group')}
+ value={featureGroupId}
+ onChange={featureGroup => onDataChanged({featureGroupId: featureGroup ? featureGroup.value : null})}
+ type='select'
+ clearable={true}
+ disabled={isReadOnlyMode || !featureGroupsExist}
+ className='field-section'
+ options={selectedFeatureGroupsList}/>
+ </GridItem>
+ </GridSection>
+ {!featureGroupsExist && <GridSection className='deployment-feature-group-warning-section'>
+ <GridItem colSpan={3}>
+ <span>{i18n('Please assign Feature Groups in VSP General')}</span>
+ </GridItem>
+ </GridSection>}
+ <GridSection title={i18n('Assign VFCs and Compute Flavors')} className='vfc-table'>
+ <GridItem colSpan={4}>
+ <SelectActionTable
+ columns={['Virtual Function Components', 'Compute Flavors']}
+ numOfIcons={0}>
+ {componentComputeAssociations.map( (association, index) =>
+ <SelectActionTableRow key={association.componentId}>
+ <SelectActionTableCell
+ options={
+ componentsList
+ .map(component => ({value: component.id, label: component.displayName}) )
+ }
+ selected={association.componentId}
+ onChange={componentId => {
+ let newAssociations = [...componentComputeAssociations];
+ newAssociations[index] = {...newAssociations[index], componentId};
+ onDataChanged({componentComputeAssociations: newAssociations});
+ }}
+ disabled={true}/>
+ <SelectActionTableCell
+ options={
+ computesList
+ .filter(compute => compute.componentId === association.componentId)
+ .map(compute => ({value: compute.computeFlavorId, label: compute.name}) )
+ }
+ selected={association.computeFlavorId}
+ onChange={computeFlavorId => {
+ let newAssociations = [...componentComputeAssociations];
+ newAssociations[index] = {...newAssociations[index], computeFlavorId};
+ onDataChanged({componentComputeAssociations: newAssociations});
+ }}
+ disabled={isReadOnlyMode}/>
+ </SelectActionTableRow>
+ )}
+ </SelectActionTable>
+ </GridItem>
+ </GridSection>
+ </Form>}
+ </div>
+ );
+ }
+
+ validateName(value) {
+ const {data: {id = ''}, DFNames} = this.props;
+ const isExists = Validator.isItemNameAlreadyExistsInList({itemId: id, itemName: value, list: DFNames});
+
+ return !isExists ? {isValid: true, errorText: ''} :
+ {isValid: false, errorText: i18n('Deployment flavor by the name \'' + value + '\' already exists. Deployment flavor name must be unique')};
+ }
+
+ submit(){
+ let {isEdit, onCreate, onEdit, onClose, data} = this.props;
+ if (isEdit) {
+ onEdit(data);
+ } else {
+ onCreate(data);
+ }
+ onClose();
+ }
+
+ validate() {
+ this.props.onValidateForm();
+ }
+}
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js
index e8091bf..8806ffd 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js
@@ -20,6 +20,7 @@
import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js';
import LandingPageView from './SoftwareProductLandingPageView.jsx';
import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
+import {onboardingMethod} from '../SoftwareProductConstants.js';
export const mapStateToProps = ({softwareProduct, licenseModel: {licenseAgreement}}) => {
let {softwareProductEditor: {data:currentSoftwareProduct = {}}, softwareProductComponents, softwareProductCategories = []} = softwareProduct;
@@ -52,7 +53,8 @@
fullCategoryDisplayName
},
isReadOnlyMode,
- componentsList
+ componentsList,
+ isManual: currentSoftwareProduct.onboardingMethod === onboardingMethod.MANUAL
};
};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx
index 5fbf1b7..d3738e3 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx
@@ -19,11 +19,10 @@
import i18n from 'nfvo-utils/i18n/i18n.js';
-import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx';
-import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx';
-import ListEditorItemViewField from 'nfvo-components/listEditor/ListEditorItemViewField.jsx';
-import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
+
+import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
+import SoftwareProductComponentsList from '../components/SoftwareProductComponentsList.js';
const SoftwareProductPropType = React.PropTypes.shape({
name: React.PropTypes.string,
@@ -47,7 +46,7 @@
class SoftwareProductLandingPageView extends React.Component {
state = {
- localFilter: '',
+
fileName: '',
dragging: false,
files: []
@@ -67,13 +66,13 @@
};
render() {
- let {currentSoftwareProduct, isReadOnlyMode, componentsList = []} = this.props;
+ let {currentSoftwareProduct, isReadOnlyMode, isManual, onDetailsSelect, componentsList} = this.props;
return (
<div className='software-product-landing-wrapper'>
<Dropzone
className={classnames('software-product-landing-view', {'active-dragging': this.state.dragging})}
- onDrop={files => this.handleImportSubmit(files, isReadOnlyMode)}
- onDragEnter={() => this.handleOnDragEnter(isReadOnlyMode)}
+ onDrop={files => this.handleImportSubmit(files, isReadOnlyMode, isManual)}
+ onDragEnter={() => this.handleOnDragEnter(isReadOnlyMode, isManual)}
onDragLeave={() => this.setState({dragging:false})}
multiple={false}
disableClick={true}
@@ -84,68 +83,29 @@
<div className='draggable-wrapper'>
<div className='software-product-landing-view-top'>
<div className='row'>
- {this.renderProductSummary(currentSoftwareProduct)}
- {this.renderProductDetails(currentSoftwareProduct, isReadOnlyMode)}
+ <ProductSummary currentSoftwareProduct={currentSoftwareProduct} onDetailsSelect={onDetailsSelect} />
+ {isManual ?
+ <div className='details-panel'/>
+ : this.renderProductDetails(currentSoftwareProduct, isReadOnlyMode)}
</div>
</div>
</div>
</Dropzone>
- {
- componentsList.length > 0 && this.renderComponents()
- }
+ <SoftwareProductComponentsList
+ isReadOnlyMode={isReadOnlyMode}
+ componentsList={componentsList}
+ isManual={isManual}
+ currentSoftwareProduct={currentSoftwareProduct}/>
</div>
);
}
- handleOnDragEnter(isReadOnlyMode) {
- if (!isReadOnlyMode) {
+ handleOnDragEnter(isReadOnlyMode, isManual) {
+ if (!isReadOnlyMode && !isManual) {
this.setState({dragging: true});
}
}
- renderProductSummary(currentSoftwareProduct) {
- let {name = '', description = '', vendorName = '', fullCategoryDisplayName = '', licenseAgreementName = ''} = currentSoftwareProduct;
- let {onDetailsSelect} = this.props;
- return (
- <div className='details-panel'>
- <div className='software-product-landing-view-heading-title'>{i18n('Software Product Details')}</div>
- <div
- className='software-product-landing-view-top-block clickable'
- onClick={() => onDetailsSelect(currentSoftwareProduct)}>
- <div className='details-container'>
- <div className='single-detail-section title-section'>
- <div className='single-detail-section title-text'>
- {name}
- </div>
- </div>
- <div className='details-section'>
- <div className='multiple-details-section'>
- <div className='detail-col' >
- <div className='title'>{i18n('Vendor')}</div>
- <div className='description'>{vendorName}</div>
- </div>
- <div className='detail-col'>
- <div className='title'>{i18n('Category')}</div>
- <div className='description'>{fullCategoryDisplayName}</div>
- </div>
- <div className='detail-col'>
- <div className='title extra-large'>{i18n('License Agreement')}</div>
- <div className='description'>
- {this.renderLicenseAgreement(licenseAgreementName)}
- </div>
- </div>
- </div>
- <div className='single-detail-section'>
- <div className='title'>{i18n('Description')}</div>
- <div className='description'>{description}</div>
- </div>
- </div>
- </div>
- </div>
- </div>
- );
- }
-
renderProductDetails(currentSoftwareProduct, isReadOnlyMode) {
let {validationData} = currentSoftwareProduct;
let {onAttachmentsSelect} = this.props;
@@ -181,64 +141,8 @@
);
}
- renderComponents() {
- const {localFilter} = this.state;
-
- return (
- <ListEditorView
- title={i18n('Virtual Function Components')}
- filterValue={localFilter}
- placeholder={i18n('Filter Components')}
- onFilter={value => this.setState({localFilter: value})}
- twoColumns>
- {this.filterList().map(component => this.renderComponentsListItem(component))}
- </ListEditorView>
- );
- }
-
- renderComponentsListItem(component) {
- let {id: componentId, name, displayName, description = ''} = component;
- let {currentSoftwareProduct: {id}, onComponentSelect} = this.props;
- return (
- <ListEditorItemView
- key={name + Math.floor(Math.random() * (100 - 1) + 1).toString()}
- className='list-editor-item-view'
- onSelect={() => onComponentSelect({id, componentId})}>
- <ListEditorItemViewField>
- <div className='name'>{displayName}</div>
- </ListEditorItemViewField>
- <ListEditorItemViewField>
- <div className='description'>{description}</div>
- </ListEditorItemViewField>
- </ListEditorItemView>
- );
- }
-
- renderLicenseAgreement(licenseAgreementName) {
- if (licenseAgreementName !== null && !licenseAgreementName) {
- return (<div className='missing-license'><SVGIcon name='exclamation-triangle-full'/><div className='warning-text'>{i18n('Missing')}</div></div>);
- }
- return (licenseAgreementName);
- }
-
-
- filterList() {
- let {componentsList = []} = this.props;
-
- let {localFilter} = this.state;
- if (localFilter.trim()) {
- const filter = new RegExp(escape(localFilter), 'i');
- return componentsList.filter(({displayName = '', description = ''}) => {
- return escape(displayName).match(filter) || escape(description).match(filter);
- });
- }
- else {
- return componentsList;
- }
- }
-
- handleImportSubmit(files, isReadOnlyMode) {
- if (isReadOnlyMode) {
+ handleImportSubmit(files, isReadOnlyMode, isManual) {
+ if (isReadOnlyMode || isManual) {
return;
}
if (files[0] && files[0].size) {
@@ -280,4 +184,54 @@
}
}
+const ProductSummary = ({currentSoftwareProduct, onDetailsSelect}) => {
+ let {name = '', description = '', vendorName = '', fullCategoryDisplayName = '', licenseAgreementName = ''} = currentSoftwareProduct;
+ return (
+ <div className='details-panel'>
+ <div className='software-product-landing-view-heading-title'>{i18n('Software Product Details')}</div>
+ <div
+ className='software-product-landing-view-top-block clickable'
+ onClick={() => onDetailsSelect(currentSoftwareProduct)}>
+ <div className='details-container'>
+ <div className='single-detail-section title-section'>
+ <div className='single-detail-section title-text'>
+ {name}
+ </div>
+ </div>
+ <div className='details-section'>
+ <div className='multiple-details-section'>
+ <div className='detail-col' >
+ <div className='title'>{i18n('Vendor')}</div>
+ <div className='description'>{vendorName}</div>
+ </div>
+ <div className='detail-col'>
+ <div className='title'>{i18n('Category')}</div>
+ <div className='description'>{fullCategoryDisplayName}</div>
+ </div>
+ <div className='detail-col'>
+ <div className='title extra-large'>{i18n('License Agreement')}</div>
+ <div className='description'>
+ <LicenseAgreement licenseAgreementName={licenseAgreementName}/>
+ </div>
+ </div>
+ </div>
+ <div className='single-detail-section'>
+ <div className='title'>{i18n('Description')}</div>
+ <div className='description'>{description}</div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+};
+
+
+const LicenseAgreement = ({licenseAgreementName}) => {
+ if (!licenseAgreementName) {
+ return (<div className='missing-license'><SVGIcon name='exclamationTriangleFull'/><div className='warning-text'>{i18n('Missing')}</div></div>);
+ }
+ return <div>{licenseAgreementName}</div>;
+};
+
export default SoftwareProductLandingPageView;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcesses.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcesses.js
index 66926ce..afd6331 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcesses.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcesses.js
@@ -42,7 +42,7 @@
onDeleteProcess: (process, version) => dispatch({
type: modalActionTypes.GLOBAL_MODAL_WARNING,
data:{
- msg: i18n('Are you sure you want to delete "{name}"?', {name: process.name}),
+ msg: i18n(`Are you sure you want to delete "${process.name}"?`),
onConfirmed: ()=> SoftwareProductProcessesActionHelper.deleteProcess(dispatch,
{process, softwareProductId, version})
}