Add collaboration feature
[sdc.git] / openecomp-ui / src / sdc-app / onboarding / licenseModel / entitlementPools / EntitlementPoolsEditorView.jsx
1 /*!
2  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 import React from 'react';
17 import PropTypes from 'prop-types';
18
19 import i18n from 'nfvo-utils/i18n/i18n.js';
20 import Validator from 'nfvo-utils/Validator.js';
21
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';
37
38 const EntitlementPoolPropType = PropTypes.shape({
39         id: PropTypes.string,
40         name: PropTypes.string,
41         description: PropTypes.string,
42         operationalScope: PropTypes.shape({
43                 choices: PropTypes.array,
44                 other: PropTypes.string
45         }),
46         thresholdUnits: PropTypes.string,
47         thresholdValue: PropTypes.string,
48         increments: PropTypes.string,
49         startDate: PropTypes.string,
50         expiryDate: PropTypes.string
51 });
52
53 const EntitlementPoolsFormContent = ({data, genericFieldInfo, onDataChanged, validateName,
54          thresholdValueValidation, validateStartDate}) => {
55
56         let {name, description, operationalScope, thresholdUnits, thresholdValue,
57                 increments, startDate, expiryDate} = data;
58         return (
59                 <GridSection hasLastColSet>
60                         <GridItem colSpan={2}>
61                                 <Input
62                                         onChange={name => onDataChanged({name}, SP_ENTITLEMENT_POOL_FORM, {name: validateName})}
63                                         isValid={genericFieldInfo.name.isValid}
64                                         isRequired={true}
65                                         errorText={genericFieldInfo.name.errorText}
66                                         label={i18n('Name')}
67                                         value={name}
68                                         data-test-id='create-ep-name'
69                                         type='text'/>
70                         </GridItem>
71                         <GridItem colSpan={2} lastColInRow>
72                                 <InputOptions
73                                         onInputChange={()=>{}}
74                                         isMultiSelect={true}
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'
81                                         type='select'
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} />
87                         </GridItem>
88                         <GridItem colSpan={2} stretch>
89                                 <Input
90                                         onChange={description => onDataChanged({description}, SP_ENTITLEMENT_POOL_FORM)}
91                                         isValid={genericFieldInfo.description.isValid}
92                                         errorText={genericFieldInfo.description.errorText}
93                                         label={i18n('Description')}
94                                         value={description}
95                                         data-test-id='create-ep-description'
96                                         type='textarea'/>
97                         </GridItem>
98                         <GridItem colSpan={2} lastColInRow>
99                                 <div className='threshold-section'>
100                                         <Input
101                                                 onChange={e => {
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});
109                                                         }}
110
111                                                 }
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'
119                                                 type='select' >
120                                                 {LicenseModelOptionsInputValues.THRESHOLD_UNITS.map(mtype =>
121                                                         <option key={mtype.enum} value={mtype.enum}>{`${mtype.title}`}</option>)}
122                                         </Input>
123
124                                         <Input
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}
133                                                 type='text'/>
134                                 </div>
135                                 <Input
136                                         onChange={increments => onDataChanged({increments}, SP_ENTITLEMENT_POOL_FORM)}
137                                         label={i18n('Increments')}
138                                         value={increments}
139                                         data-test-id='create-ep-increments'
140                                         type='text'/>
141                                 <div className='date-section'>
142                                         <Input
143                                                 type='date'
144                                                 label={i18n('Start Date')}
145                                                 value={startDate}
146                                                 dateFormat={DATE_FORMAT}
147                                                 startDate={startDate}
148                                                 endDate={expiryDate}
149                                                 onChange={startDate => onDataChanged(
150                                                         {startDate: startDate ? startDate.format(DATE_FORMAT) : ''},
151                                                         SP_ENTITLEMENT_POOL_FORM,
152                                                         {startDate: validateStartDate}
153                                                 )}
154                                                 isValid={genericFieldInfo.startDate.isValid}
155                                                 errorText={genericFieldInfo.startDate.errorText}
156                                                 selectsStart/>
157                                         <Input
158                                                 type='date'
159                                                 label={i18n('Expiry Date')}
160                                                 value={expiryDate}
161                                                 dateFormat={DATE_FORMAT}
162                                                 startDate={startDate}
163                                                 endDate={expiryDate}
164                                                 onChange={expiryDate => {
165                                                         onDataChanged({expiryDate: expiryDate ? expiryDate.format(DATE_FORMAT) : ''}, SP_ENTITLEMENT_POOL_FORM);
166                                                         onDataChanged({startDate}, SP_ENTITLEMENT_POOL_FORM, {startDate: validateStartDate});
167                                                 }}
168                                                 isValid={genericFieldInfo.expiryDate.isValid}
169                                                 errorText={genericFieldInfo.expiryDate.errorText}
170                                                 selectsEnd/>
171                                 </div>
172                         </GridItem>
173                 </GridSection>
174         );
175 };
176
177 class EntitlementPoolsEditorView extends React.Component {
178
179         static propTypes = {
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
187         };
188
189         static defaultProps = {
190                 data: {}
191         };
192
193         componentDidUpdate(prevProps) {
194                 if (this.props.formReady && this.props.formReady !== prevProps.formReady) { // if form validation succeeded -> continue with submit
195                         this.submit();
196                 }
197         }
198         
199         state = {               
200                 selectedTab: tabIds.GENERAL,
201                 selectedLimit: ''
202         };
203
204         render() {
205                 let {data = {}, onDataChanged, isReadOnlyMode, genericFieldInfo, onCloseLimitEditor, limitsList = []} = this.props;
206                 const {selectedTab} = this.state;
207                 const isTabsDisabled = !data.id || !this.props.isFormValid;
208
209                 return (
210                         <div>
211                         <Tabs
212                                 type='menu'
213                                 activeTab={selectedTab}
214                                 onTabClick={(tabIndex)=>{
215                                         if (tabIndex === tabIds.ADD_LIMIT_BUTTON)  {
216                                                 this.onAddLimit();
217                                         } else {
218                                                 this.setState({selectedTab: tabIndex});
219                                                 this.setState({selectedLimit: ''});
220                                                 onCloseLimitEditor();
221                                         }
222                                 }}
223                                 invalidTabs={[]}>
224                                 <Tab tabId={tabIds.GENERAL} data-test-id='general-tab' title={i18n('General')}>
225                                         {
226                                                 genericFieldInfo && <Form
227                                                         ref='validationForm'
228                                                         hasButtons={false}
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
236                                                                 data={data}
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)}/>
242                                                 </Form>
243                                         }
244                                 </Tab>
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)}/>}
254                                 </Tab>
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)}/>}
264                                 </Tab>
265                                 {
266                                         selectedTab !== tabIds.GENERAL ?
267                                                 <Button
268                                                         disabled={this.state.selectedLimit || isReadOnlyMode}
269                                                         className='add-limit-button'
270                                                         tabId={tabIds.ADD_LIMIT_BUTTON}
271                                                         btnType='link'
272                                                         iconName='plus'>
273                                                         {i18n('Add Limit')}
274                                                 </Button>
275                                         :
276                                                 <div></div> // Render empty div to not break tabs
277                                 }
278                         </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'>
282                                                 {i18n('Save')}
283                                         </Button>
284                                 }
285                         <Button btnType={this.state.selectedLimit ? 'default' : 'outline'} onClick={() => this.props.onCancel()} type='reset'>
286                                 {i18n('Cancel')}
287                         </Button>
288                         </GridSection>
289                         </div>
290                 );
291         }
292
293         submit() {
294                 const {data: entitlementPool, previousData: previousEntitlementPool, formReady} = this.props;
295                 if (!formReady) {
296                         this.props.onValidateForm(SP_ENTITLEMENT_POOL_FORM);
297                 } else {
298                         this.props.onSubmit({entitlementPool, previousEntitlementPool});
299                 }
300         }
301
302         validateName(value) {
303                 const {data: {id}, EPNames} = this.props;
304                 const isExists = Validator.isItemNameAlreadyExistsInList({itemId: id, itemName: value, list: EPNames});
305
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')};
308         }
309
310         onSelectLimit(limit) {
311                 if (limit.id === this.state.selectedLimit) {
312                         this.setState({selectedLimit: ''});
313                         return;
314                 }
315                 this.setState({selectedLimit: limit.id});
316                 this.props.onOpenLimitEditor(limit);
317         }
318
319         onCloseLimitEditor() {
320                 this.setState({selectedLimit: ''});
321                 this.props.onCloseLimitEditor();
322         }
323
324         onAddLimit() {
325                 this.setState({selectedLimit: NEW_LIMIT_TEMP_ID});
326                 this.props.onOpenLimitEditor();
327         }
328
329 }
330
331 export default EntitlementPoolsEditorView;