Specify a model while creating a VSP
[sdc.git] / openecomp-ui / src / sdc-app / onboarding / softwareProduct / creation / SoftwareProductCreationView.jsx
1 /*!
2  * Copyright © 2016-2018 European Support Limited
3  * Modifications Copyright (C) 2021 Nordix Foundation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14  * or implied. See the License for the specific language governing
15  * permissions and limitations under the License.
16  */
17 import React from 'react';
18 import PropTypes, { string } from 'prop-types';
19 import i18n from 'nfvo-utils/i18n/i18n.js';
20 import Validator from 'nfvo-utils/Validator.js';
21 import Input from 'nfvo-components/input/validation/Input.jsx';
22 import Form from 'nfvo-components/input/validation/Form.jsx';
23 import GridSection from 'nfvo-components/grid/GridSection.jsx';
24 import GridItem from 'nfvo-components/grid/GridItem.jsx';
25
26 import { SP_CREATION_FORM_NAME } from './SoftwareProductCreationConstants.js';
27 import sortByStringProperty from 'nfvo-utils/sortByStringProperty.js';
28
29 import SoftwareProductCategoriesHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductCategoriesHelper.js';
30 import {
31     ModelOption,
32     onboardingMethod as onboardingMethodConst
33 } from '../SoftwareProductConstants.js';
34 import SelectInput from 'nfvo-components/input/SelectInput.jsx';
35
36 const SoftwareProductPropType = PropTypes.shape({
37     id: PropTypes.string,
38     name: PropTypes.string,
39     description: PropTypes.string,
40     category: PropTypes.string,
41     subCategory: PropTypes.string,
42     vendorId: PropTypes.string,
43     selectedModelList: PropTypes.arrayOf(string)
44 });
45
46 class SoftwareProductCreationView extends React.Component {
47     static propTypes = {
48         data: SoftwareProductPropType,
49         finalizedLicenseModelList: PropTypes.array,
50         softwareProductCategories: PropTypes.array,
51         VSPNames: PropTypes.object,
52         usersList: PropTypes.array,
53         modelList: PropTypes.array,
54         onDataChanged: PropTypes.func.isRequired,
55         onSubmit: PropTypes.func.isRequired,
56         onCancel: PropTypes.func.isRequired
57     };
58
59     render() {
60         let {
61             softwareProductCategories,
62             data = {},
63             onDataChanged,
64             onCancel,
65             genericFieldInfo,
66             disableVendor,
67             modelList
68         } = this.props;
69         let {
70             name,
71             description,
72             vendorId,
73             subCategory,
74             onboardingMethod,
75             modelOption,
76             selectedModelList
77         } = data;
78
79         const vendorList = this.getVendorList();
80         return (
81             <div className="software-product-creation-page">
82                 {genericFieldInfo && (
83                     <Form
84                         ref={validationForm =>
85                             (this.validationForm = validationForm)
86                         }
87                         hasButtons={true}
88                         onSubmit={() => this.submit()}
89                         onReset={() => onCancel()}
90                         labledButtons={true}
91                         isValid={this.props.isFormValid}
92                         submitButtonText={i18n('Create')}
93                         formReady={this.props.formReady}
94                         btnClassName="sdc-modal__footer"
95                         onValidateForm={() => this.validate()}>
96                         <GridSection hasLastColSet>
97                             <GridItem colSpan="2">
98                                 <Input
99                                     value={name}
100                                     label={i18n('Name')}
101                                     isRequired={true}
102                                     onChange={name =>
103                                         onDataChanged(
104                                             { name },
105                                             SP_CREATION_FORM_NAME
106                                         )
107                                     }
108                                     onBlur={this.validateIsNameUnique}
109                                     isValid={genericFieldInfo.name.isValid}
110                                     errorText={genericFieldInfo.name.errorText}
111                                     type="text"
112                                     className="field-section"
113                                     data-test-id="new-vsp-name"
114                                 />
115                                 <Input
116                                     label={i18n('Vendor')}
117                                     type="select"
118                                     value={vendorId}
119                                     overlayPos="bottom"
120                                     isRequired={true}
121                                     disabled={disableVendor}
122                                     onChange={e => this.onSelectVendor(e)}
123                                     isValid={genericFieldInfo.vendorId.isValid}
124                                     errorText={
125                                         genericFieldInfo.vendorId.errorText
126                                     }
127                                     className="input-options-select"
128                                     groupClassName="bootstrap-input-options"
129                                     data-test-id="new-vsp-vendor">
130                                     {vendorList.map(vendor => (
131                                         <option
132                                             key={vendor.title}
133                                             value={vendor.enum}>
134                                             {vendor.title}
135                                         </option>
136                                     ))}
137                                 </Input>
138                                 <Input
139                                     label={i18n('Category')}
140                                     type="select"
141                                     value={subCategory}
142                                     isRequired={true}
143                                     onChange={e => this.onSelectSubCategory(e)}
144                                     isValid={
145                                         genericFieldInfo.subCategory.isValid
146                                     }
147                                     errorText={
148                                         genericFieldInfo.subCategory.errorText
149                                     }
150                                     className="input-options-select"
151                                     groupClassName="bootstrap-input-options"
152                                     data-test-id="new-vsp-category">
153                                     <option key="" value="">
154                                         {i18n('please select…')}
155                                     </option>
156                                     {softwareProductCategories.map(
157                                         category =>
158                                             category.subcategories && (
159                                                 <optgroup
160                                                     key={category.name}
161                                                     label={category.name}>
162                                                     {category.subcategories.map(
163                                                         sub => (
164                                                             <option
165                                                                 key={
166                                                                     sub.uniqueId
167                                                                 }
168                                                                 value={
169                                                                     sub.uniqueId
170                                                                 }>{`${
171                                                                 sub.name
172                                                             } (${
173                                                                 category.name
174                                                             })`}</option>
175                                                         )
176                                                     )}
177                                                 </optgroup>
178                                             )
179                                     )}
180                                 </Input>
181                             </GridItem>
182                             <GridItem colSpan="2" stretch lastColInRow>
183                                 <Input
184                                     value={description}
185                                     label={i18n('Description')}
186                                     isRequired={true}
187                                     overlayPos="bottom"
188                                     onChange={description =>
189                                         onDataChanged(
190                                             { description },
191                                             SP_CREATION_FORM_NAME
192                                         )
193                                     }
194                                     isValid={
195                                         genericFieldInfo.description.isValid
196                                     }
197                                     errorText={
198                                         genericFieldInfo.description.errorText
199                                     }
200                                     type="textarea"
201                                     className="field-section"
202                                     data-test-id="new-vsp-description"
203                                 />
204                             </GridItem>
205                         </GridSection>
206                         <GridSection>
207                             <GridItem colSpan={2}>
208                                 <OnboardingProcedure
209                                     genericFieldInfo={genericFieldInfo}
210                                     onboardingMethod={onboardingMethod}
211                                     onDataChanged={onDataChanged}
212                                 />
213                             </GridItem>
214                             <GridItem colSpan={2}>
215                                 <ModelSelection
216                                     genericFieldInfo={genericFieldInfo}
217                                     modelOption={modelOption}
218                                     modelList={modelList}
219                                     selectedModelList={selectedModelList}
220                                     onDataChanged={onDataChanged}
221                                 />
222                             </GridItem>
223                         </GridSection>
224                     </Form>
225                 )}
226             </div>
227         );
228     }
229
230     getVendorList() {
231         let { vendorList } = this.props;
232
233         return [{ enum: '', title: i18n('please select...') }].concat(
234             sortByStringProperty(vendorList, 'name').map(vendor => {
235                 return {
236                     enum: vendor.id,
237                     title: vendor.name
238                 };
239             })
240         );
241     }
242
243     onSelectVendor(e) {
244         const selectedIndex = e.target.selectedIndex;
245         const vendorId = e.target.options[selectedIndex].value;
246         this.props.onDataChanged({ vendorId }, SP_CREATION_FORM_NAME);
247     }
248
249     onSelectSubCategory(e) {
250         const selectedIndex = e.target.selectedIndex;
251         const subCategory = e.target.options[selectedIndex].value;
252         let { softwareProductCategories, onDataChanged } = this.props;
253         let category = SoftwareProductCategoriesHelper.getCurrentCategoryOfSubCategory(
254             subCategory,
255             softwareProductCategories
256         );
257         onDataChanged({ category, subCategory }, SP_CREATION_FORM_NAME);
258     }
259
260     submit() {
261         let { finalizedLicenseModelList, usersList } = this.props;
262         const softwareProduct = { ...this.props.data };
263         softwareProduct.vendorName = finalizedLicenseModelList.find(
264             vendor => vendor.id === softwareProduct.vendorId
265         ).name;
266         delete softwareProduct.modelOption;
267         this.props.onSubmit(softwareProduct, usersList);
268     }
269
270     validateName(value) {
271         const { data: { id }, VSPNames } = this.props;
272         const isExists = Validator.isItemNameAlreadyExistsInList({
273             itemId: id,
274             itemName: value,
275             list: VSPNames
276         });
277
278         return !isExists
279             ? { isValid: true, errorText: '' }
280             : {
281                   isValid: false,
282                   errorText: i18n(
283                       "Software product by the name '" +
284                           value +
285                           "' already exists. Software product name must be unique"
286                   )
287               };
288     }
289
290     validateIsNameUnique = e => {
291         const value = e.target.value;
292         if (value) {
293             this.props.isNameUnique(value, 'name', SP_CREATION_FORM_NAME);
294         }
295     };
296
297     validate() {
298         this.props.onValidateForm(SP_CREATION_FORM_NAME);
299     }
300 }
301
302 const OnboardingProcedure = ({
303     onboardingMethod,
304     onDataChanged,
305     genericFieldInfo
306 }) => {
307     return (
308         <GridSection title={i18n('Onboarding procedure')} required={true}>
309             <GridItem colSpan={4}>
310                 <Input
311                     label={i18n('Network Package')}
312                     overlayPos="top"
313                     checked={
314                         onboardingMethod ===
315                         onboardingMethodConst.NETWORK_PACKAGE
316                     }
317                     errorText={genericFieldInfo.onboardingMethod.errorText}
318                     onChange={() =>
319                         onDataChanged(
320                             {
321                                 onboardingMethod:
322                                     onboardingMethodConst.NETWORK_PACKAGE
323                             },
324                             SP_CREATION_FORM_NAME
325                         )
326                     }
327                     type="radio"
328                     data-test-id="new-vsp-creation-procedure-heat"
329                 />
330             </GridItem>
331             <GridItem colSpan={4}>
332                 <Input
333                     label={i18n('Manual')}
334                     overlayPos="bottom"
335                     checked={onboardingMethod === onboardingMethodConst.MANUAL}
336                     isValid={genericFieldInfo.onboardingMethod.isValid}
337                     errorText={genericFieldInfo.onboardingMethod.errorText}
338                     onChange={() =>
339                         onDataChanged(
340                             { onboardingMethod: onboardingMethodConst.MANUAL },
341                             SP_CREATION_FORM_NAME
342                         )
343                     }
344                     type="radio"
345                     data-test-id="new-vsp-creation-procedure-manual"
346                     groupClassName="no-bottom-margin"
347                 />
348             </GridItem>
349         </GridSection>
350     );
351 };
352
353 const ModelSelection = ({
354     modelOption,
355     onDataChanged,
356     genericFieldInfo,
357     modelList = [],
358     selectedModelList = []
359 }) => {
360     function onSelectChanged(selectedValueList) {
361         let modelList1 = [];
362         if (selectedValueList) {
363             modelList1 = selectedValueList.map(item => item.value);
364         }
365         onDataChanged({ selectedModelList: modelList1 }, SP_CREATION_FORM_NAME);
366     }
367
368     function selectDefaultModel() {
369         return () => {
370             onDataChanged(
371                 { modelOption: ModelOption.DEFAULT },
372                 SP_CREATION_FORM_NAME
373             );
374             onDataChanged({ selectedModelList: [] }, SP_CREATION_FORM_NAME);
375         };
376     }
377
378     return (
379         <GridSection title={i18n('Model')} required={true}>
380             <GridItem colSpan={4}>
381                 <Input
382                     label={i18n('model.sdc.label')}
383                     checked={modelOption === ModelOption.DEFAULT}
384                     errorText={genericFieldInfo.modelOption.errorText}
385                     onChange={selectDefaultModel()}
386                     type="radio"
387                     data-test-id="model-option-default"
388                 />
389                 <Input
390                     label={i18n('vsp.model.select.label')}
391                     checked={modelOption === ModelOption.SELECTED}
392                     isValid={genericFieldInfo.modelOption.isValid}
393                     errorText={genericFieldInfo.modelOption.errorText}
394                     onChange={() =>
395                         onDataChanged(
396                             { modelOption: ModelOption.SELECTED },
397                             SP_CREATION_FORM_NAME
398                         )
399                     }
400                     type="radio"
401                     data-test-id="model-option-selected"
402                     groupClassName="no-bottom-margin"
403                 />
404             </GridItem>
405             <GridItem colSpan={4}>
406                 {modelOption === ModelOption.SELECTED && <br />}
407                 {modelOption === ModelOption.SELECTED && (
408                     <SelectInput
409                         options={modelList.map(model => ({
410                             label: model.name,
411                             value: model.name
412                         }))}
413                         onMultiSelectChanged={onSelectChanged}
414                         value={selectedModelList}
415                         clearable={true}
416                         placeholder={i18n('vsp.model.select.label')}
417                         multi
418                     />
419                 )}
420                 {modelOption === ModelOption.SELECTED && <br />}
421             </GridItem>
422         </GridSection>
423     );
424 };
425
426 export default SoftwareProductCreationView;