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';
18 import i18n from 'nfvo-utils/i18n/i18n.js';
19 import Validator from 'nfvo-utils/Validator.js';
21 import Input from 'nfvo-components/input/validation/Input.jsx';
22 import InputOptions from 'nfvo-components/input/validation/InputOptions.jsx';
23 import Form from 'nfvo-components/input/validation/Form.jsx';
24 import GridSection from 'nfvo-components/grid/GridSection.jsx';
25 import GridItem from 'nfvo-components/grid/GridItem.jsx';
26 import {optionsInputValues as EntitlementPoolsOptionsInputValues, thresholdUnitType, SP_ENTITLEMENT_POOL_FORM, EP_TIME_FORMAT} from './EntitlementPoolsConstants.js';
27 import {other as optionInputOther} from 'nfvo-components/input/inputOptions/InputOptions.jsx';
29 const EntitlementPoolPropType = React.PropTypes.shape({
30 id: React.PropTypes.string,
31 name: React.PropTypes.string,
32 description: React.PropTypes.string,
33 manufacturerReferenceNumber: React.PropTypes.string,
34 operationalScope: React.PropTypes.shape({
35 choices: React.PropTypes.array,
36 other: React.PropTypes.string
38 aggregationFunction: React.PropTypes.shape({
39 choice: React.PropTypes.string,
40 other: React.PropTypes.string
42 increments: React.PropTypes.string,
43 time: React.PropTypes.shape({
44 choice: React.PropTypes.string,
45 other: React.PropTypes.string
47 entitlementMetric: React.PropTypes.shape({
48 choice: React.PropTypes.string,
49 other: React.PropTypes.string
53 const EntitlementPoolsFormContent = ({data, genericFieldInfo, onDataChanged, validateName, validateChoiceWithOther, validateTimeOtherValue,
54 thresholdValueValidation, validateStartDate}) => {
56 name, description, manufacturerReferenceNumber, operationalScope , aggregationFunction, thresholdUnits, thresholdValue,
57 increments, time, entitlementMetric, startDate, expiryDate} = data;
61 <GridItem colSpan={2}>
63 onChange={name => onDataChanged({name}, SP_ENTITLEMENT_POOL_FORM, {name: validateName})}
64 isValid={genericFieldInfo.name.isValid}
66 errorText={genericFieldInfo.name.errorText}
69 data-test-id='create-ep-name'
72 <GridItem colSpan={2}>
74 onInputChange={()=>{}}
78 onEnumChange={operationalScope => onDataChanged({operationalScope:{choices: operationalScope, other: ''}},
79 SP_ENTITLEMENT_POOL_FORM, {operationalScope: validateChoiceWithOther})}
80 onOtherChange={operationalScope => onDataChanged({operationalScope:{choices: [optionInputOther.OTHER],
81 other: operationalScope}}, SP_ENTITLEMENT_POOL_FORM, {operationalScope: validateChoiceWithOther})}
82 label={i18n('Operational Scope')}
83 data-test-id='create-ep-operational-scope'
85 multiSelectedEnum={operationalScope && operationalScope.choices}
86 otherValue={operationalScope && operationalScope.other}
87 values={EntitlementPoolsOptionsInputValues.OPERATIONAL_SCOPE}
88 isValid={genericFieldInfo.operationalScope.isValid}
89 errorText={genericFieldInfo.operationalScope.errorText} />
91 <GridItem colSpan={2} stretch>
93 onChange={description => onDataChanged({description}, SP_ENTITLEMENT_POOL_FORM)}
94 isValid={genericFieldInfo.description.isValid}
95 errorText={genericFieldInfo.description.errorText}
96 label={i18n('Description')}
99 data-test-id='create-ep-description'
102 <GridItem colSpan={2}>
103 <div className='threshold-section'>
107 // setting the unit to the correct value
108 const selectedIndex = e.target.selectedIndex;
109 const val = e.target.options[selectedIndex].value;
110 onDataChanged({thresholdUnits: val}, SP_ENTITLEMENT_POOL_FORM);
111 // TODO make sure that the value is valid too
112 onDataChanged({thresholdValue: thresholdValue}, SP_ENTITLEMENT_POOL_FORM,{thresholdValue : thresholdValueValidation});}
115 value={thresholdUnits}
116 label={i18n('Threshold Units')}
117 data-test-id='create-ep-threshold-units'
118 isValid={genericFieldInfo.thresholdUnits.isValid}
119 errorText={genericFieldInfo.thresholdUnits.errorText}
120 groupClassName='bootstrap-input-options'
121 className='input-options-select'
123 {EntitlementPoolsOptionsInputValues.THRESHOLD_UNITS.map(mtype =>
124 <option key={mtype.enum} value={mtype.enum}>{`${mtype.title}`}</option>)}
128 className='entitlement-pools-form-row-threshold-value'
129 onChange={thresholdValue => onDataChanged({thresholdValue}, SP_ENTITLEMENT_POOL_FORM,
130 {thresholdValue : thresholdValueValidation})}
131 label={i18n('Threshold Value')}
132 isValid={genericFieldInfo.thresholdValue.isValid}
133 errorText={genericFieldInfo.thresholdValue.errorText}
134 data-test-id='create-ep-threshold-value'
135 value={thresholdValue}
140 onInputChange={()=>{}}
141 isMultiSelect={false}
143 onEnumChange={entitlementMetric => onDataChanged({entitlementMetric:{choice: entitlementMetric, other: ''}},
144 SP_ENTITLEMENT_POOL_FORM, {entitlementMetric: validateChoiceWithOther})}
145 onOtherChange={entitlementMetric => onDataChanged({entitlementMetric:{choice: optionInputOther.OTHER,
146 other: entitlementMetric}}, SP_ENTITLEMENT_POOL_FORM, {entitlementMetric: validateChoiceWithOther})}
147 label={i18n('Entitlement Metric')}
148 data-test-id='create-ep-entitlement-metric'
151 selectedEnum={entitlementMetric && entitlementMetric.choice}
152 otherValue={entitlementMetric && entitlementMetric.other}
153 values={EntitlementPoolsOptionsInputValues.ENTITLEMENT_METRIC}
154 isValid={genericFieldInfo.entitlementMetric.isValid}
155 errorText={genericFieldInfo.entitlementMetric.errorText} />
157 onInputChange={()=>{}}
158 isMultiSelect={false}
160 onEnumChange={aggregationFunction => onDataChanged({aggregationFunction:{choice: aggregationFunction, other: ''}},
161 SP_ENTITLEMENT_POOL_FORM, {aggregationFunction: validateChoiceWithOther})}
162 onOtherChange={aggregationFunction => onDataChanged({aggregationFunction:{choice: optionInputOther.OTHER,
163 other: aggregationFunction}}, SP_ENTITLEMENT_POOL_FORM, {aggregationFunction: validateChoiceWithOther})}
164 label={i18n('Aggregate Function')}
165 data-test-id='create-ep-aggregate-function'
168 selectedEnum={aggregationFunction && aggregationFunction.choice}
169 otherValue={aggregationFunction && aggregationFunction.other}
170 values={EntitlementPoolsOptionsInputValues.AGGREGATE_FUNCTION}
171 isValid={genericFieldInfo.aggregationFunction.isValid}
172 errorText={genericFieldInfo.aggregationFunction.errorText} />
174 <GridItem colSpan={2}>
176 onChange={manufacturerReferenceNumber => onDataChanged({manufacturerReferenceNumber}, SP_ENTITLEMENT_POOL_FORM)}
177 label={i18n('Manufacturer Reference Number')}
178 value={manufacturerReferenceNumber}
179 isValid={genericFieldInfo.manufacturerReferenceNumber.isValid}
180 errorText={genericFieldInfo.manufacturerReferenceNumber.errorText}
182 data-test-id='create-ep-reference-number'
185 <GridItem colSpan={2}>
187 onInputChange={()=>{}}
188 isMultiSelect={false}
190 onEnumChange={time => onDataChanged({time:{choice: time, other: ''}},
191 SP_ENTITLEMENT_POOL_FORM, {time: validateChoiceWithOther})}
192 onOtherChange={time => onDataChanged({time:{choice: optionInputOther.OTHER,
193 other: time}}, SP_ENTITLEMENT_POOL_FORM, {time: validateTimeOtherValue})}
195 data-test-id='create-ep-time'
198 selectedEnum={time && time.choice}
199 otherValue={time && time.other}
200 values={EntitlementPoolsOptionsInputValues.TIME}
201 isValid={genericFieldInfo.time.isValid}
202 errorText={genericFieldInfo.time.errorText} />
204 <GridItem colSpan={2}>
206 onChange={increments => onDataChanged({increments}, SP_ENTITLEMENT_POOL_FORM)}
207 label={i18n('Increments')}
209 data-test-id='create-ep-increments'
212 <GridItem colSpan={2} />
213 <GridItem colSpan={2}>
216 label={i18n('Start Date')}
218 dateFormat={EP_TIME_FORMAT}
219 startDate={startDate}
221 onChange={startDate => onDataChanged(
222 {startDate: startDate ? startDate.format(EP_TIME_FORMAT) : ''},
223 SP_ENTITLEMENT_POOL_FORM,
224 {startDate: validateStartDate}
226 isValid={genericFieldInfo.startDate.isValid}
227 errorText={genericFieldInfo.startDate.errorText}
230 <GridItem colSpan={2}>
233 label={i18n('Expiry Date')}
235 dateFormat={EP_TIME_FORMAT}
236 startDate={startDate}
238 onChange={expiryDate => {
239 onDataChanged({expiryDate: expiryDate ? expiryDate.format(EP_TIME_FORMAT) : ''}, SP_ENTITLEMENT_POOL_FORM);
240 onDataChanged({startDate}, SP_ENTITLEMENT_POOL_FORM, {startDate: validateStartDate});
242 isValid={genericFieldInfo.expiryDate.isValid}
243 errorText={genericFieldInfo.expiryDate.errorText}
250 class EntitlementPoolsEditorView extends React.Component {
253 data: EntitlementPoolPropType,
254 previousData: EntitlementPoolPropType,
255 EPNames: React.PropTypes.object,
256 isReadOnlyMode: React.PropTypes.bool,
257 onDataChanged: React.PropTypes.func.isRequired,
258 onSubmit: React.PropTypes.func.isRequired,
259 onCancel: React.PropTypes.func.isRequired
262 static defaultProps = {
267 let {data = {}, onDataChanged, isReadOnlyMode, genericFieldInfo} = this.props;
273 genericFieldInfo && <Form
276 onSubmit={ () => this.submit() }
277 onReset={ () => this.props.onCancel() }
279 isReadOnlyMode={isReadOnlyMode}
280 isValid={this.props.isFormValid}
281 formReady={this.props.formReady}
282 onValidateForm={() => this.props.onValidateForm(SP_ENTITLEMENT_POOL_FORM) }
283 className='entitlement-pools-form'>
284 <EntitlementPoolsFormContent
286 genericFieldInfo={genericFieldInfo}
287 onDataChanged={onDataChanged}
288 validateName={(value)=> this.validateName(value)}
289 validateTimeOtherValue ={(value)=> this.validateTimeOtherValue(value)}
290 validateChoiceWithOther={(value)=> this.validateChoiceWithOther(value)}
291 validateStartDate={(value, state)=> this.validateStartDate(value, state)}
292 thresholdValueValidation={(value, state)=> this.thresholdValueValidation(value, state)}/>
300 const {data: entitlementPool, previousData: previousEntitlementPool} = this.props;
301 this.props.onSubmit({entitlementPool, previousEntitlementPool});
304 validateName(value) {
305 const {data: {id}, EPNames} = this.props;
306 const isExists = Validator.isItemNameAlreadyExistsInList({itemId: id, itemName: value, list: EPNames});
308 return !isExists ? {isValid: true, errorText: ''} :
309 {isValid: false, errorText: i18n('Entitlement pool by the name \'' + value + '\' already exists. Entitlement pool name must be unique')};
312 validateStartDate(value, state) {
313 if (state.data.expiryDate) {
315 return {isValid: false, errorText: i18n('Start date has to be specified if expiry date is specified')};
318 return {isValid: true, errorText: ''};
321 validateTimeOtherValue(value) {
322 return Validator.validate('time', value.other, [{type: 'required', data: true}, {type: 'numeric', data: true}]);
325 validateChoiceWithOther(value) {
326 let chosen = value.choice;
327 // if we have an empty multiple select we have a problem since it's required
329 if (value.choices.length === 0) {
330 return Validator.validate('field', '', [{type: 'required', data: true}]);
332 // continuing validation with the first chosen value in case we have the 'Other' field
333 chosen = value.choices[0];
336 if (chosen !== optionInputOther.OTHER) {
337 return Validator.validate('field', chosen, [{type: 'required', data: true}]);
338 } else { // when 'Other' was chosen, validate other value
339 return Validator.validate('field', value.other, [{type: 'required', data: true}]);
343 thresholdValueValidation(value, state) {
345 let unit = state.data.thresholdUnits;
346 if (unit === thresholdUnitType.PERCENTAGE) {
347 return Validator.validate('thresholdValue', value, [
348 {type: 'required', data: true},
349 {type: 'numeric', data: true},
350 {type: 'maximum', data: 100},
351 {type: 'minimum', data: 0}]);
353 return Validator.validate('thresholdValue', value, [
354 {type: 'numeric', data: true},
355 {type: 'required', data: true}]);
361 export default EntitlementPoolsEditorView;