summaryrefslogtreecommitdiffstats
path: root/openecomp-ui/src/sdc-app
diff options
context:
space:
mode:
authorshrek2000 <orenkle@amdocs.com>2017-09-11 15:45:37 +0300
committershrek2000 <orenkle@amdocs.com>2017-09-12 10:38:35 +0300
commitc8a540b3c234449163f6fb1899807bba951113b4 (patch)
treea8aae0dd0f6a0feb27369914e9e3fa321740e7ed /openecomp-ui/src/sdc-app
parent82d454fd3e8c9fdf66517d01a99019a379dbfdb6 (diff)
Create new VSP, onboard from TOSCA file - UI
Change-Id: I018c6d07a4b9ec7e6b1507ab37e2550865423cfe Issue-ID: SDC-230 Signed-off-by: shrek2000 <orenkle@amdocs.com>
Diffstat (limited to 'openecomp-ui/src/sdc-app')
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js18
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx21
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js24
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js22
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js10
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js2
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js12
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsActionHelper.js26
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsConstants.js6
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsReducer.js25
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsView.jsx42
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationReducer.js11
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationView.jsx6
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx8
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js5
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx41
16 files changed, 182 insertions, 97 deletions
diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js
index 24ba05e303..fc65083bff 100644
--- a/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js
+++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js
@@ -31,11 +31,13 @@ import OnboardActionHelper from './onboard/OnboardActionHelper.js';
import SoftwareProductComponentsMonitoringAction from './softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringActionHelper.js';
import {actionTypes, enums} from './OnboardingConstants.js';
import SoftwareProductComponentsImageActionHelper from './softwareProduct/components/images/SoftwareProductComponentsImageActionHelper.js';
-import {navigationItems as SoftwareProductNavigationItems, actionTypes as SoftwareProductActionTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
+import {navigationItems as SoftwareProductNavigationItems, actionTypes as SoftwareProductActionTypes, onboardingOriginTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
import ActivityLogActionHelper from 'sdc-app/common/activity-log/ActivityLogActionHelper.js';
import licenseModelOverviewActionHelper from 'sdc-app/onboarding/licenseModel/overview/licenseModelOverviewActionHelper.js';
import store from 'sdc-app/AppStore.js';
import {selectedButton as licenseModelOverviewSelectedButton} from 'sdc-app/onboarding/licenseModel/overview/LicenseModelOverviewConstants.js';
+import {tabsMapping as attachmentsTabsMapping} from 'sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsConstants.js';
+import SoftwareProductAttachmentsActionHelper from 'sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsActionHelper.js';
function setCurrentScreen(dispatch, screen, props = {}) {
dispatch({
@@ -165,7 +167,9 @@ export default {
SoftwareProductActionHelper.loadSoftwareProductDetailsData(dispatch, {licenseModelId, licensingVersion});
SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version: newVersion});
- SoftwareProductActionHelper.loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version: newVersion});
+ if(response[0].onboardingOrigin === onboardingOriginTypes.ZIP) {
+ SoftwareProductActionHelper.loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version: newVersion});
+ }
setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, {softwareProductId, licenseModelId, version: newVersion});
});
},
@@ -175,11 +179,19 @@ export default {
setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_DETAILS, {softwareProductId, version});
},
- navigateToSoftwareProductAttachments(dispatch, {softwareProductId, version}) {
+ navigateToSoftwareProductAttachmentsSetupTab(dispatch, {softwareProductId, version}) {
SoftwareProductActionHelper.loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version});
+ SoftwareProductAttachmentsActionHelper.setActiveTab(dispatch, {activeTab: attachmentsTabsMapping.SETUP});
setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS, {softwareProductId, version});
},
+ navigateToSoftwareProductAttachmentsValidationTab(dispatch, {softwareProductId, version}) {
+ SoftwareProductActionHelper.processAndValidateHeatCandidate(dispatch, {softwareProductId, version}).then(() => {
+ SoftwareProductAttachmentsActionHelper.setActiveTab(dispatch, {activeTab: attachmentsTabsMapping.VALIDATION});
+ setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS, {softwareProductId, version});
+ });
+ },
+
navigateToSoftwareProductProcesses(dispatch, {softwareProductId, version}) {
if (softwareProductId) {
SoftwareProductProcessesActionHelper.fetchProcessesList(dispatch, {softwareProductId, version});
diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx b/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx
index aea5fc6406..c1f3251281 100644
--- a/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx
@@ -28,7 +28,6 @@ import Onboard from './onboard/Onboard.js';
import LicenseModel from './licenseModel/LicenseModel.js';
import LicenseModelOverview from './licenseModel/overview/LicenseModelOverview.js';
import ActivityLog from 'sdc-app/common/activity-log/ActivityLog.js';
-import {doesHeatDataExist} from './softwareProduct/attachments/SoftwareProductAttachmentsUtils.js';
import LicenseAgreementListEditor from './licenseModel/licenseAgreement/LicenseAgreementListEditor.js';
import FeatureGroupListEditor from './licenseModel/featureGroups/FeatureGroupListEditor.js';
@@ -55,7 +54,8 @@ import SoftwareProductComponentsMonitoring from './softwareProduct/components/mo
import {
navigationItems as SoftwareProductNavigationItems,
onboardingMethod as onboardingMethodTypes,
- actionTypes as SoftwareProductActionTypes
+ actionTypes as SoftwareProductActionTypes,
+ onboardingOriginTypes
} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
import {statusEnum as VCItemStatus} from 'nfvo-components/panel/versionController/VersionControllerConstants.js';
@@ -314,7 +314,12 @@ export default class OnboardingPunchOut {
OnboardingActionHelper.navigateToSoftwareProductDetails(dispatch, {softwareProductId, version: currentSoftwareProductVersion});
break;
case enums.BREADCRUMS.SOFTWARE_PRODUCT_ATTACHMENTS:
- OnboardingActionHelper.navigateToSoftwareProductAttachments(dispatch, {softwareProductId, version: currentSoftwareProductVersion});
+ if(softwareProduct.onboardingOrigin === onboardingOriginTypes.ZIP) {
+ OnboardingActionHelper.navigateToSoftwareProductAttachmentsSetupTab(dispatch, {softwareProductId, version: currentSoftwareProductVersion});
+ }
+ else if(softwareProduct.onboardingOrigin === onboardingOriginTypes.CSAR) {
+ OnboardingActionHelper.navigateToSoftwareProductAttachmentsValidationTab(dispatch, {softwareProductId, version: currentSoftwareProductVersion});
+ }
break;
case enums.BREADCRUMS.SOFTWARE_PRODUCT_PROCESSES:
OnboardingActionHelper.navigateToSoftwareProductProcesses(dispatch, {softwareProductId, version: currentSoftwareProductVersion});
@@ -415,9 +420,9 @@ export default class OnboardingPunchOut {
handleStoreChange() {
let {currentScreen, licenseModelList, softwareProductList,
softwareProduct: {softwareProductEditor: {data = {onboardingMethod: ''}},
- softwareProductComponents: {componentsList}, softwareProductAttachments: {heatSetup}}} = store.getState();
- let {onboardingMethod} = data;
- let breadcrumbsData = {onboardingMethod, currentScreen, licenseModelList, softwareProductList, componentsList, heatSetup};
+ softwareProductComponents: {componentsList}}} = store.getState();
+ let {onboardingMethod, onboardingOrigin} = data;
+ let breadcrumbsData = {onboardingMethod, currentScreen, licenseModelList, softwareProductList, componentsList, onboardingOrigin};
if (currentScreen.forceBreadCrumbsUpdate || !isEqual(breadcrumbsData, this.prevBreadcrumbsData) || this.breadcrumbsPrefixSelected) {
this.prevBreadcrumbsData = breadcrumbsData;
this.breadcrumbsPrefixSelected = false;
@@ -434,7 +439,7 @@ export default class OnboardingPunchOut {
}
}
- buildBreadcrumbs({currentScreen: {screen, props}, onboardingMethod, licenseModelList, softwareProductList, componentsList, heatSetup}) {
+ buildBreadcrumbs({currentScreen: {screen, props}, onboardingMethod, licenseModelList, softwareProductList, componentsList, onboardingOrigin}) {
let screenToBreadcrumb;
switch (screen) {
case enums.SCREEN.ONBOARDING_CATALOG:
@@ -593,7 +598,7 @@ export default class OnboardingPunchOut {
key: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENTS,
displayText: i18n('Components')
}].filter(item => {
- let isHeatData = doesHeatDataExist(heatSetup);
+ let isHeatData = onboardingOrigin !== onboardingOriginTypes.NONE;
let isManualMode = onboardingMethod === onboardingMethodTypes.MANUAL;
switch (item.key) {
case enums.BREADCRUMS.SOFTWARE_PRODUCT_ATTACHMENTS:
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js
index c9c95f359e..6426847cfc 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js
@@ -22,11 +22,10 @@ import TabulatedEditor from 'src/nfvo-components/editor/TabulatedEditor.jsx';
import {enums} from 'sdc-app/onboarding/OnboardingConstants.js';
import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js';
-import {navigationItems, mapScreenToNavigationItem, onboardingMethod as onboardingMethodTypes} from './SoftwareProductConstants.js';
+import {navigationItems, mapScreenToNavigationItem, onboardingMethod as onboardingMethodTypes, onboardingOriginTypes} from './SoftwareProductConstants.js';
import SoftwareProductActionHelper from './SoftwareProductActionHelper.js';
import SoftwareProductComponentsActionHelper from './components/SoftwareProductComponentsActionHelper.js';
import SoftwareProductDependenciesActionHelper from './dependencies/SoftwareProductDependenciesActionHelper.js';
-import {doesHeatDataExist} from './attachments/SoftwareProductAttachmentsUtils.js';
import HeatSetupActionHelper from './attachments/setup/HeatSetupActionHelper.js';
import { actionsEnum as versionControllerActions } from 'nfvo-components/panel/versionController/VersionControllerConstants.js';
@@ -86,7 +85,7 @@ const buildComponentNavigationBarGroups = ({componentId, meta}) => {
const buildNavigationBarProps = ({softwareProduct, meta, screen, componentId, componentsList, mapOfExpandedIds}) => {
const {softwareProductEditor: {data: currentSoftwareProduct = {}}} = softwareProduct;
- const {id, name, onboardingMethod} = currentSoftwareProduct;
+ const {id, name, onboardingMethod, onboardingOrigin} = currentSoftwareProduct;
const groups = [{
id: id,
name: name,
@@ -122,7 +121,7 @@ const buildNavigationBarProps = ({softwareProduct, meta, screen, componentId, co
id: navigationItems.ATTACHMENTS,
name: i18n('Attachments'),
disabled: false,
- hidden: !doesHeatDataExist(meta.heatSetup),
+ hidden: onboardingOrigin === onboardingOriginTypes.NONE,
meta
}, {
id: navigationItems.ACTIVITY_LOG,
@@ -175,7 +174,7 @@ const buildVersionControllerProps = (softwareProduct) => {
function buildMeta({softwareProduct, componentId, softwareProductDependencies}) {
const {softwareProductEditor, softwareProductComponents, softwareProductQuestionnaire, softwareProductAttachments} = softwareProduct;
const {data: currentSoftwareProduct = {}} = softwareProductEditor;
- const {version} = currentSoftwareProduct;
+ const {version, onboardingOrigin} = currentSoftwareProduct;
const isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct);
const {qdata} = softwareProductQuestionnaire;
const {heatSetup, heatSetupCache} = softwareProductAttachments;
@@ -184,7 +183,7 @@ function buildMeta({softwareProduct, componentId, softwareProductDependencies})
const {componentEditor: {data: componentData = {} , qdata: componentQdata}} = softwareProductComponents;
currentComponentMeta = {componentData, componentQdata};
}
- const meta = {softwareProduct: currentSoftwareProduct, qdata, version, heatSetup, heatSetupCache, isReadOnlyMode, currentComponentMeta, softwareProductDependencies};
+ const meta = {softwareProduct: currentSoftwareProduct, qdata, version, onboardingOrigin, heatSetup, heatSetupCache, isReadOnlyMode, currentComponentMeta, softwareProductDependencies};
return meta;
}
@@ -280,7 +279,7 @@ const mapActionsToProps = (dispatch, {currentScreen: {screen, props: {softwarePr
},
onToggle: (groups, itemIdToExpand) => groups.map(({items}) => SoftwareProductActionHelper.toggleNavigationItems(dispatch, {items, itemIdToExpand})),
onNavigate: ({id, meta, version}) => {
- let {heatSetup, heatSetupCache} = meta;
+ let {onboardingOrigin, heatSetup, heatSetupCache} = meta;
let heatSetupPopupPromise = screen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS ?
HeatSetupActionHelper.heatSetupLeaveConfirmation(dispatch, {softwareProductId, heatSetup, heatSetupCache}) :
Promise.resolve();
@@ -307,7 +306,12 @@ const mapActionsToProps = (dispatch, {currentScreen: {screen, props: {softwarePr
OnboardingActionHelper.navigateToSoftwareProductDependencies(dispatch, {softwareProductId, version});
break;
case navigationItems.ATTACHMENTS:
- OnboardingActionHelper.navigateToSoftwareProductAttachments(dispatch, {softwareProductId, version});
+ if(onboardingOrigin === onboardingOriginTypes.ZIP) {
+ OnboardingActionHelper.navigateToSoftwareProductAttachmentsSetupTab(dispatch, {softwareProductId, version});
+ }
+ else if(onboardingOrigin === onboardingOriginTypes.CSAR) {
+ OnboardingActionHelper.navigateToSoftwareProductAttachmentsValidationTab(dispatch, {softwareProductId, version});
+ }
break;
case navigationItems.COMPONENTS:
OnboardingActionHelper.navigateToSoftwareProductComponents(dispatch, {softwareProductId, version});
@@ -334,9 +338,7 @@ const mapActionsToProps = (dispatch, {currentScreen: {screen, props: {softwarePr
case enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT:
case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES:
case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING:
- props.onSave = () => {
- return Promise.resolve();
- };
+ props.onSave = () => Promise.resolve();
break;
default:
props.onSave = ({softwareProduct, qdata}) => SoftwareProductActionHelper.updateSoftwareProduct(dispatch, {softwareProduct, qdata});
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js
index d4bee0a876..41306a1c1a 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js
@@ -20,7 +20,7 @@ import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseMod
import LicenseAgreementActionHelper from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js';
import FeatureGroupsActionHelper from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js';
-import {actionTypes} from './SoftwareProductConstants.js';
+import {actionTypes, onboardingOriginTypes, PRODUCT_QUESTIONNAIRE, forms} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js';
import SoftwareProductComponentsActionHelper from './components/SoftwareProductComponentsActionHelper.js';
import {actionsEnum as VersionControllerActionsEnum} from 'nfvo-components/panel/versionController/VersionControllerConstants.js';
@@ -29,10 +29,10 @@ import {actionTypes as featureGroupsActionConstants} from 'sdc-app/onboarding/li
import {actionTypes as licenseAgreementActionTypes} from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js';
import {actionTypes as componentActionTypes} from './components/SoftwareProductComponentsConstants.js';
import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js';
-import {PRODUCT_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js';
import {statusEnum} from 'nfvo-components/panel/versionController/VersionControllerConstants.js';
+import {actionTypes as commonActionTypes} from 'sdc-app/common/reducers/PlainDataReducerConstants.js';
function baseUrl() {
const restPrefix = Configuration.get('restPrefix');
@@ -59,7 +59,9 @@ function putSoftwareProduct(softwareProduct) {
licensingVersion: softwareProduct.licensingVersion && softwareProduct.licensingVersion.id ? softwareProduct.licensingVersion : {} ,
icon: softwareProduct.icon,
licensingData: softwareProduct.licensingData,
- onboardingMethod: softwareProduct.onboardingMethod
+ onboardingMethod: softwareProduct.onboardingMethod,
+ networkPackageName: softwareProduct.networkPackageName,
+ onboardingOrigin: softwareProduct.onboardingOrigin
});
}
@@ -267,7 +269,19 @@ const SoftwareProductActionHelper = {
.then(() => uploadFile(softwareProductId, formData, version))
.then(response => {
if (response.status === 'Success') {
- OnboardingActionHelper.navigateToSoftwareProductAttachments(dispatch, {softwareProductId, version});
+ 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));
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js
index 0379ee5d4a..2c094ac36a 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js
@@ -39,7 +39,7 @@ export const navigationItems = keyMirror({
GENERAL: 'general',
PROCESS_DETAILS: 'process-details',
DEPLOYMENT_FLAVORS: 'deployment-flavor',
- NETWORKS: 'networks',
+ NETWORKS: 'networks',
IMAGES: 'images',
ATTACHMENTS: 'attachments',
ACTIVITY_LOG: 'activity-log',
@@ -54,7 +54,13 @@ export const navigationItems = keyMirror({
export const onboardingMethod = {
MANUAL: 'Manual',
- HEAT: 'HEAT'
+ NETWORK_PACKAGE: 'NetworkPackage'
+};
+
+export const onboardingOriginTypes = {
+ NONE: 'none',
+ ZIP: 'zip',
+ CSAR: 'csar'
};
export const forms = keyMirror({
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js
index 977a76ac69..d7a6c2ef5c 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js
@@ -15,6 +15,7 @@
*/
import {combineReducers} from 'redux';
import {actionTypes, PRODUCT_QUESTIONNAIRE} from './SoftwareProductConstants.js';
+import SoftwareProductAttachmentsReducer from './attachments/SoftwareProductAttachmentsReducer.js';
import HeatValidationReducer from './attachments/validation/HeatValidationReducer.js';
import HeatSetupReducer from './attachments/setup/HeatSetupReducer.js';
import {actionTypes as heatSetupActionTypes} from './attachments/setup/HeatSetupConstants.js';
@@ -48,6 +49,7 @@ import {IMAGE_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components
export default combineReducers({
softwareProductAttachments: combineReducers({
+ attachmentsDetails: SoftwareProductAttachmentsReducer,
heatValidation: HeatValidationReducer,
heatSetup: HeatSetupReducer,
heatSetupCache: (state = {}, action) => action.type === heatSetupActionTypes.FILL_HEAT_SETUP_CACHE ? action.payload : state
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js
index 945de4fc36..f14c988866 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js
@@ -23,6 +23,7 @@ import {errorLevels} from 'sdc-app/onboarding/softwareProduct/attachments/valida
import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js';
import HeatSetup from './setup/HeatSetup.js';
import {doesHeatDataExist} from './SoftwareProductAttachmentsUtils.js';
+import SoftwareProductAttachmentsActionHelper from './SoftwareProductAttachmentsActionHelper.js';
import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js';
@@ -30,7 +31,7 @@ export const mapStateToProps = (state) => {
let {
softwareProduct: {
softwareProductEditor:{data: currentSoftwareProduct = {}},
- softwareProductAttachments: {heatSetup, heatSetupCache, heatValidation : {errorList}}
+ softwareProductAttachments: {attachmentsDetails: {activeTab}, heatSetup, heatSetupCache, heatValidation : {errorList}}
}
} = state;
@@ -47,7 +48,7 @@ export const mapStateToProps = (state) => {
let isReadOnlyMode = currentSoftwareProduct && currentSoftwareProduct.version ?
VersionControllerUtils.isReadOnly(currentSoftwareProduct) : false;
- let {version} = currentSoftwareProduct;
+ let {version, onboardingOrigin} = currentSoftwareProduct;
return {
isValidationAvailable: unassigned.length === 0 && modules.length > 0,
heatSetup,
@@ -56,7 +57,9 @@ export const mapStateToProps = (state) => {
goToOverview,
HeatSetupComponent: HeatSetup,
isReadOnlyMode,
- version
+ version,
+ onboardingOrigin,
+ activeTab
};
};
@@ -83,7 +86,8 @@ export const mapActionsToProps = (dispatch, {softwareProductId}) => {
onProcessAndValidate: ({heatData, heatDataCache, isReadOnlyMode, version}) => {
return HeatSetupActionHelper.processAndValidateHeat(dispatch,
{softwareProductId, heatData, heatDataCache, isReadOnlyMode, version});
- }
+ },
+ setActiveTab: ({activeTab}) => SoftwareProductAttachmentsActionHelper.setActiveTab(dispatch, {activeTab})
};
};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsActionHelper.js
new file mode 100644
index 0000000000..ae4a615a40
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsActionHelper.js
@@ -0,0 +1,26 @@
+/*!
+ * 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 {actionTypes} from './SoftwareProductAttachmentsConstants';
+
+export default {
+ setActiveTab(dispatch, {activeTab}) {
+ dispatch({
+ type: actionTypes.SET_ACTIVE_TAB,
+ activeTab
+ });
+ }
+};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsConstants.js
index b0410d1566..67265909d7 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsConstants.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsConstants.js
@@ -13,7 +13,13 @@
* 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 tabsMapping = {
SETUP: 1,
VALIDATION: 2
};
+
+export const actionTypes = keyMirror({
+ SET_ACTIVE_TAB: null
+});
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsReducer.js
new file mode 100644
index 0000000000..5f6538ab7e
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsReducer.js
@@ -0,0 +1,25 @@
+/*!
+ * 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 {actionTypes} from './SoftwareProductAttachmentsConstants.js';
+
+export default (state = [], action) => {
+ switch (action.type) {
+ case actionTypes.SET_ACTIVE_TAB:
+ return {activeTab: action.activeTab};
+ default:
+ return state;
+ }
+};
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsView.jsx
index 3da26cc20f..8c59b2b1cc 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsView.jsx
@@ -20,34 +20,34 @@ import {tabsMapping} from './SoftwareProductAttachmentsConstants.js';
import i18n from 'nfvo-utils/i18n/i18n.js';
import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js';
import HeatValidation from './validation/HeatValidation.js';
+import {onboardingOriginTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js';
class HeatScreenView extends Component {
static propTypes = {
isValidationAvailable: PropTypes.bool,
- goToOverview: PropTypes.bool
- };
-
- state = {
- activeTab: tabsMapping.SETUP
+ goToOverview: PropTypes.bool,
+ setActiveTab: PropTypes.function
};
render() {
- let {isValidationAvailable, isReadOnlyMode, heatDataExist, onDownload, softwareProductId, onProcessAndValidate, heatSetup, HeatSetupComponent, onGoToOverview, version, ...other} = this.props;
+ let {isValidationAvailable, isReadOnlyMode, heatDataExist, onDownload, softwareProductId, onProcessAndValidate,
+ heatSetup, HeatSetupComponent, onGoToOverview, version, onboardingOrigin, activeTab, setActiveTab, ...other} = this.props;
+
return (
<div className='vsp-attachments-view'>
<div className='attachments-view-controllers'>
- {(this.state.activeTab === tabsMapping.SETUP) &&
+ {(activeTab === tabsMapping.SETUP) &&
<SVGIcon
disabled={heatDataExist ? false : true}
name='download'
className='icon-component'
- label={i18n('Download HEAT')}
+ label={i18n('Export Validation')}
labelPosition='right'
color='secondary'
onClick={heatDataExist ? () => onDownload({heatCandidate: heatSetup, isReadOnlyMode, version}) : undefined}
data-test-id='download-heat'/>}
- {(this.state.activeTab === tabsMapping.VALIDATION && softwareProductId) &&
+ {(activeTab === tabsMapping.VALIDATION && softwareProductId) &&
<SVGIcon
disabled={this.props.goToOverview !== true}
onClick={this.props.goToOverview ? () => onGoToOverview({version}) : undefined}
@@ -60,7 +60,7 @@ class HeatScreenView extends Component {
<SVGIcon
name='upload'
className='icon-component'
- label={i18n('Upload New HEAT')}
+ label={i18n('Upload New File')}
labelPosition='right'
color='secondary'
disabled={isReadOnlyMode}
@@ -70,20 +70,20 @@ class HeatScreenView extends Component {
ref='hiddenImportFileInput'
type='file'
name='fileInput'
- accept='.zip'
+ accept='.zip, .csar'
onChange={evt => this.handleImport(evt)}/>
</div>
- <Tabs id='attachments-tabs' activeKey={this.state.activeTab} onSelect={key => this.handleTabPress(key)}>
- <Tab eventKey={tabsMapping.SETUP} title='HEAT Setup'>
+ <Tabs id='attachments-tabs' activeKey={activeTab} onSelect={key => this.handleTabPress(key)}>
+ <Tab eventKey={tabsMapping.SETUP} title='Setup' disabled={onboardingOrigin === onboardingOriginTypes.CSAR}>
<HeatSetupComponent
heatDataExist={heatDataExist}
- changeAttachmentsTab={tab => this.setState({activeTab: tab})}
+ changeAttachmentsTab={tab => setActiveTab({activeTab: tab})}
onProcessAndValidate={onProcessAndValidate}
softwareProductId={softwareProductId}
isReadOnlyMode={isReadOnlyMode}
version={version}/>
</Tab>
- <Tab eventKey={tabsMapping.VALIDATION} title='Heat Validation' disabled={!isValidationAvailable}>
+ <Tab eventKey={tabsMapping.VALIDATION} title='Validation' disabled={!isValidationAvailable}>
<HeatValidation {...other}/>
</Tab>
</Tabs>
@@ -92,15 +92,15 @@ class HeatScreenView extends Component {
}
handleTabPress(key) {
- let {heatSetup, heatSetupCache, onProcessAndValidate, isReadOnlyMode, version} = this.props;
+ let {heatSetup, heatSetupCache, onProcessAndValidate, isReadOnlyMode, version, setActiveTab} = this.props;
switch (key) {
case tabsMapping.VALIDATION:
onProcessAndValidate({heatData: heatSetup, heatDataCache: heatSetupCache, isReadOnlyMode, version}).then(
- () => this.setState({activeTab: tabsMapping.VALIDATION})
+ () => setActiveTab({activeTab: tabsMapping.VALIDATION})
);
return;
case tabsMapping.SETUP:
- this.setState({activeTab: tabsMapping.SETUP});
+ setActiveTab({activeTab: tabsMapping.SETUP});
return;
}
}
@@ -112,11 +112,13 @@ class HeatScreenView extends Component {
formData.append('upload', this.refs.hiddenImportFileInput.files[0]);
this.refs.hiddenImportFileInput.value = '';
this.props.onUpload(formData, version);
- this.setState({activeTab: tabsMapping.SETUP});
}
save() {
- return this.props.onSave(this.props.heatSetup, this.props.version);
+
+ return this.props.onboardingOrigin === onboardingOriginTypes.ZIP ?
+ this.props.onSave(this.props.heatSetup, this.props.version) :
+ Promise.resolve();
}
}
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationReducer.js
index f0c10ed457..1d11bdd6b7 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationReducer.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationReducer.js
@@ -89,16 +89,16 @@ function createErrorList(node, parent, deep = 0, errorList = []) {
return errorList;
}
-const mapValidationDataToTree = validationData => {
- let {heat, volume, network, artifacts, other} = validationData.importStructure || {};
+const mapValidationDataToTree = (validationData, packageName) => {
+ let {heat, nested, volume, network, artifacts, other} = validationData.importStructure || {};
return {
children: [
{
- name: 'HEAT',
+ name: packageName,
expanded: true,
type: 'heat',
header: true,
- children: (heat ? heat.map(mapHeatData) : [])
+ children: (heat ? heat.map(mapHeatData) : nested ? nested.map(mapHeatData) : [])
},
...(artifacts ? [{
name: 'artifacts',
@@ -165,7 +165,8 @@ export default (state = {attachmentsTree: {}}, action) => {
switch (action.type) {
case softwareProductsActionTypes.SOFTWARE_PRODUCT_LOADED:
let currentSoftwareProduct = action.response;
- let attachmentsTree = currentSoftwareProduct.validationData ? mapValidationDataToTree(currentSoftwareProduct.validationData) : {};
+ const packageName = currentSoftwareProduct.networkPackageName;
+ let attachmentsTree = currentSoftwareProduct.validationData ? mapValidationDataToTree(currentSoftwareProduct.validationData, packageName) : {};
let errorList = createErrorList(attachmentsTree);
return {
...state,
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationView.jsx
index 2a2f4ac291..80d74b2964 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationView.jsx
@@ -93,9 +93,9 @@ function HeatFileTreeHeader(props) {
<div onClick={() => props.selectNode(nodeFilters.ALL)} className={classNames({'attachments-tree-header': true,
'header-selected' : props.selectedNode === nodeFilters.ALL})} data-test-id='validation-tree-header'>
<div className='tree-header-title' >
- <SVGIcon name='zip' color={props.selectedNode === nodeFilters.ALL ? 'primary' : ''} iconClassName='header-icon' />
+ {/*<SVGIcon name='zip' color={props.selectedNode === nodeFilters.ALL ? 'primary' : ''} iconClassName='header-icon' />*/}
<span className={classNames({'tree-header-title-text' : true,
- 'tree-header-title-selected' : props.selectedNode === nodeFilters.ALL})}>{i18n(`HEAT${hasErrors ? ' (Draft)' : ''}`)}</span>
+ 'tree-header-title-selected' : props.selectedNode === nodeFilters.ALL})}>{i18n(`${props.headerTitle} ${hasErrors ? '(Draft)' : ''}`)}</span>
</div>
<ErrorsAndWarningsCount errorList={props.errorList} size='large' />
</div>);
@@ -134,7 +134,7 @@ class HeatFileTree extends React.Component {
<div key={node.name + rand} className={classNames({'tree-block-inside' : !node.header})}>
{
node.header ?
- <HeatFileTreeHeader selectedNode={selectedNode} errorList={this.props.errorList} selectNode={(nodeName) => this.selectNode(nodeName)} /> :
+ <HeatFileTreeHeader headerTitle={node.name} selectedNode={selectedNode} errorList={this.props.errorList} selectNode={(nodeName) => this.selectNode(nodeName)} /> :
<HeatFileTreeRow toggleExpanded={this.props.toggleExpanded} node={node} path={path} selectedNode={selectedNode} selectNode={() => this.selectNode(node.name)} />
}
{
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx
index 11f3543e39..c7ab3e644c 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx
@@ -186,12 +186,12 @@ const OnboardingProcedure = ({onboardingMethod, onDataChanged, genericFieldInfo}
<GridSection title={i18n('Onboarding procedure')}>
<GridItem colSpan={4}>
<Input
- label={i18n('HEAT file')}
+ label={i18n('Network Package')}
overlayPos='top'
isValid={genericFieldInfo.onboardingMethod.isValid}
- checked={onboardingMethod === onboardingMethodConst.HEAT}
+ checked={onboardingMethod === onboardingMethodConst.NETWORK_PACKAGE}
errorText={genericFieldInfo.onboardingMethod.errorText}
- onChange={() => onDataChanged({onboardingMethod:'HEAT'},SP_CREATION_FORM_NAME)}
+ onChange={() => onDataChanged({onboardingMethod: onboardingMethodConst.NETWORK_PACKAGE},SP_CREATION_FORM_NAME)}
type='radio'
data-test-id='new-vsp-creation-procedure-heat' />
</GridItem>
@@ -202,7 +202,7 @@ const OnboardingProcedure = ({onboardingMethod, onDataChanged, genericFieldInfo}
checked={onboardingMethod === onboardingMethodConst.MANUAL}
isValid={genericFieldInfo.onboardingMethod.isValid}
errorText={genericFieldInfo.onboardingMethod.errorText}
- onChange={() => onDataChanged({onboardingMethod:'Manual'},SP_CREATION_FORM_NAME)}
+ onChange={() => onDataChanged({onboardingMethod: onboardingMethodConst.MANUAL},SP_CREATION_FORM_NAME)}
type='radio'
data-test-id='new-vsp-creation-procedure-manual' />
</GridItem>
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 8806ffd0bf..a13e742006 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js
@@ -53,7 +53,7 @@ export const mapStateToProps = ({softwareProduct, licenseModel: {licenseAgreemen
fullCategoryDisplayName
},
isReadOnlyMode,
- componentsList,
+ componentsList,
isManual: currentSoftwareProduct.onboardingMethod === onboardingMethod.MANUAL
};
};
@@ -65,7 +65,6 @@ const mapActionsToProps = (dispatch, {version}) => {
licenseModelId,
version
}),
- onAttachmentsSelect: ({id: softwareProductId}) => OnboardingActionHelper.navigateToSoftwareProductAttachments(dispatch, {softwareProductId, version}),
onUpload: (softwareProductId, formData) =>
SoftwareProductActionHelper.uploadFile(dispatch, {
softwareProductId,
@@ -98,7 +97,7 @@ const mapActionsToProps = (dispatch, {version}) => {
data: {
title: i18n('Upload Failed'),
confirmationButtonText: i18n('Continue'),
- msg: i18n('no zip file was uploaded or zip file doesn\'t exist')
+ msg: i18n('no zip or csar file was uploaded or expected file doesn\'t exist')
}
}),
onComponentSelect: ({id: softwareProductId, componentId}) => {
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 7ffbeda4dc..72a416473c 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx
@@ -57,7 +57,6 @@ class SoftwareProductLandingPageView extends React.Component {
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,
@@ -78,15 +77,13 @@ class SoftwareProductLandingPageView extends React.Component {
disableClick={true}
ref='fileInput'
name='fileInput'
- accept='.zip'
+ accept='.zip, .csar'
disabled>
<div className='draggable-wrapper'>
<div className='software-product-landing-view-top'>
<div className='row'>
<ProductSummary currentSoftwareProduct={currentSoftwareProduct} onDetailsSelect={onDetailsSelect} />
- {isManual ?
- <div className='details-panel'/>
- : this.renderProductDetails(currentSoftwareProduct, isReadOnlyMode)}
+ {this.renderProductDetails(isManual, isReadOnlyMode)}
</div>
</div>
</div>
@@ -106,34 +103,18 @@ class SoftwareProductLandingPageView extends React.Component {
}
}
- renderProductDetails(currentSoftwareProduct, isReadOnlyMode) {
- let {validationData} = currentSoftwareProduct;
- let {onAttachmentsSelect} = this.props;
- let details = {
- heatTemplates: validationData ? '1' : '0',
- images: '0',
- otherArtifacts: '0'
- };
-
+ renderProductDetails(isManual, isReadOnlyMode) {
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>
+ { !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()}/>
</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>
);
}