diff options
Diffstat (limited to 'openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute')
13 files changed, 690 insertions, 125 deletions
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 0000000000..02c09fbdf8 --- /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 e97477b54d..bb8df29b82 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 SoftwareProductComponentsActionHelper from 'sdc-app/onboarding/softwarePr 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 8c197f0d49..dd524a35f3 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 @@ class SoftwareProductComponentComputeView extends React.Component { 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 @@ class SoftwareProductComponentComputeView extends React.Component { 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 @@ class SoftwareProductComponentComputeView extends React.Component { 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 0000000000..c72d42c11f --- /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 7a730d6f94..16bf599834 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 @@ const GuestOs = ({qgenericFieldInfo, dataMap, onQDataChanged}) => { 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 @@ const GuestOs = ({qgenericFieldInfo, dataMap, onQDataChanged}) => { <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 efeedc653e..ddde4391d9 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 @@ const NumberOfVms = ({qgenericFieldInfo, dataMap, onQDataChanged, qValidateData, 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 39f84807a2..0000000000 --- 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 0000000000..41728eefb0 --- /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 0000000000..caec0702fd --- /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 0000000000..8f8a504629 --- /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 0000000000..6c02f36c90 --- /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 0000000000..a476f85a19 --- /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 0000000000..8b30468362 --- /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; |