2 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13 * or implied. See the License for the specific language governing
14 * permissions and limitations under the License.
16 import React from 'react';
17 import PropTypes from 'prop-types';
19 import i18n from 'nfvo-utils/i18n/i18n.js';
20 import Validator from 'nfvo-utils/Validator.js';
22 import Input from 'nfvo-components/input/validation/Input.jsx';
23 import InputOptions from 'nfvo-components/input/validation/InputOptions.jsx';
24 import Form from 'nfvo-components/input/validation/Form.jsx';
25 import Button from 'sdc-ui/lib/react/Button.js';
26 import GridSection from 'nfvo-components/grid/GridSection.jsx';
27 import GridItem from 'nfvo-components/grid/GridItem.jsx';
28 import {optionsInputValues as EntitlementPoolsOptionsInputValues, SP_ENTITLEMENT_POOL_FORM, tabIds} from './EntitlementPoolsConstants.js';
29 import {optionsInputValues as LicenseModelOptionsInputValues} from '../LicenseModelConstants.js';
30 import {validateStartDate, thresholdValueValidation} from '../LicenseModelValidations.js';
31 import {DATE_FORMAT} from 'sdc-app/onboarding/OnboardingConstants.js';
32 import {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx';
33 import Tabs from 'sdc-ui/lib/react/Tabs.js';
34 import Tab from 'sdc-ui/lib/react/Tab.js';
35 import EntitlementPoolsLimits from './EntitlementPoolsLimits.js';
36 import {limitType, NEW_LIMIT_TEMP_ID} from '../limits/LimitEditorConstants.js';
38 const EntitlementPoolPropType = PropTypes.shape({
40 name: PropTypes.string,
41 description: PropTypes.string,
42 operationalScope: PropTypes.shape({
43 choices: PropTypes.array,
44 other: PropTypes.string
46 thresholdUnits: PropTypes.string,
47 thresholdValue: PropTypes.string,
48 increments: PropTypes.string,
49 startDate: PropTypes.string,
50 expiryDate: PropTypes.string
53 const EntitlementPoolsFormContent = ({data, genericFieldInfo, onDataChanged, validateName,
54 thresholdValueValidation, validateStartDate}) => {
56 let {name, description, operationalScope, thresholdUnits, thresholdValue,
57 increments, startDate, expiryDate} = data;
59 <GridSection hasLastColSet>
60 <GridItem colSpan={2}>
62 onChange={name => onDataChanged({name}, SP_ENTITLEMENT_POOL_FORM, {name: validateName})}
63 isValid={genericFieldInfo.name.isValid}
65 errorText={genericFieldInfo.name.errorText}
68 data-test-id='create-ep-name'
71 <GridItem colSpan={2} lastColInRow>
73 onInputChange={()=>{}}
75 onEnumChange={operationalScope => onDataChanged({operationalScope:{choices: operationalScope, other: ''}},
76 SP_ENTITLEMENT_POOL_FORM)}
77 onOtherChange={operationalScope => onDataChanged({operationalScope:{choices: [optionInputOther.OTHER],
78 other: operationalScope}}, SP_ENTITLEMENT_POOL_FORM)}
79 label={i18n('Operational Scope')}
80 data-test-id='create-ep-operational-scope'
82 multiSelectedEnum={operationalScope && operationalScope.choices}
83 otherValue={operationalScope && operationalScope.other}
84 values={EntitlementPoolsOptionsInputValues.OPERATIONAL_SCOPE}
85 isValid={genericFieldInfo.operationalScope.isValid}
86 errorText={genericFieldInfo.operationalScope.errorText} />
88 <GridItem colSpan={2} stretch>
90 onChange={description => onDataChanged({description}, SP_ENTITLEMENT_POOL_FORM)}
91 isValid={genericFieldInfo.description.isValid}
92 errorText={genericFieldInfo.description.errorText}
93 label={i18n('Description')}
95 data-test-id='create-ep-description'
98 <GridItem colSpan={2} lastColInRow>
99 <div className='threshold-section'>
102 // setting the unit to the correct value
103 const selectedIndex = e.target.selectedIndex;
104 const val = e.target.options[selectedIndex].value;
105 onDataChanged({thresholdUnits: val}, SP_ENTITLEMENT_POOL_FORM);
106 // TODO make sure that the value is valid too
107 if(thresholdValue && thresholdValue !== '') {
108 onDataChanged({thresholdValue: thresholdValue}, SP_ENTITLEMENT_POOL_FORM,{thresholdValue : thresholdValueValidation});
112 value={thresholdUnits}
113 label={i18n('Threshold Units')}
114 data-test-id='create-ep-threshold-units'
115 isValid={genericFieldInfo.thresholdUnits.isValid}
116 errorText={genericFieldInfo.thresholdUnits.errorText}
117 groupClassName='bootstrap-input-options'
118 className='input-options-select'
120 {LicenseModelOptionsInputValues.THRESHOLD_UNITS.map(mtype =>
121 <option key={mtype.enum} value={mtype.enum}>{`${mtype.title}`}</option>)}
125 className='entitlement-pools-form-row-threshold-value'
126 onChange={thresholdValue => onDataChanged({thresholdValue}, SP_ENTITLEMENT_POOL_FORM,
127 {thresholdValue : thresholdValueValidation})}
128 label={i18n('Threshold Value')}
129 isValid={genericFieldInfo.thresholdValue.isValid}
130 errorText={genericFieldInfo.thresholdValue.errorText}
131 data-test-id='create-ep-threshold-value'
132 value={thresholdValue}
136 onChange={increments => onDataChanged({increments}, SP_ENTITLEMENT_POOL_FORM)}
137 label={i18n('Increments')}
139 data-test-id='create-ep-increments'
141 <div className='date-section'>
144 label={i18n('Start Date')}
146 dateFormat={DATE_FORMAT}
147 startDate={startDate}
149 onChange={startDate => onDataChanged(
150 {startDate: startDate ? startDate.format(DATE_FORMAT) : ''},
151 SP_ENTITLEMENT_POOL_FORM,
152 {startDate: validateStartDate}
154 isValid={genericFieldInfo.startDate.isValid}
155 errorText={genericFieldInfo.startDate.errorText}
159 label={i18n('Expiry Date')}
161 dateFormat={DATE_FORMAT}
162 startDate={startDate}
164 onChange={expiryDate => {
165 onDataChanged({expiryDate: expiryDate ? expiryDate.format(DATE_FORMAT) : ''}, SP_ENTITLEMENT_POOL_FORM);
166 onDataChanged({startDate}, SP_ENTITLEMENT_POOL_FORM, {startDate: validateStartDate});
168 isValid={genericFieldInfo.expiryDate.isValid}
169 errorText={genericFieldInfo.expiryDate.errorText}
177 class EntitlementPoolsEditorView extends React.Component {
180 data: EntitlementPoolPropType,
181 previousData: EntitlementPoolPropType,
182 EPNames: PropTypes.object,
183 isReadOnlyMode: PropTypes.bool,
184 onDataChanged: PropTypes.func.isRequired,
185 onSubmit: PropTypes.func.isRequired,
186 onCancel: PropTypes.func.isRequired
189 static defaultProps = {
193 componentDidUpdate(prevProps) {
194 if (this.props.formReady && this.props.formReady !== prevProps.formReady) { // if form validation succeeded -> continue with submit
200 selectedTab: tabIds.GENERAL,
205 let {data = {}, onDataChanged, isReadOnlyMode, genericFieldInfo, onCloseLimitEditor, limitsList = []} = this.props;
206 const {selectedTab} = this.state;
207 const isTabsDisabled = !data.id || !this.props.isFormValid;
213 activeTab={selectedTab}
214 onTabClick={(tabIndex)=>{
215 if (tabIndex === tabIds.ADD_LIMIT_BUTTON) {
218 this.setState({selectedTab: tabIndex});
219 this.setState({selectedLimit: ''});
220 onCloseLimitEditor();
224 <Tab tabId={tabIds.GENERAL} data-test-id='general-tab' title={i18n('General')}>
226 genericFieldInfo && <Form
229 labledButtons={false}
230 isReadOnlyMode={isReadOnlyMode}
231 isValid={this.props.isFormValid}
232 formReady={this.props.formReady}
233 onValidateForm={() => this.props.onValidateForm(SP_ENTITLEMENT_POOL_FORM) }
234 className='license-model-form entitlement-pools-form'>
235 <EntitlementPoolsFormContent
237 genericFieldInfo={genericFieldInfo}
238 onDataChanged={onDataChanged}
239 validateName={(value) => this.validateName(value)}
240 validateStartDate={(value, state) => validateStartDate(value, state)}
241 thresholdValueValidation={(value, state) => thresholdValueValidation(value, state)}/>
245 <Tab disabled={isTabsDisabled} tabId={tabIds.SP_LIMITS} data-test-id='sp-limits-tab' title={i18n('SP Limits')}>
246 {selectedTab === tabIds.SP_LIMITS &&
247 <EntitlementPoolsLimits
248 isReadOnlyMode={isReadOnlyMode}
249 limitType={limitType.SERVICE_PROVIDER}
250 limitsList={limitsList.filter(item => item.type === limitType.SERVICE_PROVIDER)}
251 selectedLimit={this.state.selectedLimit}
252 onCloseLimitEditor={() => this.onCloseLimitEditor()}
253 onSelectLimit={limit => this.onSelectLimit(limit)}/>}
255 <Tab disabled={isTabsDisabled} tabId={tabIds.VENDOR_LIMITS} data-test-id='vendor-limits-tab' title={i18n('Vendor Limits')}>
256 {selectedTab === tabIds.VENDOR_LIMITS &&
257 <EntitlementPoolsLimits
258 isReadOnlyMode={isReadOnlyMode}
259 limitType={limitType.VENDOR}
260 limitsList={limitsList.filter(item => item.type === limitType.VENDOR)}
261 selectedLimit={this.state.selectedLimit}
262 onCloseLimitEditor={() => this.onCloseLimitEditor()}
263 onSelectLimit={limit => this.onSelectLimit(limit)}/>}
266 selectedTab !== tabIds.GENERAL ?
268 disabled={this.state.selectedLimit || isReadOnlyMode}
269 className='add-limit-button'
270 tabId={tabIds.ADD_LIMIT_BUTTON}
276 <div></div> // Render empty div to not break tabs
279 <GridSection className='license-model-modal-buttons entitlement-pools-editor-buttons'>
280 {!this.state.selectedLimit &&
281 <Button btnType='default' disabled={!this.props.isFormValid || isReadOnlyMode} onClick={() => this.submit()} type='reset'>
285 <Button btnType={this.state.selectedLimit ? 'default' : 'outline'} onClick={() => this.props.onCancel()} type='reset'>
294 const {data: entitlementPool, previousData: previousEntitlementPool, formReady} = this.props;
296 this.props.onValidateForm(SP_ENTITLEMENT_POOL_FORM);
298 this.props.onSubmit({entitlementPool, previousEntitlementPool});
302 validateName(value) {
303 const {data: {id}, EPNames} = this.props;
304 const isExists = Validator.isItemNameAlreadyExistsInList({itemId: id, itemName: value, list: EPNames});
306 return !isExists ? {isValid: true, errorText: ''} :
307 {isValid: false, errorText: i18n('Entitlement pool by the name \'' + value + '\' already exists. Entitlement pool name must be unique')};
310 onSelectLimit(limit) {
311 if (limit.id === this.state.selectedLimit) {
312 this.setState({selectedLimit: ''});
315 this.setState({selectedLimit: limit.id});
316 this.props.onOpenLimitEditor(limit);
319 onCloseLimitEditor() {
320 this.setState({selectedLimit: ''});
321 this.props.onCloseLimitEditor();
325 this.setState({selectedLimit: NEW_LIMIT_TEMP_ID});
326 this.props.onOpenLimitEditor();
331 export default EntitlementPoolsEditorView;