Integrate VNF Repository in Beijing release

Migrate the code

Change-Id: Ifccacf83634af32b034fd9c413e68f894f06d2f7
Issue-ID: VNFSDK-155
Signed-off-by: Murali-P <murali.p@huawei.com>
diff --git a/openecomp-ui/resources/scss/_components.scss b/openecomp-ui/resources/scss/_components.scss
index e18b260..7bd9010 100644
--- a/openecomp-ui/resources/scss/_components.scss
+++ b/openecomp-ui/resources/scss/_components.scss
@@ -22,6 +22,7 @@
 @import "components/userNotifications";
 @import "components/overlay";
 @import "components/vspDetailsVendorSelect";
+@import "components/vnfBrowse";
 
 %noselect {
   -webkit-touch-callout: none;
diff --git a/openecomp-ui/resources/scss/components/_vnfBrowse.scss b/openecomp-ui/resources/scss/components/_vnfBrowse.scss
new file mode 100644
index 0000000..7e0085a
--- /dev/null
+++ b/openecomp-ui/resources/scss/components/_vnfBrowse.scss
@@ -0,0 +1,109 @@
+$message-info-icon-size: 16px;
+
+.vnf-creation-page {
+	.list-editor-view-header {
+		border-bottom: none;
+	}
+	.vnfBrowse-list-item {
+		display: flex;
+		height: 36px;
+		@extend .body-1;
+		&.header {
+			@extend .body-1-semibold;
+			background-color: $tlv-light-gray;
+			color: $text-black;
+		}
+		&.selectedRow {
+			background-color: $blue;
+			color: $white;
+			.svg-icon-wrapper {
+				&.__positive {
+					fill: $white;
+					color: $white;
+				}
+			}
+		}
+		.svg-icon-wrapper {
+			&.__positive {
+				fill: $dark-gray;
+				color: $dark-gray;
+			}
+		}
+	}
+
+  	.activity-action {
+		.svg-icon-wrapper {
+			float: left;
+		}
+  	}
+
+	.message-further-info-icon {
+		background-color: $gray;
+	}
+
+	.table-cell {
+	border-right: 1px solid $light-gray;
+	border-bottom: 1px solid $light-gray;
+	&:last-child {
+  		border-right: none;
+	}
+	flex-basis: 22%;
+	display: flex;
+	padding: 0 20px;
+	justify-content: center;
+	flex-direction: column;
+
+	&.vnftable-action {
+		flex-basis: 12%;
+		span {
+			margin: auto;
+		}
+	}
+}
+
+  .vnf-table-header {
+	cursor: pointer;
+	display: flex;
+	align-items: center;
+	.header-sort-arrow {
+	  width: 0;
+	  height: 0;
+	  border-left: 5px solid transparent;
+	  border-right: 5px solid transparent;
+	  margin-left: 9px;
+	  &.up {
+		border-bottom: 5px solid $black;
+	  }
+	  &.down {
+		border-top: 5px solid $black;
+	  }
+
+	}
+  }
+
+  .vnf-table-cell {
+	display: flex;
+	justify-content: space-between;
+	span {
+		overflow: hidden;
+		text-overflow: ellipsis;
+	}
+  } 
+  .vnftable-name {
+  	max-width: 22%;
+  }
+
+  .vnf-grid-section {
+  	margin: 20px 20px 20px 50px;
+  }
+
+  .vnf-modal {
+  	text-align: right;
+  	margin-top: 22px;
+  }
+ 
+  .vnf-submit {
+  	margin-right: 15px;
+  }
+
+}
\ No newline at end of file
diff --git a/openecomp-ui/resources/scss/modules/_softwareProductLandingPage.scss b/openecomp-ui/resources/scss/modules/_softwareProductLandingPage.scss
index 99027d6..8d124c3 100644
--- a/openecomp-ui/resources/scss/modules/_softwareProductLandingPage.scss
+++ b/openecomp-ui/resources/scss/modules/_softwareProductLandingPage.scss
@@ -160,12 +160,65 @@
               color: $light-blue;
             }
           }
+        }
 
         .software-product-landing-view-top-block-col-upl {
           @extend .flex;
+          height: 215px;
+          text-align: center;
+          flex-direction: column;
+          justify-content: center;
+          border: 2px dashed $light-gray;
           margin-bottom: 20px;
+          @extend .body-1;
+          align-items: center;
+          .upload-btn {
+            padding: 15px 55px;
 
           }
+          .drag-text {
+            color: $blue;
+            @extend .body-1-semibold;
+          }
+          .or-text {
+            margin-top: 10px;
+            margin-bottom: 10px;
+            color: $light-gray;
+          }
+          .upload {
+            width: 50%;
+            border : 0px !important;
+          }
+          .vnfRepo {
+            width: 50%;
+            cursor: pointer;
+            .searchRepo-text {
+              color: $blue;
+              @extend .body-1-semibold;
+              width: 72px;
+              line-height: 24px;
+              margin-left: auto;
+              margin-right: auto;
+            }
+            .svg-icon-wrapper {
+              .svg-icon.__search {
+                width: 34px;
+                height: 34px;
+                margin-top: 10px;
+              }
+              &.__positive {
+                fill: $blue;
+                color: $blue;
+              }
+            }
+          }
+          .verticalLine {
+            height: 90%;
+            border-left: 1px solid $light-gray;
+          }
+        }
+        .showVnf {
+          flex-direction: row;
         }
       }
     }
diff --git a/openecomp-ui/src/nfvo-components/vnfMarketPlace/VnfRepositorySearchBox.jsx b/openecomp-ui/src/nfvo-components/vnfMarketPlace/VnfRepositorySearchBox.jsx
new file mode 100644
index 0000000..ab8a18b
--- /dev/null
+++ b/openecomp-ui/src/nfvo-components/vnfMarketPlace/VnfRepositorySearchBox.jsx
@@ -0,0 +1,73 @@
+/*!
+ * 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.
+ */
+
+import React, { Component } from 'react';
+import DraggableUploadFileBox from 'nfvo-components/fileupload/DraggableUploadFileBox.jsx';
+import Configuration from 'sdc-app/config/Configuration.js';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
+
+function VNFBrowse({ onBrowseVNF, isReadOnlyMode }) {
+    if (!Configuration.get('showBrowseVNF')) {
+        return <div />;
+    } else {
+        return (
+            <div
+                className={`${'vnfRepo'}${isReadOnlyMode ? ' disabled' : ''}`}
+                onClick={onBrowseVNF}>
+                <div className={`${'searchRepo-text'}`}>
+                    {i18n('Search in Repository')}
+                </div>
+                <SVGIcon
+                    name="search"
+                    color="positive"
+                    iconClassName="searchIcon"
+                />
+            </div>
+        );
+    }
+}
+
+class VnfRepositorySearchBox extends Component {
+    render() {
+        let {
+            className,
+            onClick,
+            onBrowseVNF,
+            dataTestId,
+            isReadOnlyMode
+        } = this.props;
+        let showVNF = Configuration.get('showBrowseVNF');
+        return (
+            <div className={`${className}${isReadOnlyMode ? ' disabled' : ''}`}>
+                <DraggableUploadFileBox
+                    dataTestId={dataTestId}
+                    isReadOnlyMode={isReadOnlyMode}
+                    className={'upload'}
+                    onClick={onClick}
+                />
+
+                <div className={`${'verticalLine'}${showVNF ? '' : ' hide'}`} />
+
+                <VNFBrowse
+                    onBrowseVNF={onBrowseVNF}
+                    isReadOnlyMode={isReadOnlyMode}
+                />
+            </div>
+        );
+    }
+}
+export default VnfRepositorySearchBox;
diff --git a/openecomp-ui/src/nfvo-utils/RestAPIUtil.js b/openecomp-ui/src/nfvo-utils/RestAPIUtil.js
index 1a5817d..6be5db7 100644
--- a/openecomp-ui/src/nfvo-utils/RestAPIUtil.js
+++ b/openecomp-ui/src/nfvo-utils/RestAPIUtil.js
@@ -41,6 +41,9 @@
 
 function applySecurity(options, data) {
     let headers = options.headers || (options.headers = {});
+    if (options.isAnonymous) {
+        return;
+    }
 
     let authToken = localStorage.getItem(STORAGE_AUTH_KEY);
     if (authToken) {
diff --git a/openecomp-ui/src/nfvo-utils/i18n/en.json b/openecomp-ui/src/nfvo-utils/i18n/en.json
index cbc2031..10ddb42 100644
--- a/openecomp-ui/src/nfvo-utils/i18n/en.json
+++ b/openecomp-ui/src/nfvo-utils/i18n/en.json
@@ -620,5 +620,14 @@
   "VSPQuestionnaire/general/storageDataReplication/storageReplicationFrequency" : "Storage Replication Frequency",
   "VSPQuestionnaire/general/storageDataReplication/storageReplicationDestination" : "Storage Replication Destination",
 
+  "VNF List Title": "VNF List",
+  "VNF import failed title" : "VNF import failed",
+  "VNF import failed msg" : "VNF Repository Server is not responding or not reachable. Please check server address in configuration file.",
+  "VNF Header Name" : "Name",
+  "VNF Header Version" : "Version",
+  "VNF Header Vendor" : "Vendor",
+  "VNF Header Desc" : "Description",
+  "VNF Header Action" : "Action",
+  
   "GENERIC_ERROR": "An error has occurred. Please contact your System Administrator for further assistance."
 }
diff --git a/openecomp-ui/src/sdc-app/common/modal/ModalContentMapper.js b/openecomp-ui/src/sdc-app/common/modal/ModalContentMapper.js
index 5b28c5d..745f01d 100644
--- a/openecomp-ui/src/sdc-app/common/modal/ModalContentMapper.js
+++ b/openecomp-ui/src/sdc-app/common/modal/ModalContentMapper.js
@@ -24,6 +24,7 @@
 import SoftwareProductComponentsNICEditor from 'sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditor.js';
 import ComponentCreation from 'sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreation.js';
 import SoftwareProductDeploymentEditor from 'sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditor.js';
+import VNFImport from 'sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImport.js';
 import PermissionsManager from 'sdc-app/onboarding/permissions/PermissionsManager.js';
 import CommitCommentModal from 'nfvo-components/panel/versionController/components/CommitCommentModal.jsx';
 import Tree from 'nfvo-components/tree/Tree.jsx';
@@ -48,7 +49,8 @@
     VERSION_TREE: 'VERSION_TREE',
     MERGE_EDITOR: 'MERGE_EDITOR',
     REVISIONS_LIST: 'REVISIONS_LIST',
-    VENDOR_SELECTOR: 'VENDOR_SELECTOR'
+    VENDOR_SELECTOR: 'VENDOR_SELECTOR',
+    VNF_IMPORT: 'VNF_IMPORT'
 };
 
 export const modalContentComponents = {
@@ -67,5 +69,6 @@
     VERSION_TREE: Tree,
     MERGE_EDITOR: MergeEditor,
     REVISIONS_LIST: Revisions,
-    VENDOR_SELECTOR: VendorSelector
+    VENDOR_SELECTOR: VendorSelector,
+    VNF_IMPORT: VNFImport
 };
diff --git a/openecomp-ui/src/sdc-app/config/config.json b/openecomp-ui/src/sdc-app/config/config.json
index fbfaf1d..e9e0b55 100644
--- a/openecomp-ui/src/sdc-app/config/config.json
+++ b/openecomp-ui/src/sdc-app/config/config.json
@@ -7,5 +7,6 @@
 	"defaultRestCatalogPrefix": "/sdc1/feProxy/rest",
 	"defaultWebsocketPort" : "8181",
 	"defaultDebugWebsocketPort" : "9000",
-	"defaultWebsocketPath" : "notification-api/ws/notificationHandler"
+	"defaultWebsocketPath" : "notification-api/ws/notificationHandler",
+	"showBrowseVNF" : true
 }
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js
index 25bd32e..877c786 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js
@@ -81,6 +81,12 @@
     );
 }
 
+function uploadVNFFile(csarId, softwareProductId, version) {
+    let verId = typeof version === 'object' ? version.id : version;
+    return RestAPIUtil.post(
+        `${baseUrl()}${softwareProductId}/versions/${verId}/vnfrepository/vnfpackage/${csarId}/import`
+    );
+}
 function putSoftwareProduct({ softwareProduct, version }) {
     return RestAPIUtil.put(
         `${baseUrl()}${softwareProduct.id}/versions/${version.id}`,
@@ -421,6 +427,54 @@
             });
     },
 
+    uploadVNFFile(
+        dispatch,
+        { csarId, failedNotificationTitle, softwareProductId, version }
+    ) {
+        dispatch({
+            type: HeatSetupActions.FILL_HEAT_SETUP_CACHE,
+            payload: {}
+        });
+
+        Promise.resolve()
+            .then(() => uploadVNFFile(csarId, softwareProductId, version))
+            .then(response => {
+                if (response.status === 'Success') {
+                    dispatch({
+                        type: commonActionTypes.DATA_CHANGED,
+                        deltaData: {
+                            onboardingOrigin: response.onboardingOrigin
+                        },
+                        formName: forms.VENDOR_SOFTWARE_PRODUCT_DETAILS
+                    });
+                    switch (response.onboardingOrigin) {
+                        case onboardingOriginTypes.ZIP:
+                            OnboardingActionHelper.navigateToSoftwareProductAttachmentsSetupTab(
+                                dispatch,
+                                { softwareProductId, version }
+                            );
+                            break;
+                        case onboardingOriginTypes.CSAR:
+                            OnboardingActionHelper.navigateToSoftwareProductAttachmentsValidationTab(
+                                dispatch,
+                                { softwareProductId, version }
+                            );
+                            break;
+                    }
+                } else {
+                    throw new Error(parseUploadErrorMsg(response.errors));
+                }
+            })
+            .catch(error => {
+                dispatch({
+                    type: modalActionTypes.GLOBAL_MODAL_ERROR,
+                    data: {
+                        title: failedNotificationTitle,
+                        msg: error.message
+                    }
+                });
+            });
+    },
     downloadHeatFile(
         dispatch,
         { softwareProductId, heatCandidate, isReadOnlyMode, version }
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js
index f3de517..fd4f02c 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js
@@ -56,6 +56,8 @@
 import { NIC_QUESTIONNAIRE } from 'sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js';
 import { IMAGE_QUESTIONNAIRE } from 'sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageConstants.js';
 
+import VNFImportReducer from './vnfMarketPlace/VNFImportReducer.js';
+
 export default combineReducers({
     softwareProductAttachments: combineReducers({
         attachmentsDetails: SoftwareProductAttachmentsReducer,
@@ -150,5 +152,8 @@
         }
         return state;
     },
-    softwareProductQuestionnaire: createJSONSchemaReducer(PRODUCT_QUESTIONNAIRE)
+    softwareProductQuestionnaire: createJSONSchemaReducer(
+        PRODUCT_QUESTIONNAIRE
+    ),
+    VNFMarketPlaceImport: VNFImportReducer
 });
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js
index 34bfcee..f5f3b7e 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js
@@ -21,6 +21,7 @@
 import { onboardingMethod } from '../SoftwareProductConstants.js';
 import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js';
 import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js';
+import VNFImportActionHelper from '../vnfMarketPlace/VNFImportActionHelper.js';
 
 export const mapStateToProps = ({
     softwareProduct,
@@ -137,7 +138,12 @@
                 props: { softwareProductId, version, componentId }
             }),
         /** for the next version */
-        onAddComponent: () => SoftwareProductActionHelper.addComponent(dispatch)
+        onAddComponent: () =>
+            SoftwareProductActionHelper.addComponent(dispatch),
+
+        onBrowseVNF: currentSoftwareProduct => {
+            VNFImportActionHelper.open(dispatch, currentSoftwareProduct);
+        }
     };
 };
 
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx
index bc8a2be..00f0c2a 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx
@@ -19,7 +19,9 @@
 import Dropzone from 'react-dropzone';
 
 import i18n from 'nfvo-utils/i18n/i18n.js';
+import Configuration from 'sdc-app/config/Configuration.js';
 import DraggableUploadFileBox from 'nfvo-components/fileupload/DraggableUploadFileBox.jsx';
+import VnfRepositorySearchBox from 'nfvo-components/vnfMarketPlace/VnfRepositorySearchBox.jsx';
 
 import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
 import SoftwareProductComponentsList from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponents.js';
@@ -122,26 +124,55 @@
     }
 
     renderProductDetails(isManual, isReadOnlyMode) {
-        return (
-            <div className="details-panel">
-                {!isManual && (
-                    <div>
-                        <div className="software-product-landing-view-heading-title">
-                            {i18n('Software Product Attachments')}
+        let { onBrowseVNF, currentSoftwareProduct } = this.props;
+
+        if (Configuration.get('showBrowseVNF')) {
+            return (
+                <div className="details-panel">
+                    {!isManual && (
+                        <div>
+                            <div className="software-product-landing-view-heading-title">
+                                {i18n('Software Product Attachments')}
+                            </div>
+                            <VnfRepositorySearchBox
+                                dataTestId="upload-btn"
+                                isReadOnlyMode={isReadOnlyMode}
+                                className={classnames(
+                                    'software-product-landing-view-top-block-col-upl showVnf',
+                                    { disabled: isReadOnlyMode }
+                                )}
+                                onClick={() => this.refs.fileInput.open()}
+                                onBrowseVNF={() =>
+                                    onBrowseVNF(currentSoftwareProduct)
+                                }
+                            />
                         </div>
-                        <DraggableUploadFileBox
-                            dataTestId="upload-btn"
-                            isReadOnlyMode={isReadOnlyMode}
-                            className={classnames(
-                                'software-product-landing-view-top-block-col-upl',
-                                { disabled: isReadOnlyMode }
-                            )}
-                            onClick={() => this.refs.fileInput.open()}
-                        />
-                    </div>
-                )}
-            </div>
-        );
+                    )}
+                </div>
+            );
+        } else {
+            return (
+                <div className="details-panel">
+                    {!isManual && (
+                        <div>
+                            <div className="software-product-landing-view-heading-title">
+                                {i18n('Software Product Attachments')}
+                            </div>
+                            <DraggableUploadFileBox
+                                dataTestId="upload-btn"
+                                isReadOnlyMode={isReadOnlyMode}
+                                className={classnames(
+                                    'software-product-landing-view-top-block-col-upl',
+                                    { disabled: isReadOnlyMode }
+                                )}
+                                onClick={() => this.refs.fileInput.open()}
+                                onBrowseVNF={() => onBrowseVNF()}
+                            />
+                        </div>
+                    )}
+                </div>
+            );
+        }
     }
 
     handleImportSubmit(files, isReadOnlyMode, isManual) {
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImport.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImport.js
new file mode 100644
index 0000000..19efab6
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImport.js
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd.
+ *
+ * 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.
+ */
+
+import { connect } from 'react-redux';
+import VNFImportView from './VNFImportView.jsx';
+import VNFImportActionHelper from './VNFImportActionHelper.js';
+
+export const mapStateToProps = response => {
+    const {
+        softwareProduct: { VNFMarketPlaceImport: { vnfItems } }
+    } = response;
+    return {
+        vnfItems: vnfItems
+    };
+};
+
+export const mapActionsToProps = dispatch => {
+    return {
+        onCancel: () => VNFImportActionHelper.resetData(dispatch),
+        onSubmit: (csarId, selectedVendor) => {
+            VNFImportActionHelper.uploadData(selectedVendor, csarId, dispatch);
+        }
+    };
+};
+
+export default connect(mapStateToProps, mapActionsToProps, null, {
+    withRef: true
+})(VNFImportView);
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImportActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImportActionHelper.js
new file mode 100644
index 0000000..3843330
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImportActionHelper.js
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd.
+ *
+ * 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.
+ */
+
+import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js';
+import Configuration from 'sdc-app/config/Configuration.js';
+import {
+    actionTypes as modalActionTypes,
+    modalSizes
+} from 'nfvo-components/modal/GlobalModalConstants.js';
+import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js';
+import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js';
+import { actionTypes } from './VNFImportConstants.js';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+
+function baseUrl(selectedVendor) {
+    const restPrefix = Configuration.get('restPrefix');
+    let vspId = selectedVendor.id;
+    let version = selectedVendor.version;
+    return `${restPrefix}/v1.0/vendor-software-products/${vspId}/versions/${
+        version.id
+    }/vnfrepository`;
+}
+
+function getVNFMarketplace(dispatch, currentSoftwareProduct) {
+    return RestAPIUtil.fetch(`${baseUrl(currentSoftwareProduct)}/vnfpackages`, {
+        isAnonymous: false
+    })
+        .then(response => {
+            dispatch({
+                type: actionTypes.OPEN,
+                response
+            });
+            dispatch({
+                type: modalActionTypes.GLOBAL_MODAL_SHOW,
+                data: {
+                    modalComponentName: modalContentMapper.VNF_IMPORT,
+                    title: i18n('Browse VNF'),
+                    modalComponentProps: {
+                        currentSoftwareProduct,
+                        size: modalSizes.LARGE
+                    }
+                }
+            });
+        })
+        .catch(error => {
+            let errMessage = error.responseJSON
+                ? error.responseJSON.message
+                : i18n('VNF import failed msg');
+
+            dispatch({
+                type: modalActionTypes.GLOBAL_MODAL_ERROR,
+                data: {
+                    title: i18n('VNF import failed title'),
+                    msg: errMessage,
+                    cancelButtonText: i18n('Ok')
+                }
+            });
+        });
+}
+
+function downloadCSARFile(csarId, currSoftwareProduct) {
+    let url = `${baseUrl(currSoftwareProduct)}/vnfpackage/${csarId}/download`;
+    return RestAPIUtil.fetch(url, {
+        dataType: 'binary',
+        isAnonymous: false
+    });
+}
+
+function getFileName(xhr, defaultFilename) {
+    let filename = '';
+    let contentDisposition =
+        xhr && xhr.getResponseHeader('Content-Disposition')
+            ? xhr.getResponseHeader('Content-Disposition')
+            : '';
+    let match = contentDisposition.match(/filename=(.*?)(;|$)/);
+    if (match) {
+        filename = match[1].replace(/['"]/g, '');
+    } else {
+        filename = defaultFilename;
+    }
+    return filename;
+}
+
+function uploadVNFData(csarId, currSoftwareProduct, dispatch) {
+    let softwareProductId = currSoftwareProduct.id;
+    let version = { id: currSoftwareProduct.version };
+
+    SoftwareProductActionHelper.uploadVNFFile(dispatch, {
+        csarId,
+        currSoftwareProduct,
+        failedNotificationTitle: i18n('Upload validation failed'),
+        softwareProductId,
+        version
+    });
+}
+
+function getTimestampString() {
+    let date = new Date();
+    let z = n => (n < 10 ? '0' + n : n);
+    return `${date.getFullYear()}-${z(date.getMonth())}-${z(
+        date.getDate()
+    )}_${z(date.getHours())}-${z(date.getMinutes())}`;
+}
+
+function showFileSaveDialog({ blob, xhr, defaultFilename, addTimestamp }) {
+    let filename = getFileName(xhr, defaultFilename);
+
+    if (addTimestamp) {
+        filename = filename.replace(
+            /(^.*?)\.([^.]+$)/,
+            `$1_${getTimestampString()}.$2`
+        );
+    }
+
+    let link = document.createElement('a');
+
+    let url = URL.createObjectURL(blob.blob);
+
+    link.href = url;
+    link.download = filename;
+    link.style.display = 'none';
+    document.body.appendChild(link);
+    link.click();
+    setTimeout(function() {
+        document.body.removeChild(link);
+        URL.revokeObjectURL(url);
+    }, 0);
+}
+
+const VNFImportActionHelper = {
+    open(dispatch, currentSoftwareProduct) {
+        getVNFMarketplace(dispatch, currentSoftwareProduct);
+    },
+
+    download(csarId, currSoftwareProduct) {
+        downloadCSARFile(csarId, currSoftwareProduct).then(
+            (blob, statusText, xhr) =>
+                showFileSaveDialog({
+                    blob,
+                    xhr,
+                    defaultFilename: 'MyNewCSAR.csar',
+                    addTimestamp: true
+                })
+        );
+    },
+
+    resetData(dispatch) {
+        dispatch({
+            type: modalActionTypes.GLOBAL_MODAL_CLOSE
+        });
+
+        dispatch({
+            type: actionTypes.RESET_DATA
+        });
+    },
+
+    getVNFMarketplace(dispatch) {
+        return getVNFMarketplace(dispatch);
+    },
+
+    uploadData(currSoftwareProduct, csarId, dispatch) {
+        this.resetData(dispatch);
+        uploadVNFData(csarId, currSoftwareProduct, dispatch);
+    }
+};
+
+export default VNFImportActionHelper;
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImportConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImportConstants.js
new file mode 100644
index 0000000..e4540dd
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImportConstants.js
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd.
+ *
+ * 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.
+ */
+import keyMirror from 'nfvo-utils/KeyMirror.js';
+
+export const actionTypes = keyMirror({
+    OPEN: null,
+    RESET_DATA: null
+});
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImportReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImportReducer.js
new file mode 100644
index 0000000..0f2638f
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImportReducer.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd.
+ *
+ * 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.
+ */
+import { actionTypes } from './VNFImportConstants.js';
+
+export default (state = {}, action) => {
+    switch (action.type) {
+        case actionTypes.OPEN:
+            return {
+                ...state,
+                showModal: true,
+                vnfItems: action.response
+            };
+        case actionTypes.RESET_DATA:
+            return {};
+        default:
+            return state;
+    }
+};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImportView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImportView.jsx
new file mode 100644
index 0000000..3a90c80
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/vnfMarketPlace/VNFImportView.jsx
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd.
+ *
+ * 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.
+ */
+
+import React from 'react';
+import GridSection from 'nfvo-components/grid/GridSection.jsx';
+import GridItem from 'nfvo-components/grid/GridItem.jsx';
+import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
+import Button from 'sdc-ui/lib/react/Button.js';
+import VNFImportActionHelper from '../vnfMarketPlace/VNFImportActionHelper.js';
+
+function VNFAction({
+    action,
+    isHeader,
+    downloadCSAR,
+    id,
+    currSoftwareProduct
+}) {
+    if (isHeader) {
+        return <span>{action}</span>;
+    }
+    return (
+        <span>
+            <SVGIcon
+                name="download"
+                color="positive"
+                onClick={() => {
+                    downloadCSAR(id, currSoftwareProduct);
+                }}
+            />
+        </span>
+    );
+}
+
+function VNFSortableCellHeader({
+    isHeader,
+    data,
+    isDes,
+    onSort,
+    activeSortColumn
+}) {
+    //TODO check icon sdc-ui
+    if (isHeader) {
+        if (activeSortColumn === data) {
+            return (
+                <span
+                    className="vnf-table-header"
+                    onClick={() => {
+                        onSort(activeSortColumn);
+                    }}>
+                    <span>{data}</span>
+                    <span
+                        className={`header-sort-arrow ${isDes ? 'up' : 'down'}`}
+                    />
+                </span>
+            );
+        } else {
+            return (
+                <span
+                    className="vnf-table-header"
+                    onClick={() => {
+                        activeSortColumn = data;
+                        onSort(activeSortColumn);
+                    }}>
+                    <span>{data}</span>
+                </span>
+            );
+        }
+    }
+    return (
+        <span className="vnf-table-cell">
+            <span>{data}</span>
+        </span>
+    );
+}
+
+export function VNFItemList({
+    vnf,
+    isHeader,
+    isDes,
+    onSort,
+    activeSortColumn,
+    downloadCSAR,
+    selectTableRow,
+    selectedRow,
+    currentSoftwareProduct
+}) {
+    let { csarId, name, version, provider, shortDesc, action } = vnf;
+    return (
+        <li
+            className={`vnfBrowse-list-item ${isHeader ? 'header' : ''} ${
+                csarId === selectedRow ? 'selectedRow' : ''
+            }`}
+            data-test-id="vnfBrowse-list-item"
+            onClick={() => {
+                selectTableRow(csarId);
+            }}>
+            <div
+                className="table-cell vnftable-name"
+                data-test-id="vnftable-name">
+                <VNFSortableCellHeader
+                    isHeader={isHeader}
+                    data={name}
+                    isDes={isDes}
+                    onSort={activeSort => {
+                        onSort('name', activeSort);
+                    }}
+                    activeSortColumn={activeSortColumn}
+                />
+            </div>
+            <div
+                className="table-cell vnftable-version"
+                data-test-id="vnftable-version">
+                <VNFSortableCellHeader
+                    isHeader={isHeader}
+                    data={version}
+                    isDes={isDes}
+                    onSort={activeSort => {
+                        onSort('version', activeSort);
+                    }}
+                    activeSortColumn={activeSortColumn}
+                />
+            </div>
+            <div
+                className="table-cell vnftable-provider"
+                data-test-id="vnftable-provider">
+                <VNFSortableCellHeader
+                    isHeader={isHeader}
+                    data={provider}
+                    isDes={isDes}
+                    onSort={activeSort => {
+                        onSort('provider', activeSort);
+                    }}
+                    activeSortColumn={activeSortColumn}
+                />
+            </div>
+            <div
+                className="table-cell vnftable-shortDesc"
+                data-test-id="vnftable-shortDesc">
+                <VNFSortableCellHeader
+                    isHeader={isHeader}
+                    data={shortDesc}
+                    isDes={isDes}
+                    onSort={activeSort => {
+                        onSort('shortDesc', activeSort);
+                    }}
+                    activeSortColumn={activeSortColumn}
+                />
+            </div>
+            <div
+                className="table-cell vnftable-action"
+                data-test-id="vnftable-action">
+                <VNFAction
+                    isHeader={isHeader}
+                    action={action}
+                    downloadCSAR={downloadCSAR}
+                    id={csarId}
+                    currSoftwareProduct={currentSoftwareProduct}
+                />
+            </div>
+        </li>
+    );
+}
+
+class VNFImportView extends React.Component {
+    state = {
+        localFilter: '',
+        sortDescending: true,
+        sortCrit: 'name',
+        activeSortColumn: 'Name',
+        selectedRow: ''
+    };
+
+    render() {
+        let { onCancel, onSubmit, currentSoftwareProduct } = this.props;
+
+        return (
+            <div className="vnf-creation-page">
+                <GridSection className="vnf-grid-section">
+                    <GridItem colSpan="4">
+                        <ListEditorView
+                            title={i18n('VNF List Title')}
+                            filterValue={this.state.localFilter}
+                            onFilter={filter =>
+                                this.setState({ localFilter: filter })
+                            }>
+                            <VNFItemList
+                                isHeader={true}
+                                vnf={{
+                                    csarId: 0,
+                                    name: i18n('VNF Header Name'),
+                                    version: i18n('VNF Header Version'),
+                                    provider: i18n('VNF Header Vendor'),
+                                    shortDesc: i18n('VNF Header Desc'),
+                                    action: i18n('VNF Header Action')
+                                }}
+                                isDes={this.state.sortDescending}
+                                onSort={(sortCriteria, activeSortCol) =>
+                                    this.setState({
+                                        sortDescending: !this.state
+                                            .sortDescending,
+                                        sortCrit: sortCriteria,
+                                        activeSortColumn: activeSortCol
+                                    })
+                                }
+                                activeSortColumn={this.state.activeSortColumn}
+                            />
+                            {this.sortVNFItems(
+                                this.filterVNFItems(),
+                                this.state.sortDescending,
+                                this.state.sortCrit
+                            ).map(vnf => (
+                                <VNFItemList
+                                    key={vnf.id}
+                                    vnf={vnf}
+                                    downloadCSAR={this.downloadCSAR}
+                                    selectTableRow={selID => {
+                                        this.setState({ selectedRow: selID });
+                                        this.selectTableRow(selID);
+                                    }}
+                                    selectedRow={this.state.selectedRow}
+                                    currentSoftwareProduct={
+                                        currentSoftwareProduct
+                                    }
+                                />
+                            ))}
+                        </ListEditorView>
+                    </GridItem>
+                    <GridItem colSpan="4">
+                        <div className="vnf-modal">
+                            <Button
+                                className="vnf-submit"
+                                type="button"
+                                btnType="default"
+                                onClick={() =>
+                                    onSubmit(
+                                        this.state.selectedRow,
+                                        currentSoftwareProduct
+                                    )
+                                }>
+                                {i18n('OK')}
+                            </Button>
+                            <Button
+                                className="Cancel"
+                                type="button"
+                                btnType="outline"
+                                onClick={onCancel}>
+                                {i18n('Cancel')}
+                            </Button>
+                        </div>
+                    </GridItem>
+                </GridSection>
+            </div>
+        );
+    }
+
+    filterVNFItems() {
+        let { vnfItems } = this.props;
+        let { localFilter } = this.state;
+        if (localFilter.trim()) {
+            const filter = new RegExp(escape(localFilter), 'i');
+            return vnfItems.filter(
+                ({ name = '', provider = '', version = '', shortDesc = '' }) =>
+                    escape(name).match(filter) ||
+                    escape(provider).match(filter) ||
+                    escape(version).match(filter) ||
+                    escape(shortDesc).match(filter)
+            );
+        } else {
+            return vnfItems;
+        }
+    }
+
+    sortVNFItems(vnfItems, sortDesc, sortCrit) {
+        if (sortDesc) {
+            return vnfItems.sort((a, b) => {
+                if (a[sortCrit] < b[sortCrit]) {
+                    return -1;
+                } else if (a[sortCrit] > b[sortCrit]) {
+                    return 1;
+                } else {
+                    return 0;
+                }
+            });
+        } else {
+            return vnfItems.reverse();
+        }
+    }
+
+    downloadCSAR(id, currSoftwareProduct) {
+        VNFImportActionHelper.download(id, currSoftwareProduct);
+    }
+}
+
+export default VNFImportView;