5fbf1b74b05ddebfba350bf142c92bd3dcc80245
[sdc.git] / openecomp-ui / src / sdc-app / onboarding / softwareProduct / landingPage / SoftwareProductLandingPageView.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 classnames from 'classnames';
18 import Dropzone from 'react-dropzone';
19
20
21 import i18n from 'nfvo-utils/i18n/i18n.js';
22 import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx';
23 import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx';
24 import ListEditorItemViewField from 'nfvo-components/listEditor/ListEditorItemViewField.jsx';
25
26 import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx';
27
28 const SoftwareProductPropType = React.PropTypes.shape({
29         name: React.PropTypes.string,
30         description: React.PropTypes.string,
31         version: React.PropTypes.object,
32         id: React.PropTypes.string,
33         categoryId: React.PropTypes.string,
34         vendorId: React.PropTypes.string,
35         status: React.PropTypes.string,
36         licensingData: React.PropTypes.object,
37         validationData: React.PropTypes.object
38 });
39
40 const ComponentPropType = React.PropTypes.shape({
41         id: React.PropTypes.string,
42         name: React.PropTypes.string,
43         displayName: React.PropTypes.string,
44         description: React.PropTypes.string
45 });
46
47 class SoftwareProductLandingPageView extends React.Component {
48
49         state = {
50                 localFilter: '',
51                 fileName: '',
52                 dragging: false,
53                 files: []
54         };
55
56         static propTypes = {
57                 currentSoftwareProduct: SoftwareProductPropType,
58                 isReadOnlyMode: React.PropTypes.bool,
59                 componentsList: React.PropTypes.arrayOf(ComponentPropType),
60                 onDetailsSelect: React.PropTypes.func,
61                 onAttachmentsSelect: React.PropTypes.func,
62                 onUpload: React.PropTypes.func,
63                 onUploadConfirmation: React.PropTypes.func,
64                 onInvalidFileSizeUpload: React.PropTypes.func,
65                 onComponentSelect: React.PropTypes.func,
66                 onAddComponent: React.PropTypes.func
67         };
68
69         render() {
70                 let {currentSoftwareProduct, isReadOnlyMode, componentsList = []} =  this.props;
71                 return (
72                         <div className='software-product-landing-wrapper'>
73                                 <Dropzone
74                                         className={classnames('software-product-landing-view', {'active-dragging': this.state.dragging})}
75                                         onDrop={files => this.handleImportSubmit(files, isReadOnlyMode)}
76                                         onDragEnter={() => this.handleOnDragEnter(isReadOnlyMode)}
77                                         onDragLeave={() => this.setState({dragging:false})}
78                                         multiple={false}
79                                         disableClick={true}
80                                         ref='fileInput'
81                                         name='fileInput'
82                                         accept='.zip'
83                                         disabled>
84                                         <div className='draggable-wrapper'>
85                                                 <div className='software-product-landing-view-top'>
86                                                         <div className='row'>
87                                                                 {this.renderProductSummary(currentSoftwareProduct)}
88                                                                 {this.renderProductDetails(currentSoftwareProduct, isReadOnlyMode)}
89                                                         </div>
90                                                 </div>
91                                         </div>
92                                 </Dropzone>
93                                 {
94                                         componentsList.length > 0 && this.renderComponents()
95                                 }
96                         </div>
97                 );
98         }
99
100         handleOnDragEnter(isReadOnlyMode) {
101                 if (!isReadOnlyMode) {
102                         this.setState({dragging: true});
103                 }
104         }
105
106         renderProductSummary(currentSoftwareProduct) {
107                 let {name = '', description = '', vendorName = '', fullCategoryDisplayName = '', licenseAgreementName = ''}  = currentSoftwareProduct;
108                 let {onDetailsSelect} = this.props;
109                 return (
110                         <div className='details-panel'>
111                                 <div className='software-product-landing-view-heading-title'>{i18n('Software Product Details')}</div>
112                                 <div
113                                         className='software-product-landing-view-top-block clickable'
114                                         onClick={() => onDetailsSelect(currentSoftwareProduct)}>
115                                         <div className='details-container'>
116                                                 <div className='single-detail-section title-section'>
117                                                         <div className='single-detail-section title-text'>
118                                                                 {name}
119                                                         </div>
120                                                 </div>
121                                                 <div className='details-section'>
122                                                         <div className='multiple-details-section'>
123                                                                 <div className='detail-col' >
124                                                                         <div className='title'>{i18n('Vendor')}</div>
125                                                                         <div className='description'>{vendorName}</div>
126                                                                 </div>
127                                                                 <div className='detail-col'>
128                                                                         <div className='title'>{i18n('Category')}</div>
129                                                                         <div className='description'>{fullCategoryDisplayName}</div>
130                                                                 </div>
131                                                                 <div className='detail-col'>
132                                                                         <div className='title extra-large'>{i18n('License Agreement')}</div>
133                                                                         <div className='description'>
134                                                                                 {this.renderLicenseAgreement(licenseAgreementName)}
135                                                                         </div>
136                                                                 </div>
137                                                         </div>
138                                                         <div className='single-detail-section'>
139                                                                 <div className='title'>{i18n('Description')}</div>
140                                                                 <div className='description'>{description}</div>
141                                                         </div>
142                                                 </div>
143                                         </div>
144                                 </div>
145                         </div>
146                 );
147         }
148
149         renderProductDetails(currentSoftwareProduct, isReadOnlyMode) {
150                 let {validationData} = currentSoftwareProduct;
151                 let {onAttachmentsSelect} = this.props;
152                 let details = {
153                         heatTemplates: validationData ? '1' : '0',
154                         images: '0',
155                         otherArtifacts: '0'
156                 };
157
158                 return (
159                         <div className='details-panel'>
160                                 <div className='software-product-landing-view-heading-title'>{i18n('Software Product Attachments')}</div>
161                                 <div className='software-product-landing-view-top-block'>
162                                         <div
163                                                 className='software-product-landing-view-top-block-col'
164                                                 onClick={() => onAttachmentsSelect(currentSoftwareProduct)}>
165                                                 <div>
166                                                         <div className='attachment-details'>{i18n('HEAT Templates')} (<span
167                                                                 className='attachment-details-count'>{details.heatTemplates}</span>)
168                                                         </div>
169                                                 </div>
170                                         </div>
171                                         <div
172                                                 className={classnames('software-product-landing-view-top-block-col-upl', {'disabled': isReadOnlyMode})}>
173                                                 <div className='drag-text'>{i18n('Drag & drop for upload')}</div>
174                                                 <div className='or-text'>{i18n('or')}</div>
175                                                 <div data-test-id='upload-btn' className='upload-btn primary-btn' onClick={() => this.refs.fileInput.open()}>
176                                                         <span className='primary-btn-text'>{i18n('Select file')}</span>
177                                                 </div>
178                                         </div>
179                                 </div>
180                         </div>
181                 );
182         }
183
184         renderComponents() {
185                 const {localFilter} = this.state;
186
187                 return (
188                         <ListEditorView
189                                 title={i18n('Virtual Function Components')}
190                                 filterValue={localFilter}
191                                 placeholder={i18n('Filter Components')}
192                                 onFilter={value => this.setState({localFilter: value})}
193                                 twoColumns>
194                                 {this.filterList().map(component => this.renderComponentsListItem(component))}
195                         </ListEditorView>
196                 );
197         }
198
199         renderComponentsListItem(component) {
200                 let {id: componentId, name, displayName, description = ''} = component;
201                 let {currentSoftwareProduct: {id}, onComponentSelect} = this.props;
202                 return (
203                         <ListEditorItemView
204                                 key={name + Math.floor(Math.random() * (100 - 1) + 1).toString()}
205                                 className='list-editor-item-view'
206                                 onSelect={() => onComponentSelect({id, componentId})}>
207                                 <ListEditorItemViewField>
208                                         <div className='name'>{displayName}</div>
209                                 </ListEditorItemViewField>
210                                 <ListEditorItemViewField>
211                                         <div className='description'>{description}</div>
212                                 </ListEditorItemViewField>
213                         </ListEditorItemView>
214                 );
215         }
216
217         renderLicenseAgreement(licenseAgreementName) {
218                 if (licenseAgreementName !== null && !licenseAgreementName) {
219                         return (<div className='missing-license'><SVGIcon name='exclamation-triangle-full'/><div className='warning-text'>{i18n('Missing')}</div></div>);
220                 }
221                 return (licenseAgreementName);
222         }
223
224
225         filterList() {
226                 let {componentsList = []} = this.props;
227
228                 let {localFilter} = this.state;
229                 if (localFilter.trim()) {
230                         const filter = new RegExp(escape(localFilter), 'i');
231                         return componentsList.filter(({displayName = '', description = ''}) => {
232                                 return escape(displayName).match(filter) || escape(description).match(filter);
233                         });
234                 }
235                 else {
236                         return componentsList;
237                 }
238         }
239
240         handleImportSubmit(files, isReadOnlyMode) {
241                 if (isReadOnlyMode) {
242                         return;
243                 }
244                 if (files[0] && files[0].size) {
245                         this.setState({
246                                 fileName: files[0].name,
247                                 dragging: false,
248                                 complete: '0',
249                         });
250                         this.startUploading(files);
251                 }
252                 else {
253                         this.setState({
254                                 dragging: false
255                         });
256                         this.props.onInvalidFileSizeUpload();
257                 }
258
259         }
260
261         startUploading(files) {
262                 let {onUpload, currentSoftwareProduct, onUploadConfirmation} = this.props;
263
264                 let {validationData} = currentSoftwareProduct;
265
266                 if (!(files && files.length)) {
267                         return;
268                 }
269                 let file = files[0];
270                 let formData = new FormData();
271                 formData.append('upload', file);
272                 this.refs.fileInput.value = '';
273
274                 if (validationData) {
275                         onUploadConfirmation(currentSoftwareProduct.id, formData);
276                 }else {
277                         onUpload(currentSoftwareProduct.id, formData);
278                 }
279
280         }
281 }
282
283 export default SoftwareProductLandingPageView;