Add collaboration feature
[sdc.git] / openecomp-ui / src / sdc-app / onboarding / softwareProduct / details / SoftwareProductDetailsView.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, {Component} from 'react';
17 import PropTypes from 'prop-types';
18
19 import i18n from 'nfvo-utils/i18n/i18n.js';
20 import sortByStringProperty from 'nfvo-utils/sortByStringProperty.js';
21 import Form from 'nfvo-components/input/validation/Form.jsx';
22 import Input from 'nfvo-components/input/validation/Input.jsx';
23 import InputOptions from 'nfvo-components/input/validation/InputOptions.jsx';
24 import GridSection from 'nfvo-components/grid/GridSection.jsx';
25 import GridItem from 'nfvo-components/grid/GridItem.jsx';
26 import SoftwareProductCategoriesHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductCategoriesHelper.js';
27 import {forms} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
28
29 class GeneralSection extends React.Component {
30         static propTypes = {
31                 vendorId: PropTypes.string,
32                 name: PropTypes.string,
33                 description: PropTypes.string,
34                 subCategory: PropTypes.string,
35                 softwareProductCategories: PropTypes.array,
36                 finalizedLicenseModelList: PropTypes.array,
37                 onDataChanged: PropTypes.func.isRequired,
38                 onVendorParamChanged: PropTypes.func.isRequired,
39                 onSelectSubCategory: PropTypes.func.isRequired
40         };
41
42         onVendorParamChanged(e) {
43                 const selectedIndex = e.target.selectedIndex;
44                 const vendorId = e.target.options[selectedIndex].value;
45                 this.props.onVendorParamChanged({vendorId}, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS);
46
47         }
48
49         onSelectSubCategory(e) {
50                 const selectedIndex = e.target.selectedIndex;
51                 const subCategory = e.target.options[selectedIndex].value;
52                 this.props.onSelectSubCategory(subCategory);
53         }
54
55         render (){
56                 let {genericFieldInfo} = this.props;
57                 return (
58                         <div>
59                         {genericFieldInfo && <GridSection title={i18n('General')} className='grid-section-general'>
60                         <GridItem>
61                                 <Input
62                                         data-test-id='vsp-name'
63                                         label={i18n('Name')}
64                                         type='text'
65                                         value={this.props.name}
66                                         isRequired={true}
67                                         errorText={genericFieldInfo.name.errorText}
68                                         isValid={genericFieldInfo.name.isValid}
69                                         onChange={name => name.length <= 25 && this.props.onDataChanged({name}, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS)}/>
70                                 <Input
71                                         data-test-id='vsp-vendor-name'
72                                         label={i18n('Vendor')}
73                                         type='select'
74                                         value={this.props.vendorId}
75                                         onChange={e => this.onVendorParamChanged(e)}>
76                                         {sortByStringProperty(
77                                                 this.props.finalizedLicenseModelList,
78                                                 'name'
79                                         ).map(lm => <option key={lm.id} value={lm.id}>{lm.name}</option>)
80                                         }
81                                 </Input>
82                                 <Input
83                                         data-test-id='vsp-category-name'
84                                         label={i18n('Category')}
85                                         type='select'
86                                         value={this.props.subCategory}
87                                         onChange={e => this.onSelectSubCategory(e)}>
88                                         {
89                                                 this.props.softwareProductCategories.map(category =>
90                                                         category.subcategories &&
91                                                         <optgroup
92                                                                 key={category.name}
93                                                                 label={category.name}>{category.subcategories.map(sub =>
94                                                                 <option
95                                                                         key={sub.uniqueId}
96                                                                         value={sub.uniqueId}>{`${sub.name} (${category.name})`}</option>)}
97                                                         </optgroup>
98                                                 )
99                                         }
100                                 </Input>
101                         </GridItem>
102                         <GridItem colSpan={2} stretch>
103                                 <Input
104                                         data-test-id='vsp-description'
105                                         label={i18n('Description')}
106                                         type='textarea'
107                                         isRequired={true}
108                                         isValid={genericFieldInfo.description.isValid}
109                                         errorText={genericFieldInfo.description.errorText}
110                                         value={this.props.description}
111                                         onChange={description => this.props.onDataChanged({description}, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS)}/>
112                         </GridItem>
113                 </GridSection>}
114                 </div>);
115         }
116 }
117 class LicensesSection extends React.Component {
118         static propTypes = {
119                 onVendorParamChanged: PropTypes.func.isRequired,
120                 vendorId: PropTypes.string,
121                 licensingVersion: PropTypes.string,
122                 licensingVersionsList: PropTypes.array,
123                 licensingData: PropTypes.shape({
124                         licenceAgreement: PropTypes.string,
125                         featureGroups: PropTypes.array
126                 }),
127                 onFeatureGroupsChanged: PropTypes.func.isRequired,
128                 onLicensingDataChanged: PropTypes.func.isRequired,
129                 featureGroupsList: PropTypes.array,
130                 licenseAgreementList: PropTypes.array
131         };
132
133         onVendorParamChanged(e) {
134                 const selectedIndex = e.target.selectedIndex;
135                 const licensingVersion = e.target.options[selectedIndex].value;
136                 this.props.onVendorParamChanged({vendorId: this.props.vendorId, licensingVersion}, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS);
137         }
138
139         onLicensingDataChanged(e) {
140                 const selectedIndex = e.target.selectedIndex;
141                 const licenseAgreement = e.target.options[selectedIndex].value;
142                 this.props.onLicensingDataChanged({licenseAgreement, featureGroups: []});
143         }
144
145         render(){
146                 return (
147                         <GridSection title={i18n('Licenses')}>
148                                 <GridItem>
149                                         <Input
150                                                 data-test-id='vsp-licensing-version'
151                                                 onChange={e => this.onVendorParamChanged(e)}
152                                                 value={this.props.licensingVersion || ''}
153                                                 label={i18n('Licensing Version')}
154                                                 type='select'>
155                                                 {this.props.licensingVersionsList.map(version =>
156                                                         <option
157                                                                 key={version.enum}
158                                                                 value={version.enum}>{version.title}
159                                                         </option>
160                                                 )}
161                                         </Input>
162                                 </GridItem>
163                                 <GridItem>
164                                         <Input
165                                                 data-test-id='vsp-license-agreement'
166                                                 label={i18n('License Agreement')}
167                                                 type='select'
168                                                 value={this.props.licensingData.licenseAgreement ? this.props.licensingData.licenseAgreement : '' }
169                                                 onChange={(e) => this.onLicensingDataChanged(e)}>
170                                                 <option key='placeholder' value=''>{i18n('Select...')}</option>
171                                                 {this.props.licenseAgreementList.map(la => <option value={la.id} key={la.id}>{la.name}</option>)}
172                                         </Input>
173                                 </GridItem>
174                                 <GridItem>
175                                         {this.props.licensingData.licenseAgreement && (
176                                                 <InputOptions
177                                                         data-test-id='vsp-feature-group'
178                                                         type='select'
179                                                         isMultiSelect={true}
180                                                         onInputChange={()=>{}}
181                                                         onEnumChange={featureGroups => this.props.onFeatureGroupsChanged({featureGroups})}
182                                                         multiSelectedEnum={this.props.licensingData.featureGroups}
183                                                         name='feature-groups'
184                                                         label={i18n('Feature Groups')}
185                                                         clearable={false}
186                                                         values={this.props.featureGroupsList}/>)
187                                         }
188                                 </GridItem>
189                         </GridSection>
190                 );
191         }
192 }
193 const AvailabilitySection = (props) => (
194         <GridSection title={i18n('Availability')}>
195                 <GridItem colSpan={2}>
196                         <Input
197                                 data-test-id='vsp-use-availability-zone'
198                                 label={i18n('Use Availability Zones for High Availability')}
199                                 type='checkbox'
200                                 checked={props.dataMap['general/availability/useAvailabilityZonesForHighAvailability']}
201                                 value={props.dataMap['general/availability/useAvailabilityZonesForHighAvailability']}
202                                 onChange={(aZone) => props.onQDataChanged({'general/availability/useAvailabilityZonesForHighAvailability' : aZone})} />
203                 </GridItem>
204         </GridSection>
205 );
206 const RegionsSection = (props) => (
207         <GridSection title={i18n('Regions')}>
208                 <GridItem>
209                         <InputOptions
210                                 data-test-id='vsp-regions'
211                                 type='select'
212                                 isMultiSelect={true}
213                                 onInputChange={()=>{}}
214                                 onEnumChange={(regions) => props.onQDataChanged({'general/regionsData/regions' : regions})}
215                                 multiSelectedEnum={props.dataMap['general/regionsData/regions']}
216                                 name='vsp-regions'
217                                 clearable={false}
218                                 values={props.genericFieldInfo['general/regionsData/regions'].enum} />
219                 </GridItem>
220         </GridSection>
221 );
222 const StorageDataReplicationSection = (props) => (
223         <GridSection title={i18n('Storage Data Replication')}>
224                 <GridItem>
225                         <Input
226                                 data-test-id='vsp-storage-rep-size'
227                                 label={i18n('Storage Replication Size (GB)')}
228                                 type='number'
229                                 isValid={props.genericFieldInfo['general/storageDataReplication/storageReplicationSize'].isValid}
230                                 errorText={props.genericFieldInfo['general/storageDataReplication/storageReplicationSize'].errorText}
231                                 value={props.dataMap['general/storageDataReplication/storageReplicationSize']}
232                                 onChange={(sRep) => props.onQDataChanged({'general/storageDataReplication/storageReplicationSize' : sRep})} />
233                 </GridItem>
234                 <GridItem>
235                         <Input
236                                 data-test-id='vsp-storage-rep-source'
237                                 label={i18n('Storage Replication Source')}
238                                 type='text'
239                                 isValid={props.genericFieldInfo['general/storageDataReplication/storageReplicationSource'].isValid}
240                                 errorText={props.genericFieldInfo['general/storageDataReplication/storageReplicationSource'].errorText}
241                                 value={props.dataMap['general/storageDataReplication/storageReplicationSource']}
242                                 onChange={(sRepSource) => props.onQDataChanged({'general/storageDataReplication/storageReplicationSource' : sRepSource})} />
243                 </GridItem>
244                 <GridItem>
245                         <Input
246                                 data-test-id='vsp-storage-rep-freq'
247                                 label={i18n('Storage Replication Freq. (min)')}
248                                 type='number'
249                                 isValid={props.genericFieldInfo['general/storageDataReplication/storageReplicationFrequency'].isValid}
250                                 errorText={props.genericFieldInfo['general/storageDataReplication/storageReplicationFrequency'].errorText}
251                                 value={props.dataMap['general/storageDataReplication/storageReplicationFrequency']}
252                                 onChange={(sRepFreq) => props.onQDataChanged({'general/storageDataReplication/storageReplicationFrequency' : sRepFreq})} />
253                 </GridItem>
254                 <GridItem>
255                         <Input
256                                 data-test-id='vsp-storage-rep-dest'
257                                 label={i18n('Storage Replication Destination')}
258                                 type='text'
259                                 isValid={props.genericFieldInfo['general/storageDataReplication/storageReplicationDestination'].isValid}
260                                 errorText={props.genericFieldInfo['general/storageDataReplication/storageReplicationDestination'].errorText}
261                                 value={props.dataMap['general/storageDataReplication/storageReplicationDestination']}
262                                 onChange={(sRepDest) => props.onQDataChanged({'general/storageDataReplication/storageReplicationDestination' : sRepDest})} />
263                 </GridItem>
264         </GridSection>
265 );
266
267 class SoftwareProductDetails extends Component {
268
269         static propTypes = {
270                 vendorName: PropTypes.string,
271                 currentSoftwareProduct: PropTypes.shape({
272                         id: PropTypes.string,
273                         name: PropTypes.string,
274                         description: PropTypes.string,
275                         category: PropTypes.string,
276                         subCategory: PropTypes.string,
277                         vendorId: PropTypes.string,
278                         vendorName: PropTypes.string,
279                         licensingVersion: PropTypes.string,
280                         licensingData: PropTypes.shape({
281                                 licenceAgreement: PropTypes.string,
282                                 featureGroups: PropTypes.array
283                         })
284                 }),
285                 softwareProductCategories: PropTypes.array,
286                 finalizedLicenseModelList: PropTypes.array,
287                 licenseAgreementList: PropTypes.array,
288                 featureGroupsList: PropTypes.array,
289                 onSubmit: PropTypes.func.isRequired,
290                 onDataChanged: PropTypes.func.isRequired,
291                 onValidityChanged: PropTypes.func.isRequired,
292                 qdata: PropTypes.object.isRequired,
293                 onQDataChanged: PropTypes.func.isRequired,
294                 onVendorParamChanged: PropTypes.func.isRequired
295         };
296
297         prepareDataForGeneralSection(){
298                 let {softwareProductCategories, finalizedLicenseModelList, onDataChanged, currentSoftwareProduct, genericFieldInfo} = this.props;
299                 let {name, description, vendorId, subCategory} = currentSoftwareProduct;
300                 return {
301                         name,
302                         description,
303                         vendorId,
304                         subCategory,
305                         softwareProductCategories,
306                         finalizedLicenseModelList,
307                         onDataChanged,
308                         onVendorParamChanged: args => this.onVendorParamChanged(args),
309                         onSelectSubCategory: args => this.onSelectSubCategory(args),
310                         genericFieldInfo
311                 };
312
313         }
314
315         prepareDataForLicensesSection(){
316                 let { featureGroupsList, licenseAgreementList, currentSoftwareProduct } = this.props;
317                 let {vendorId, licensingVersion, licensingData = {}} = currentSoftwareProduct;
318                 return {
319                         onVendorParamChanged: args => this.onVendorParamChanged(args),
320                         vendorId,
321                         licensingVersion,
322                         licensingVersionsList: this.buildLicensingVersionsListItems(),
323                         licensingData,
324                         onFeatureGroupsChanged: args => this.onFeatureGroupsChanged(args),
325                         onLicensingDataChanged: args => this.onLicensingDataChanged(args),
326                         featureGroupsList,
327                         licenseAgreementList,
328                 };
329
330         }
331
332         render() {
333                 let {currentSoftwareProduct} = this.props;
334                 let {qdata, onQDataChanged, dataMap, qGenericFieldInfo} = this.props;
335                 let {isReadOnlyMode} = this.props;
336
337                 return (
338                 <div className='vsp-details-page'>
339                                 <Form
340                                         ref={(validationForm) => this.validationForm = validationForm}
341                                         className='vsp-general-tab'
342                                         hasButtons={false}
343                                         formReady={null}
344                                         isValid={this.props.isFormValid}
345                                         onSubmit={() => this.props.onSubmit(currentSoftwareProduct, qdata)}
346                                         onValidityChanged={(isValidityData) => this.props.onValidityChanged(isValidityData)}
347                                         isReadOnlyMode={isReadOnlyMode}>
348                                         <GeneralSection {...this.prepareDataForGeneralSection()}/>
349                                         <LicensesSection {...this.prepareDataForLicensesSection()}/>
350                                         <AvailabilitySection onQDataChanged={onQDataChanged} dataMap={dataMap} />
351                                         <RegionsSection onQDataChanged={onQDataChanged} dataMap={dataMap} genericFieldInfo={qGenericFieldInfo} />
352                                         <StorageDataReplicationSection onQDataChanged={onQDataChanged} dataMap={dataMap} genericFieldInfo={qGenericFieldInfo} />
353                                 </Form>
354                         </div>
355                 );
356         }
357
358         onVendorParamChanged({vendorId, licensingVersion}) {
359                 let {finalizedLicenseModelList, onVendorParamChanged} = this.props;
360                 if(!licensingVersion) {
361                         const licensingVersionsList = this.buildLicensingVersionsListItems();
362                         licensingVersion = licensingVersionsList[0].enum;
363                 }
364                 let vendorName = finalizedLicenseModelList.find(licenseModelItem => licenseModelItem.id === vendorId).name || '';
365                 let deltaData = {
366                         vendorId,
367                         vendorName,
368                         licensingVersion,
369                         licensingData: {}
370                 };
371
372                 onVendorParamChanged(deltaData, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS);
373
374         }
375
376         buildLicensingVersionsListItems() {
377                 let {licensingVersionsList} = this.props;
378
379                 let licensingVersionsListItems = [{
380                         enum: '',
381                         title: i18n('Select...')
382                 }];
383
384                 return licensingVersionsListItems.concat(licensingVersionsList.map(version => ({enum: version.id, title: version.name})));
385         }
386
387         onFeatureGroupsChanged({featureGroups}) {
388                 this.onLicensingDataChanged({featureGroups});
389         }
390
391         onLicensingDataChanged(deltaData) {
392                 this.props.onDataChanged({
393                         licensingData: {
394                                 ...this.props.currentSoftwareProduct.licensingData,
395                                 ...deltaData
396                         }
397                 }, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS);
398         }
399
400         onSelectSubCategory(subCategory) {
401                 let {softwareProductCategories, onDataChanged} = this.props;
402                 let category = SoftwareProductCategoriesHelper.getCurrentCategoryOfSubCategory(subCategory, softwareProductCategories);
403                 onDataChanged({category, subCategory}, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS);
404         }
405
406         save(){
407                 return this.validationForm.handleFormSubmit(new Event('dummy'));
408         }
409 }
410
411 export default SoftwareProductDetails;