summaryrefslogtreecommitdiffstats
path: root/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage
diff options
context:
space:
mode:
Diffstat (limited to 'openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage')
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js97
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageUploadConfirmationModal.jsx38
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx272
3 files changed, 407 insertions, 0 deletions
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js
new file mode 100644
index 0000000000..7604f5841d
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js
@@ -0,0 +1,97 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+import {connect} from 'react-redux';
+
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js';
+import NotificationConstants from 'nfvo-components/notifications/NotificationConstants.js';
+import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js';
+import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js';
+import LandingPageView from './SoftwareProductLandingPageView.jsx';
+
+const mapStateToProps = ({softwareProduct, licenseModel: {licenseAgreement}}) => {
+ let {softwareProductEditor: {data:currentSoftwareProduct = {}}, softwareProductComponents, softwareProductCategories = []} = softwareProduct;
+ let {licensingData = {}} = currentSoftwareProduct;
+ let {licenseAgreementList} = licenseAgreement;
+ let {componentsList} = softwareProductComponents;
+ let licenseAgreementName = licenseAgreementList.find(la => la.id === licensingData.licenseAgreement);
+ if (licenseAgreementName) {
+ licenseAgreementName = licenseAgreementName.name;
+ }
+
+ let categoryName = '', subCategoryName = '', fullCategoryDisplayName = '';
+ const category = softwareProductCategories.find(ca => ca.uniqueId === currentSoftwareProduct.category);
+ if (category) {
+ categoryName = category.name;
+ const subcategories = category.subcategories || [];
+ const subcat = subcategories.find(sc => sc.uniqueId === currentSoftwareProduct.subCategory);
+ subCategoryName = subcat && subcat.name ? subcat.name : '';
+ }
+ fullCategoryDisplayName = `${subCategoryName} (${categoryName})`;
+
+ const isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct);
+
+ return {
+ currentSoftwareProduct: {
+ ...currentSoftwareProduct,
+ licenseAgreementName,
+ fullCategoryDisplayName
+ },
+ isReadOnlyMode,
+ componentsList
+ };
+};
+
+const mapActionsToProps = (dispatch, {version}) => {
+ return {
+ onDetailsSelect: ({id: softwareProductId, vendorId: licenseModelId}) => OnboardingActionHelper.navigateToSoftwareProductDetails(dispatch, {
+ softwareProductId,
+ licenseModelId
+ }),
+ onAttachmentsSelect: ({id: softwareProductId}) => OnboardingActionHelper.navigateToSoftwareProductAttachments(dispatch, {softwareProductId}),
+ onUpload: (softwareProductId, formData) =>
+ SoftwareProductActionHelper.uploadFile(dispatch, {
+ softwareProductId,
+ formData,
+ failedNotificationTitle: i18n('Upload validation failed')
+ }),
+ onUploadConfirmation: (softwareProductId, formData) =>
+ SoftwareProductActionHelper.uploadConfirmation(dispatch, {
+ softwareProductId,
+ formData,
+ failedNotificationTitle: i18n('Upload validation failed')}),
+
+ onInvalidFileSizeUpload: () => dispatch({
+ type: NotificationConstants.NOTIFY_ERROR,
+ data: {
+ title: i18n('Upload Failed'),
+ msg: i18n('no zip file was uploaded or zip file doesn\'t exist')
+ }
+ }),
+ onComponentSelect: ({id: softwareProductId, componentId}) => {
+ OnboardingActionHelper.navigateToSoftwareProductComponentGeneralAndUpdateLeftPanel(dispatch, {softwareProductId, componentId, version });
+ },
+ /** for the next version */
+ onAddComponent: () => SoftwareProductActionHelper.addComponent(dispatch)
+ };
+};
+
+export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(LandingPageView);
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageUploadConfirmationModal.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageUploadConfirmationModal.jsx
new file mode 100644
index 0000000000..4a848834b2
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageUploadConfirmationModal.jsx
@@ -0,0 +1,38 @@
+import {connect} from 'react-redux';
+import ConfirmationModalView from 'nfvo-components/confirmations/ConfirmationModalView.jsx';
+import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js';
+
+import i18n from 'nfvo-utils/i18n/i18n.js';
+
+const mapStateToProps = ({softwareProduct}) => {
+ let {softwareProductEditor} = softwareProduct;
+ let {uploadData} = softwareProductEditor;
+ const show = uploadData ? true : false;
+ return {
+ show,
+ title: 'Warning!',
+ type: 'warning',
+ msg: i18n('Upload will erase existing data. Do you want to continue?'),
+ confirmationDetails: {uploadData}
+ };
+};
+
+const mapActionsToProps = (dispatch) => {
+ return {
+ onConfirmed: ({uploadData}) => {
+ let {softwareProductId, formData, failedNotificationTitle} = uploadData;
+ SoftwareProductActionHelper.uploadFile(dispatch, {
+ softwareProductId,
+ formData,
+ failedNotificationTitle
+ });
+ SoftwareProductActionHelper.hideUploadConfirm(dispatch);
+ },
+ onDeclined: () => {
+ SoftwareProductActionHelper.hideUploadConfirm(dispatch);
+ }
+ };
+};
+
+export default connect(mapStateToProps, mapActionsToProps)(ConfirmationModalView);
+
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx
new file mode 100644
index 0000000000..cf7c7a31a5
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx
@@ -0,0 +1,272 @@
+import React from 'react';
+import classnames from 'classnames';
+import Dropzone from 'react-dropzone';
+
+
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx';
+import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx';
+
+import FontAwesome from 'react-fontawesome';
+import SoftwareProductLandingPageUploadConfirmationModal from './SoftwareProductLandingPageUploadConfirmationModal.jsx';
+
+
+const SoftwareProductPropType = React.PropTypes.shape({
+ name: React.PropTypes.string,
+ description: React.PropTypes.string,
+ version: React.PropTypes.string,
+ id: React.PropTypes.string,
+ categoryId: React.PropTypes.string,
+ vendorId: React.PropTypes.string,
+ status: React.PropTypes.string,
+ licensingData: React.PropTypes.object,
+ validationData: React.PropTypes.object
+});
+
+const ComponentPropType = React.PropTypes.shape({
+ id: React.PropTypes.string,
+ name: React.PropTypes.string,
+ displayName: React.PropTypes.string,
+ description: React.PropTypes.string
+});
+
+class SoftwareProductLandingPageView extends React.Component {
+
+ state = {
+ localFilter: '',
+ fileName: '',
+ dragging: false,
+ files: []
+ };
+
+ static propTypes = {
+ currentSoftwareProduct: SoftwareProductPropType,
+ isReadOnlyMode: React.PropTypes.bool,
+ componentsList: React.PropTypes.arrayOf(ComponentPropType),
+ onDetailsSelect: React.PropTypes.func,
+ onAttachmentsSelect: React.PropTypes.func,
+ onUpload: React.PropTypes.func,
+ onUploadConfirmation: React.PropTypes.func,
+ onInvalidFileSizeUpload: React.PropTypes.func,
+ onComponentSelect: React.PropTypes.func,
+ onAddComponent: React.PropTypes.func
+ };
+
+ render() {
+ let {currentSoftwareProduct, isReadOnlyMode, componentsList = []} = this.props;
+ return (
+ <div className='software-product-landing-wrapper'>
+ <Dropzone
+ className={classnames('software-product-landing-view', {'active-dragging': this.state.dragging})}
+ onDrop={files => this.handleImportSubmit(files, isReadOnlyMode)}
+ onDragEnter={() => this.handleOnDragEnter(isReadOnlyMode)}
+ onDragLeave={() => this.setState({dragging:false})}
+ multiple={false}
+ disableClick={true}
+ ref='fileInput'
+ name='fileInput'
+ accept='.zip'
+ disabled>
+ <div className='draggable-wrapper'>
+ <div className='software-product-landing-view-top'>
+ <div className='row'>
+ {this.renderProductSummary(currentSoftwareProduct)}
+ {this.renderProductDetails(currentSoftwareProduct, isReadOnlyMode)}
+ </div>
+ </div>
+ </div>
+ </Dropzone>
+ {
+ componentsList.length > 0 && this.renderComponents()
+ }
+ <SoftwareProductLandingPageUploadConfirmationModal confirmationButtonText={i18n('Continue')}/>
+ </div>
+ );
+ }
+
+ handleOnDragEnter(isReadOnlyMode) {
+ if (!isReadOnlyMode) {
+ this.setState({dragging: true});
+ }
+ }
+
+ renderProductSummary(currentSoftwareProduct) {
+ let {name = '', description = '', vendorName = '', fullCategoryDisplayName = '', licenseAgreementName = ''} = currentSoftwareProduct;
+ let {onDetailsSelect} = this.props;
+ return (
+ <div className='details-panel'>
+ <div className='software-product-landing-view-heading-title'>{i18n('Software Product Details')}</div>
+ <div
+ className='software-product-landing-view-top-block clickable'
+ onClick={() => onDetailsSelect(currentSoftwareProduct)}>
+ <div className='details-container'>
+ <div className='single-detail-section title-section'>
+ <div>
+ <div>{name}</div>
+ </div>
+ </div>
+ <div className='multiple-details-section'>
+ <div className='detail-col' >
+ <div className='title'>{i18n('Vendor')}</div>
+ <div className='description'>{vendorName}</div>
+ </div>
+ <div className='detail-col'>
+ <div className='title'>{i18n('Category')}</div>
+ <div className='description'>{fullCategoryDisplayName}</div>
+ </div>
+ <div className='detail-col'>
+ <div className='title extra-large'>{i18n('License Agreement')}</div>
+ <div className='description'>
+ {this.renderLicenseAgreement(licenseAgreementName)}
+ </div>
+ </div>
+ </div>
+ <div className='single-detail-section'>
+ <div className='title'>{i18n('Description')}</div>
+ <div className='description'>{description}</div>
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+
+ renderProductDetails(currentSoftwareProduct, isReadOnlyMode) {
+ let {validationData} = currentSoftwareProduct;
+ let {onAttachmentsSelect} = this.props;
+ let details = {
+ heatTemplates: validationData ? '1' : '0',
+ images: '0',
+ otherArtifacts: '0'
+ };
+
+ return (
+ <div className='details-panel'>
+ <div className='software-product-landing-view-heading-title'>{i18n('Software Product Attachments')}</div>
+ <div className='software-product-landing-view-top-block'>
+ <div
+ className='software-product-landing-view-top-block-col'
+ onClick={() => onAttachmentsSelect(currentSoftwareProduct)}>
+ <div>
+ <div className='attachment-details'>{i18n('HEAT Templates')} (<span
+ className='attachment-details-count'>{details.heatTemplates}</span>)
+ </div>
+ <div className='attachment-details'>{i18n('Images')} (<span
+ className='attachment-details-count'>{details.images}</span>)
+ </div>
+ <div className='attachment-details'>{i18n('Other Artifacts')} (<span
+ className='attachment-details-count'>{details.otherArtifacts}</span>)
+ </div>
+ </div>
+ </div>
+ <div
+ className={classnames('software-product-landing-view-top-block-col-upl', {'disabled': isReadOnlyMode})}>
+ <div className='drag-text'>{i18n('Drag & drop for upload')}</div>
+ <div className='or-text'>{i18n('or')}</div>
+ <div className='upload-btn primary-btn' onClick={() => this.refs.fileInput.open()}>
+ <span className='primary-btn-text'>{i18n('Select file')}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+
+ renderComponents() {
+ const {localFilter} = this.state;
+
+ return (
+ <ListEditorView
+ title={i18n('Virtual Function Components')}
+ filterValue={localFilter}
+ placeholder={i18n('Filter Components')}
+ onFilter={filter => this.setState({localFilter: filter})}>
+ {this.filterList().map(component => this.renderComponentsListItem(component))}
+ </ListEditorView>
+ );
+ }
+
+ renderComponentsListItem(component) {
+ let {id: componentId, name, displayName, description = ''} = component;
+ let {currentSoftwareProduct: {id}, onComponentSelect} = this.props;
+ return (
+ <ListEditorItemView
+ key={name + Math.floor(Math.random() * (100 - 1) + 1).toString()}
+ className='list-editor-item-view'
+ onSelect={() => onComponentSelect({id, componentId})}>
+ <div className='list-editor-item-view-field'>
+ <div className='title'>{i18n('Component')}</div>
+ <div className='name'>{displayName}</div>
+ </div>
+ <div className='list-editor-item-view-field'>
+ <div className='title'>{i18n('Description')}</div>
+ <div className='description'>{description}</div>
+ </div>
+ </ListEditorItemView>
+ );
+ }
+
+ renderLicenseAgreement(licenseAgreementName) {
+ if (!licenseAgreementName) {
+ return (<FontAwesome name='exclamation-triangle' className='warning-icon'/>);
+ }
+ return (licenseAgreementName);
+ }
+
+
+ filterList() {
+ let {componentsList = []} = this.props;
+
+ let {localFilter} = this.state;
+ if (localFilter.trim()) {
+ const filter = new RegExp(escape(localFilter), 'i');
+ return componentsList.filter(({displayName = '', description = ''}) => {
+ return escape(displayName).match(filter) || escape(description).match(filter);
+ });
+ }
+ else {
+ return componentsList;
+ }
+ }
+
+ handleImportSubmit(files, isReadOnlyMode) {
+ if (isReadOnlyMode) {
+ return;
+ }
+ if (files[0] && files[0].size) {
+ this.setState({
+ fileName: files[0].name,
+ dragging: false,
+ complete: '0',
+ });
+ this.startUploading(files);
+ }
+ else {
+ this.props.onInvalidFileSizeUpload();
+ }
+
+ }
+
+ startUploading(files) {
+ let {onUpload, currentSoftwareProduct, onUploadConfirmation} = this.props;
+
+ let {validationData} = currentSoftwareProduct;
+
+ if (!(files && files.length)) {
+ return;
+ }
+ let file = files[0];
+ let formData = new FormData();
+ formData.append('upload', file);
+ this.refs.fileInput.value = '';
+
+ if (validationData) {
+ onUploadConfirmation(currentSoftwareProduct.id, formData);
+ }else {
+ onUpload(currentSoftwareProduct.id, formData);
+ }
+
+ }
+}
+
+export default SoftwareProductLandingPageView;