diff options
Diffstat (limited to 'openecomp-ui')
50 files changed, 1767 insertions, 505 deletions
diff --git a/openecomp-ui/package.json b/openecomp-ui/package.json index 70c86cc50a..6cd9f724ad 100644 --- a/openecomp-ui/package.json +++ b/openecomp-ui/package.json @@ -11,13 +11,17 @@ "static-keys-bundle": "gulp static-keys-bundle", "check-keys-against-bundles": "gulp static-keys-bundle-with-report", "test": "jest", - "test-failedTestReport": "jest --json | node test-utils/failedTestReport.js", + "test-failedTestReport": + "jest --json | node test-utils/failedTestReport.js", "test-dev": "jest --watch", - "test-coverage": "jest --coverage && start ./coverage/lcov-report/index.html", + "test-coverage": + "jest --coverage && start ./coverage/lcov-report/index.html", "test-build": "jest --coverage", - "storybook": "start-storybook -p 9090 -c .storybook -s .storybook/fonts", + "storybook": + "start-storybook -p 9090 -c .storybook -s .storybook/fonts", "storyshots": "jest storyshots.test.js", - "build-storybook": "build-storybook -c .storybook -o .storybook-dist && gulp copy-storybook-fonts", + "build-storybook": + "build-storybook -c .storybook -o .storybook-dist && gulp copy-storybook-fonts", "lint-fix": "eslint --fix --ext .js --ext .jsx src" }, "dependencies": { @@ -49,7 +53,7 @@ "react-show-more": "^1.1.1", "react-sortable": "^1.2.0", "redux": "^3.7.2", - "sdc-ui": "1.6.24", + "sdc-ui": "1.6.27", "uuid-js": "^0.7.5", "validator": "^4.3.0" }, @@ -121,10 +125,12 @@ }, "jest": { "moduleNameMapper": { - "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/test-utils/fileMock.js", + "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": + "<rootDir>/test-utils/fileMock.js", "\\.(css|scss)$": "<rootDir>/test-utils/styleMock.js", "^nfvo-utils/RestAPIUtil.js$": "<rootDir>/test-utils/MockRest.js", - "^sdc-ui/lib/react/SVGIcon.js$": "<rootDir>/test-utils/MockSVGIcon.js", + "^sdc-ui/lib/react/SVGIcon.js$": + "<rootDir>/test-utils/MockSVGIcon.js", "^react-show-more$": "<rootDir>/test-utils/ShowMore.js", "^nfvo-utils(.*)$": "<rootDir>/src/nfvo-utils$1", "^nfvo-components(.*)$": "<rootDir>/src/nfvo-components$1", @@ -136,23 +142,14 @@ "globals": { "DEBUG": false }, - "setupFiles": [ - "<rootDir>/test-utils/test-env-setup.js" - ], + "setupFiles": ["<rootDir>/test-utils/test-env-setup.js"], "setupTestFrameworkScriptFile": "<rootDir>/test-utils/test-setup.js", "testPathIgnorePatterns": [ "<rootDir>/node_modules/", "<rootDir>/test/nfvo-components/storyshots.test.js" ], - "collectCoverageFrom": [ - "src/**/*.{js,jsx}" - ], - "coveragePathIgnorePatterns": [ - "/node_modules/", - "(.)*.stories.js" - ], - "coverageReporters": [ - "lcov" - ] + "collectCoverageFrom": ["src/**/*.{js,jsx}"], + "coveragePathIgnorePatterns": ["/node_modules/", "(.)*.stories.js"], + "coverageReporters": ["lcov"] } } diff --git a/openecomp-ui/resources/scss/_components.scss b/openecomp-ui/resources/scss/_components.scss index ce5c732b3d..e18b2603e9 100644 --- a/openecomp-ui/resources/scss/_components.scss +++ b/openecomp-ui/resources/scss/_components.scss @@ -21,7 +21,6 @@ @import "components/commitModal"; @import "components/userNotifications"; @import "components/overlay"; -@import "components/accordion"; @import "components/vspDetailsVendorSelect"; %noselect { diff --git a/openecomp-ui/resources/scss/components/_accordion.scss b/openecomp-ui/resources/scss/components/_accordion.scss deleted file mode 100644 index c96bc71be5..0000000000 --- a/openecomp-ui/resources/scss/components/_accordion.scss +++ /dev/null @@ -1,28 +0,0 @@ -.accordion { - display: flex; - flex-direction: column; - .accordion-header { - display: flex; - flex-direction: row; - cursor: pointer; - margin-bottom: 10px; - .svg-icon-wrapper { - margin-right: 20px; - transition: transform .4s; - &.down { - transform: rotate(180deg); - } - } - } - .accordion-body { - padding-left: 10px; - opacity: 0; - overflow-y: hidden; - max-height: 0; - transition: max-height .3s cubic-bezier(0, 1.18, 1, 1), opacity 0.33s linear; - &.open { - opacity: 1; - max-height: 100%; - } - } -}
\ No newline at end of file diff --git a/openecomp-ui/resources/scss/modules/onboardingCatalog/_catalogFilter.scss b/openecomp-ui/resources/scss/modules/onboardingCatalog/_catalogFilter.scss index cda47c6340..a7a7628249 100644 --- a/openecomp-ui/resources/scss/modules/onboardingCatalog/_catalogFilter.scss +++ b/openecomp-ui/resources/scss/modules/onboardingCatalog/_catalogFilter.scss @@ -1,16 +1,22 @@ .catalog-filter { - width: 242px; - overflow-y: auto; - height: 100%; - box-shadow: 1px 0px 4px 0px rgba(24, 24, 25, 0.17); - background-color: $white; - padding: 12px 18px; - .form-group { - margin-bottom: 10px; + .catalog-filter-by-vendor-view { + margin-left: 18px; + margin-right: 18px; + } + .empty-block { + height: 34px; + width: 100%; } .catalog-filter-items-type { width: 100%; - background-color: $gray; - color: $white; + background-color: $tlv-light-gray; + height: 34px; + } + .sdc-accordion { + padding-left: 18px; + padding-right: 18px; + } + .first-line { + margin-top: 40px; } -}
\ No newline at end of file +} diff --git a/openecomp-ui/resources/scss/modules/onboardingCatalog/_catalogList.scss b/openecomp-ui/resources/scss/modules/onboardingCatalog/_catalogList.scss index 071268c50d..11a739d004 100644 --- a/openecomp-ui/resources/scss/modules/onboardingCatalog/_catalogList.scss +++ b/openecomp-ui/resources/scss/modules/onboardingCatalog/_catalogList.scss @@ -24,6 +24,14 @@ display: block; width: 100%; } + .venodor-tile-btn { + border: 1px solid $light-gray; + color: $black; + line-height: 20px; + &:hover { + background-color: $light-gray; + } + } } // Bottom spacing - cross browser solution diff --git a/openecomp-ui/src/nfvo-components/accordion/Accordion.jsx b/openecomp-ui/src/nfvo-components/accordion/Accordion.jsx deleted file mode 100644 index 72f8de0d23..0000000000 --- a/openecomp-ui/src/nfvo-components/accordion/Accordion.jsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright © 2016-2018 European Support Limited - * - * 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 SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; -import PropTypes from 'prop-types'; - -class Accordion extends React.Component { - static propTypes = { - title: PropTypes.string, - children: PropTypes.node - }; - - constructor(props) { - super(props); - this.state = { - open: false - }; - } - render() { - const { children, title } = this.props; - const { open } = this.state; - return ( - <div className="accordion"> - <div - onClick={() => this.setState({ open: !open })} - className="accordion-header"> - <SVGIcon - name="chevronUp" - iconClassName={open ? 'down' : ''} - /> - <div className="title">{title}</div> - </div> - <div className={`accordion-body ${open ? 'open' : ''}`}> - {children} - </div> - </div> - ); - } -} - -export default Accordion; diff --git a/openecomp-ui/src/nfvo-utils/i18n/en.json b/openecomp-ui/src/nfvo-utils/i18n/en.json index 347a8ed71c..cbc2031b4b 100644 --- a/openecomp-ui/src/nfvo-utils/i18n/en.json +++ b/openecomp-ui/src/nfvo-utils/i18n/en.json @@ -83,7 +83,8 @@ "This software product successfully submitted": "This software product successfully submitted", "Submit Failed": "Submit Failed", "Vendor Name": "Vendor Name", - "License model by the name \\": "License model by the name \\", + "License model by the name": "License model by the name", + "License model name must be unique": "License model name must be unique", "please select…": "please select…", "Warning": "Warning", "Operational Scope": "Operational Scope", @@ -160,7 +161,9 @@ "Vendor": "Vendor", "Category": "Category", "please select...": "please select...", - "Software product by the name \\": "Software product by the name \\", + "Software product by the name": "Software product by the name", + "Software product name must be unique": "Software product name must be unique", + "already exists": "already exists", "Onboarding procedure": "Onboarding procedure", "HEAT file": "HEAT file", "Manual": "Manual", @@ -356,7 +359,12 @@ "Granted": "Granted", "Taken": "Taken", "Permission": "Permission", - + "By Vendor View": "By Vendor View", + "PERMISSIONS": "PERMISSIONS", + "Contributor": "Contributor", + "Active Items": "Active Items", + "Archived Items": "Archived Items", + "VendorSoftwareProduct": "VSP", "VendorSoftwareProduct/category": "Category", "VendorSoftwareProduct/description": "Description", diff --git a/openecomp-ui/src/nfvo-utils/objectPropsToUrlString.js b/openecomp-ui/src/nfvo-utils/objectPropsToUrlString.js new file mode 100644 index 0000000000..6c18bb6111 --- /dev/null +++ b/openecomp-ui/src/nfvo-utils/objectPropsToUrlString.js @@ -0,0 +1,23 @@ +export default function objectPropsToUrlString(data) { + let str = ''; + Object.keys(data).map(key => { + if (typeof data[key] === 'object') { + let obj = data[key]; + let arr = []; + + Object.keys(obj).map(prop => { + if (obj[prop]) { + arr.push(encodeURIComponent(prop)); + } + }); + if (arr.length) { + str += `&${encodeURIComponent(key)}=${arr.join(',')}`; + } + } else if (data[key]) { + str += `&${encodeURIComponent(key)}=${encodeURIComponent( + data[key] + )}`; + } + }); + return str; +} diff --git a/openecomp-ui/src/sdc-app/AppStore.js b/openecomp-ui/src/sdc-app/AppStore.js index bca750a930..5cab6ae561 100644 --- a/openecomp-ui/src/sdc-app/AppStore.js +++ b/openecomp-ui/src/sdc-app/AppStore.js @@ -16,17 +16,20 @@ import { createStore, applyMiddleware, compose } from 'redux'; import Reducers from './Reducers.js'; +import filterUpdater from 'sdc-app/onboarding/onboard/filter/FilterMiddleware.js'; + const thunk = store => next => action => typeof action === 'function' ? action(store.dispatch, store.getState) : next(action); const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; + export const storeCreator = initialState => createStore( Reducers, initialState, - composeEnhancers(applyMiddleware(thunk)) + composeEnhancers(applyMiddleware(thunk, filterUpdater)) ); const store = storeCreator(); diff --git a/openecomp-ui/src/sdc-app/common/helpers/ItemsHelper.js b/openecomp-ui/src/sdc-app/common/helpers/ItemsHelper.js index 99ecae9887..ae5c2707b6 100644 --- a/openecomp-ui/src/sdc-app/common/helpers/ItemsHelper.js +++ b/openecomp-ui/src/sdc-app/common/helpers/ItemsHelper.js @@ -1,36 +1,32 @@ -/*! - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. +/* + * Copyright © 2016-2018 European Support Limited * * 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 - * + * + * 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. + * 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 { permissionTypes } from 'sdc-app/onboarding/permissions/PermissionsConstants.js'; import { actionsEnum as VersionControllerActionsEnum } from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; import { actionTypes as onboardingActionTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; -import restToggle from 'sdc-app/features/restToggle.js'; +import { restToggle } from 'sdc-app/features/featureToggleUtils.js'; import { featureToggleNames } from 'sdc-app/features/FeaturesConstants.js'; +import objectPropsToUrlString from 'nfvo-utils/objectPropsToUrlString.js'; + export const archiveActions = { ARCHIVE: 'ARCHIVE', RESTORE: 'RESTORE' }; -export const itemStatus = { - ARCHIVED: 'ARCHIVED', - DRAFT: 'Draft', - CERTIFIED: 'Certified' -}; - function baseUrl() { const restPrefix = Configuration.get('restPrefix'); return `${restPrefix}/v1.0/items`; @@ -118,6 +114,15 @@ const ItemsHelper = { return RestAPIUtil.put(`${baseUrl()}/${itemId}/actions`, { action: archiveActions.RESTORE }); + }, + + fetchItems(filterData) { + const str = objectPropsToUrlString(filterData); + return restToggle({ + restFunction: () => RestAPIUtil.fetch(`${baseUrl()}?${str}`), + featureName: featureToggleNames.FILTER, + mockResult: { results: [] } + }); } }; diff --git a/openecomp-ui/src/sdc-app/common/helpers/ItemsHelperConstants.js b/openecomp-ui/src/sdc-app/common/helpers/ItemsHelperConstants.js new file mode 100644 index 0000000000..ebbbfded3b --- /dev/null +++ b/openecomp-ui/src/sdc-app/common/helpers/ItemsHelperConstants.js @@ -0,0 +1,29 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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. + */ +export const itemStatus = { + ACTIVE: 'ACTIVE', + ARCHIVED: 'ARCHIVED' +}; + +export const versionStatus = { + DRAFT: 'Draft', + CERTIFIED: 'Certified' +}; + +export const itemType = { + VSP: 'vsp', + VLM: 'vlm' +}; diff --git a/openecomp-ui/src/sdc-app/common/helpers/UniqueTypesHelper.js b/openecomp-ui/src/sdc-app/common/helpers/UniqueTypesHelper.js new file mode 100644 index 0000000000..de84f91bae --- /dev/null +++ b/openecomp-ui/src/sdc-app/common/helpers/UniqueTypesHelper.js @@ -0,0 +1,69 @@ +/*! + * Copyright © 2016-2018 European Support Limited + * + * 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 ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; +import { featureToggleNames } from 'sdc-app/features/FeaturesConstants.js'; +import { restToggle } from 'sdc-app/features/featureToggleUtils.js'; + +const itemTypesMapper = { + vsp: 'VspName', + vlm: 'VlmName' +}; + +function baseUrl() { + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/unique-types/`; +} + +function uniqueValue(type, value) { + return restToggle({ + restFunction: () => + RestAPIUtil.fetch(`${baseUrl()}${type}/values/${value}`), + featureName: featureToggleNames.FILTER, + mockResult: { occupied: false } + }); +} + +export default { + async isNameUnique( + dispatch, + { value, name, formName, errorText, itemType } + ) { + const { occupied } = await uniqueValue( + itemTypesMapper[itemType], + value + ); + const validation = occupied + ? { + isValid: false, + errorText + } + : { isValid: true, errorText: '' }; + + let deltaData = {}; + deltaData[name] = value; + let customValidations = {}; + customValidations[name] = () => validation; + + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName, + customValidations + }); + } +}; diff --git a/openecomp-ui/src/sdc-app/features/featureToggle.js b/openecomp-ui/src/sdc-app/features/featureToggle.js index d33c76e523..861db6ae9c 100644 --- a/openecomp-ui/src/sdc-app/features/featureToggle.js +++ b/openecomp-ui/src/sdc-app/features/featureToggle.js @@ -38,12 +38,14 @@ import { connect } from 'react-redux'; export const FeatureComponent = props => { const { features = [], featureName, InnerComponent, ...otherProps } = props; - const AComp = InnerComponent.AComp ? InnerComponent.AComp : InnerComponent; + const OnComp = InnerComponent.OnComp + ? InnerComponent.OnComp + : InnerComponent; return !!features.find(el => el.name === featureName && el.active) ? ( - <AComp {...otherProps} /> - ) : InnerComponent.BComp ? ( - <InnerComponent.BComp {...otherProps} /> + <OnComp {...otherProps} /> + ) : InnerComponent.OffComp ? ( + <InnerComponent.OffComp {...otherProps} /> ) : null; }; diff --git a/openecomp-ui/src/sdc-app/features/restToggle.js b/openecomp-ui/src/sdc-app/features/featureToggleUtils.js index 505dace4e7..1263336fd3 100644 --- a/openecomp-ui/src/sdc-app/features/restToggle.js +++ b/openecomp-ui/src/sdc-app/features/featureToggleUtils.js @@ -16,9 +16,16 @@ import store from 'sdc-app/AppStore.js'; -export default ({ featureName, restFunction, mockResult }) => { +export const restToggle = ({ featureName, restFunction, mockResult }) => { const { features } = store.getState(); return !!features.find(el => el.name === featureName && el.active) ? restFunction() : Promise.resolve(mockResult); }; + +export const functionToggle = (featureName, { onFunction, offFunction }) => { + const { features } = store.getState(); + return !!features.find(el => el.name === featureName && el.active) + ? onFunction() + : offFunction(); +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js index 2fccfcbd2a..b8ce714bce 100644 --- a/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js @@ -45,6 +45,8 @@ import SoftwareProductComponentsImageActionHelper from './softwareProduct/compon import licenseModelOverviewActionHelper from 'sdc-app/onboarding/licenseModel/overview/licenseModelOverviewActionHelper.js'; import { tabsMapping as attachmentsTabsMapping } from 'sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsConstants.js'; import SoftwareProductAttachmentsActionHelper from 'sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsActionHelper.js'; +import { actionTypes as filterActionTypes } from './onboard/filter/FilterConstants.js'; +import FeaturesActionHelper from 'sdc-app/features/FeaturesActionHelper.js'; function setCurrentScreen(dispatch, screen, props = {}) { dispatch({ @@ -74,11 +76,16 @@ const OnboardingActionHelper = { SoftwareProductActionHelper.fetchArchivedSoftwareProductList(dispatch); }, - navigateToOnboardingCatalog(dispatch) { + async navigateToOnboardingCatalog(dispatch) { + await FeaturesActionHelper.getFeaturesList(dispatch); UsersActionHelper.fetchUsersList(dispatch); this.loadItemsLists(dispatch); OnboardActionHelper.resetOnboardStore(dispatch); setCurrentScreen(dispatch, enums.SCREEN.ONBOARDING_CATALOG); + dispatch({ + type: filterActionTypes.FILTER_DATA_CHANGED, + deltaData: {} + }); }, autoSaveBeforeNavigate( @@ -207,6 +214,7 @@ const OnboardingActionHelper = { { softwareProductId, version, status } ) { SoftwareProductComponentsActionHelper.clearComponentsStore(dispatch); + LicenseModelActionHelper.fetchFinalizedLicenseModels(dispatch); SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, { softwareProductId, version @@ -559,7 +567,7 @@ const OnboardingActionHelper = { ); }, - navigateToVersionsPage( + async navigateToVersionsPage( dispatch, { itemType, itemId, itemName, additionalProps, users } ) { @@ -568,19 +576,19 @@ const OnboardingActionHelper = { allUsers: users }); VersionsPageActionHelper.selectNone(dispatch); - VersionsPageActionHelper.fetchVersions(dispatch, { + await VersionsPageActionHelper.fetchVersions(dispatch, { itemType, itemId - }).then(() => { - ItemsHelper.fetchItem(itemId).then(result => { - setCurrentScreen(dispatch, enums.SCREEN.VERSIONS_PAGE, { - status: result.status, - itemType, - itemId, - itemName, - additionalProps - }); - }); + }); + const items = await ItemsHelper.fetchItem(itemId); + setCurrentScreen(dispatch, enums.SCREEN.VERSIONS_PAGE, { + status: items.status, + itemType, + itemId, + itemName, + vendorName: items.properties.vendorName, + vendorId: items.properties.vendorId, + additionalProps }); }, diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx b/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx index f462dd790b..245dd2b55c 100644 --- a/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx @@ -21,8 +21,6 @@ import ReactDOM from 'react-dom'; import isEqual from 'lodash/isEqual.js'; -import lodashUnionBy from 'lodash/unionBy.js'; - import i18n from 'nfvo-utils/i18n/i18n.js'; import Application from 'sdc-app/Application.jsx'; import store from 'sdc-app/AppStore.js'; @@ -356,10 +354,6 @@ export default class OnboardingPunchOut { handleStoreChange() { let { currentScreen, - licenseModelList, - finalizedLicenseModelList, - softwareProductList, - finalizedSoftwareProductList, versionsPage: { versionsList: { itemType, itemId } }, softwareProduct: { softwareProductEditor: { @@ -367,26 +361,17 @@ export default class OnboardingPunchOut { }, softwareProductComponents: { componentsList } }, - archivedLicenseModelList, - archivedSoftwareProductList + licenseModel: { + licenseModelEditor: { data: currentLicenseModel = {} } + } } = store.getState(); - const wholeSoftwareProductList = lodashUnionBy( - softwareProductList, - [...finalizedSoftwareProductList, ...archivedSoftwareProductList], - 'id' - ); - const wholeLicenseModelList = lodashUnionBy( - licenseModelList, - [...finalizedLicenseModelList, ...archivedLicenseModelList], - 'id' - ); + let breadcrumbsData = { itemType, itemId, currentScreen, - wholeLicenseModelList, - wholeSoftwareProductList, currentSoftwareProduct, + currentLicenseModel, componentsList }; @@ -415,8 +400,7 @@ export default class OnboardingPunchOut { itemType, itemId, currentSoftwareProduct, - wholeLicenseModelList, - wholeSoftwareProductList, + currentLicenseModel, componentsList }) { let { @@ -435,12 +419,12 @@ export default class OnboardingPunchOut { ? [ { selectedKey: itemId, - menuItems: wholeLicenseModelList.map( - ({ id, name }) => ({ - key: id, - displayText: name - }) - ) + menuItems: [ + { + key: itemId, + displayText: props.itemName + } + ] } ] : [ @@ -448,12 +432,12 @@ export default class OnboardingPunchOut { selectedKey: props.additionalProps.licenseModelId || currentSoftwareProduct.vendorId, - menuItems: wholeLicenseModelList.map( - ({ id, name }) => ({ - key: id, - displayText: name - }) - ) + menuItems: [ + { + key: props.vendorId, + displayText: props.vendorName + } + ] }, { selectedKey: @@ -472,17 +456,12 @@ export default class OnboardingPunchOut { }, { selectedKey: itemId, - menuItems: wholeSoftwareProductList - .filter( - ({ id, vendorId }) => - vendorId === - currentSoftwareProduct.vendorId || - id === itemId - ) - .map(({ id, name }) => ({ - key: id, - displayText: name - })) + menuItems: [ + { + key: itemId, + displayText: props.itemName + } + ] } ]; return [ @@ -519,13 +498,13 @@ export default class OnboardingPunchOut { }; return [ { - selectedKey: props.licenseModelId, - menuItems: wholeLicenseModelList.map( - ({ id, name }) => ({ - key: id, - displayText: name - }) - ) + selectedKey: currentLicenseModel.id, + menuItems: [ + { + key: currentLicenseModel.id, + displayText: currentLicenseModel.vendorName + } + ] }, { selectedKey: enums.BREADCRUMS.LICENSE_MODEL, @@ -533,19 +512,7 @@ export default class OnboardingPunchOut { { key: enums.BREADCRUMS.LICENSE_MODEL, displayText: i18n('License Model') - }, - ...(wholeSoftwareProductList.findIndex( - ({ vendorId }) => - vendorId === props.licenseModelId - ) === -1 - ? [] - : [ - { - key: - enums.BREADCRUMS.SOFTWARE_PRODUCT, - displayText: i18n('Software Products') - } - ]) + } ] }, { @@ -636,16 +603,16 @@ export default class OnboardingPunchOut { [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_MONITORING }; - let licenseModelId = currentSoftwareProduct.vendorId; + let returnedBreadcrumb = [ { - selectedKey: licenseModelId, - menuItems: wholeLicenseModelList.map( - ({ id, name }) => ({ - key: id, - displayText: name - }) - ) + selectedKey: currentSoftwareProduct.vendorId, + menuItems: [ + { + key: currentSoftwareProduct.vendorId, + displayText: currentSoftwareProduct.vendorName + } + ] }, { selectedKey: enums.BREADCRUMS.SOFTWARE_PRODUCT, @@ -661,17 +628,13 @@ export default class OnboardingPunchOut { ] }, { - selectedKey: props.softwareProductId, - menuItems: wholeSoftwareProductList - .filter( - ({ vendorId, id }) => - vendorId === licenseModelId || - id === props.softwareProductId - ) - .map(({ id, name }) => ({ - key: id, - displayText: name - })) + selectedKey: currentSoftwareProduct.id, + menuItems: [ + { + key: currentSoftwareProduct.id, + displayText: currentSoftwareProduct.name + } + ] }, .../*screen === enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE ? [] :*/ [ { diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingReducersMap.js b/openecomp-ui/src/sdc-app/onboarding/OnboardingReducersMap.js index 3b526a67f6..09f4ffb930 100644 --- a/openecomp-ui/src/sdc-app/onboarding/OnboardingReducersMap.js +++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingReducersMap.js @@ -28,7 +28,7 @@ import usersReducer from './users/UsersReducers.js'; import mergeEditorReducer from 'sdc-app/common/merge/MergeEditorReducer.js'; import revisionsReducer from './revisions/RevisionsReducer.js'; import featuresReducer from 'sdc-app/features/FeaturesReducer.js'; - +import itemsReducer from 'sdc-app/onboarding/onboard/filter/ItemsReducer.js'; export default { currentScreen: currentScreenReducer, licenseModel: licenseModelReducer, @@ -44,5 +44,6 @@ export default { users: usersReducer, versionsPage: versionsPageReducer, revisions: revisionsReducer, - features: featuresReducer + features: featuresReducer, + filteredItems: itemsReducer }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js index cfff9f1fcd..be33af7910 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js @@ -29,8 +29,11 @@ import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; import { CommitModalType } from 'nfvo-components/panel/versionController/components/CommitCommentModal.jsx'; import versionPageActionHelper from 'sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js'; import { itemTypes } from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; -import { catalogItemStatuses } from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js'; import { actionsEnum as VersionControllerActionsEnum } from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; +import { + itemStatus, + versionStatus +} from 'sdc-app/common/helpers/ItemsHelperConstants.js'; function baseUrl() { const restPrefix = Configuration.get('restPrefix'); @@ -39,19 +42,17 @@ function baseUrl() { function fetchLicenseModels() { return RestAPIUtil.fetch( - `${baseUrl()}?versionFilter=${catalogItemStatuses.DRAFT}` + `${baseUrl()}?versionFilter=${versionStatus.DRAFT}` ); } function fetchFinalizedLicenseModels() { return RestAPIUtil.fetch( - `${baseUrl()}?versionFilter=${catalogItemStatuses.CERTIFIED}` + `${baseUrl()}?versionFilter=${versionStatus.CERTIFIED}` ); } function fetchArchivedLicenseModels() { - return RestAPIUtil.fetch( - `${baseUrl()}?Status=${catalogItemStatuses.ARCHIVED}` - ); + return RestAPIUtil.fetch(`${baseUrl()}?Status=${itemStatus.ARCHIVED}`); } function fetchLicenseModelById(licenseModelId, version) { const { id: versionId } = version; @@ -206,9 +207,8 @@ const LicenseModelActionHelper = { version }).then(({ inMerge, isDirty, updatedVersion }) => { if ( - (updatedVersion.status === catalogItemStatuses.CERTIFIED || - updatedVersion.archivedStatus === - catalogItemStatuses.ARCHIVED) && + (updatedVersion.status === versionStatus.CERTIFIED || + updatedVersion.archivedStatus === versionStatus.ARCHIVED) && (action === VersionControllerActionsEnum.COMMIT || action === VersionControllerActionsEnum.SYNC) ) { @@ -217,8 +217,7 @@ const LicenseModelActionHelper = { itemId: licenseModelId }); const msg = - updatedVersion.archivedStatus === - catalogItemStatuses.ARCHIVED + updatedVersion.archivedStatus === versionStatus.ARCHIVED ? i18n('Item was Archived') : i18n('Item version already Certified'); dispatch({ diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreation.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreation.js index 4bbab865fa..c6a0702a57 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreation.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreation.js @@ -14,8 +14,12 @@ * limitations under the License. */ import { connect } from 'react-redux'; +import featureToggle from 'sdc-app/features/featureToggle.js'; +import { featureToggleNames } from 'sdc-app/features/FeaturesConstants.js'; import LicenseModelCreationActionHelper from './LicenseModelCreationActionHelper.js'; import LicenseModelCreationView from './LicenseModelCreationView.jsx'; +import LicenseModelCreationViewWithFilter from './LicenseModelCreationViewWithFilter.jsx'; + import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js'; import VersionsPageActionHelper from 'sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js'; @@ -23,6 +27,16 @@ import { itemTypes as versionItemTypes } from 'sdc-app/onboarding/versionsPage/V import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import PermissionsActionHelper from 'sdc-app/onboarding/permissions/PermissionsActionHelper.js'; +import UniqueTypesHelper from 'sdc-app/common/helpers/UniqueTypesHelper.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import { itemType } from 'sdc-app/common/helpers/ItemsHelperConstants.js'; + +const ToggledLicenseModelCreationView = featureToggle( + featureToggleNames.FILTER +)({ + OnComp: LicenseModelCreationViewWithFilter, + OffComp: LicenseModelCreationView +}); export const mapStateToProps = ({ users: { usersList }, @@ -87,10 +101,22 @@ export const mapActionsToProps = dispatch => { }); }, onValidateForm: formName => - ValidationHelper.validateForm(dispatch, formName) + ValidationHelper.validateForm(dispatch, formName), + isNameUnique: (value, name, formName) => + UniqueTypesHelper.isNameUnique(dispatch, { + value, + name, + formName, + errorText: `${i18n( + 'License model by the name' + )} ${value} ${i18n('already exists')}. ${i18n( + 'License model name must be unique' + )}`, + itemType: itemType.VLM + }) }; }; export default connect(mapStateToProps, mapActionsToProps)( - LicenseModelCreationView + ToggledLicenseModelCreationView ); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationReducer.js index 7137230cc7..5922a47822 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationReducer.js @@ -40,7 +40,8 @@ export default (state = {}, action) => { errorText: '', validations: [ { type: 'required', data: true }, - { type: 'maxLength', data: 25 } + { type: 'maxLength', data: 25 }, + { type: 'validateName', data: true } ] } } diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationViewWithFilter.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationViewWithFilter.jsx new file mode 100644 index 0000000000..8c5d966938 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationViewWithFilter.jsx @@ -0,0 +1,116 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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 PropTypes from 'prop-types'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Input from 'nfvo-components/input/validation/Input.jsx'; +import Form from 'nfvo-components/input/validation/Form.jsx'; +import { LICENSE_MODEL_CREATION_FORM_NAME } from './LicenseModelCreationConstants.js'; + +const LicenseModelPropType = PropTypes.shape({ + id: PropTypes.string, + vendorName: PropTypes.string, + description: PropTypes.string +}); + +class LicenseModelCreationView extends React.Component { + static propTypes = { + data: LicenseModelPropType, + VLMNames: PropTypes.object, + usersList: PropTypes.array, + onDataChanged: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + onValidateForm: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired + }; + + render() { + let { data = {}, onDataChanged, genericFieldInfo } = this.props; + let { vendorName, description } = data; + return ( + <div> + {genericFieldInfo && ( + <Form + ref="validationForm" + hasButtons={true} + onSubmit={() => this.submit()} + submitButtonText={i18n('Create')} + onReset={() => this.props.onCancel()} + labledButtons={true} + isValid={this.props.isFormValid} + formReady={this.props.formReady} + onValidateForm={() => this.validate()}> + <Input + value={vendorName} + label={i18n('Vendor Name')} + data-test-id="vendor-name" + onChange={vendorName => + onDataChanged( + { vendorName }, + LICENSE_MODEL_CREATION_FORM_NAME + ) + } + onBlur={e => + this.validateIsNameUnique(e.target.value) + } + isValid={genericFieldInfo.vendorName.isValid} + errorText={genericFieldInfo.vendorName.errorText} + type="text" + isRequired={true} + className="field-section" + /> + <Input + isRequired={true} + value={description} + label={i18n('Description')} + data-test-id="vendor-description" + overlayPos="bottom" + onChange={description => + onDataChanged( + { description }, + LICENSE_MODEL_CREATION_FORM_NAME + ) + } + isValid={genericFieldInfo.description.isValid} + errorText={genericFieldInfo.description.errorText} + type="textarea" + className="field-section" + /> + </Form> + )} + </div> + ); + } + + submit() { + const { data: licenseModel, usersList } = this.props; + this.props.onSubmit(licenseModel, usersList); + } + + validateIsNameUnique(value) { + this.props.isNameUnique( + value, + 'vendorName', + LICENSE_MODEL_CREATION_FORM_NAME + ); + } + + validate() { + this.props.onValidateForm(LICENSE_MODEL_CREATION_FORM_NAME); + } +} + +export default LicenseModelCreationView; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.stories.js b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.stories.js index d01b9d0d04..c0de0eeb79 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.stories.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.stories.js @@ -2,11 +2,9 @@ import React from 'react'; import { storiesOf, action } from '@kadira/storybook'; import { select, withKnobs } from '@kadira/storybook-addon-knobs'; import CatalogItemDetails from './CatalogItemDetails.jsx'; -import { - catalogItemTypes, - catalogItemStatuses -} from './onboardingCatalog/OnboardingCatalogConstants.js'; +import { catalogItemTypes } from './onboardingCatalog/OnboardingCatalogConstants.js'; import { FinalizedLicenseModelFactory } from 'test-utils/factories/licenseModel/LicenseModelFactories.js'; +import { versionStatus } from 'sdc-app/common/helpers/ItemsHelperConstants.js'; const stories = storiesOf('CatalogTiles', module); stories.addDecorator(withKnobs); @@ -22,9 +20,9 @@ function selectType() { let vlm = { ...FinalizedLicenseModelFactory.build({ name: 'Test-VLM' }), - itemStatus: catalogItemStatuses.DRAFT + itemStatus: versionStatus.DRAFT }; -let certifiedVlm = { ...vlm, itemStatus: catalogItemStatuses.CERTIFIED }; +let certifiedVlm = { ...vlm, itemStatus: versionStatus.CERTIFIED }; stories.add('preview', () => ( <div className="catalog-view"> diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/DetailsCatalogView.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/DetailsCatalogView.jsx index 771c0eb6c1..b535595355 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/DetailsCatalogView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/DetailsCatalogView.jsx @@ -13,6 +13,7 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ +import isEqual from 'lodash/isEqual.js'; import React from 'react'; import PropTypes from 'prop-types'; import { catalogItemTypes } from './onboardingCatalog/OnboardingCatalogConstants.js'; @@ -20,6 +21,28 @@ import { filterCatalogItemsByType } from './onboardingCatalog/OnboardingCatalogU import CatalogList from './CatalogList.jsx'; import CatalogItemDetails from './CatalogItemDetails.jsx'; +function renderCatalogItems({ + items, + type, + filter, + onSelect, + onMigrate, + users +}) { + const filteredItems = items.length + ? filterCatalogItemsByType({ items, filter }) + : []; + return filteredItems.map(item => ( + <CatalogItemDetails + key={item.id} + catalogItemData={item} + catalogItemTypeClass={type} + onMigrate={onMigrate} + onSelect={() => onSelect(item, users)} + /> + )); +} + class DetailsCatalogView extends React.Component { static propTypes = { VLMList: PropTypes.array, @@ -31,18 +54,14 @@ class DetailsCatalogView extends React.Component { filter: PropTypes.string.isRequired }; - renderCatalogItems({ items, type, filter, onSelect, onMigrate, users }) { - return filterCatalogItemsByType({ items, filter }).map(item => ( - <CatalogItemDetails - key={item.id} - catalogItemData={item} - catalogItemTypeClass={type} - onMigrate={onMigrate} - onSelect={() => onSelect(item, users)} - /> - )); + shouldComponentUpdate(nextProps) { + const shouldUpdate = + isEqual(nextProps.VLMList, this.props.VLMList) && + isEqual(nextProps.VSPList, this.props.VSPList) && + isEqual(nextProps.users, this.props.users) && + isEqual(nextProps.filter, this.props.filter); + return !shouldUpdate; } - render() { let { VLMList, @@ -57,7 +76,7 @@ class DetailsCatalogView extends React.Component { } = this.props; return ( <CatalogList onAddVLM={onAddVLM} onAddVSP={onAddVSP}> - {this.renderCatalogItems({ + {renderCatalogItems({ items: VLMList, type: catalogItemTypes.LICENSE_MODEL, filter, @@ -65,7 +84,7 @@ class DetailsCatalogView extends React.Component { onMigrate, users })} - {this.renderCatalogItems({ + {renderCatalogItems({ items: VSPList, type: catalogItemTypes.SOFTWARE_PRODUCT, filter, diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/Onboard.js b/openecomp-ui/src/sdc-app/onboarding/onboard/Onboard.js index a1e0018114..ea70f9c0b8 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/Onboard.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/Onboard.js @@ -22,7 +22,7 @@ import LicenseModelCreationActionHelper from '../licenseModel/creation/LicenseMo import SoftwareProductCreationActionHelper from '../softwareProduct/creation/SoftwareProductCreationActionHelper.js'; import sortByStringProperty from 'nfvo-utils/sortByStringProperty.js'; import { tabsMapping } from './onboardingCatalog/OnboardingCatalogConstants.js'; -import { itemsType } from './filter/FilterConstants.js'; +import { itemStatus } from 'sdc-app/common/helpers/ItemsHelperConstants.js'; export const mapStateToProps = ({ onboard: { onboardingCatalog, activeTab, searchValue, filter }, @@ -32,7 +32,8 @@ export const mapStateToProps = ({ archivedSoftwareProductList, finalizedLicenseModelList, softwareProductList, - finalizedSoftwareProductList + finalizedSoftwareProductList, + filteredItems }) => { const fullSoftwareProducts = softwareProductList .filter( @@ -50,6 +51,23 @@ export const mapStateToProps = ({ return accum; }; + const reduceFilteredLicenseModelList = (accum, vlm) => { + let currentSoftwareProductList = sortByStringProperty( + filteredItems.vspList.filter(vsp => vsp.vendorId === vlm.id), + 'name' + ); + accum.push({ ...vlm, softwareProductList: currentSoftwareProductList }); + return accum; + }; + + const updatedFilteredItems = { + vspList: [...filteredItems.vspList], + vlmList: sortByStringProperty( + filteredItems.vlmList.reduce(reduceFilteredLicenseModelList, []), + 'name' + ) + }; + licenseModelList = sortByStringProperty( licenseModelList.reduce(reduceLicenseModelList, []), 'name' @@ -72,7 +90,7 @@ export const mapStateToProps = ({ } = onboardingCatalog; if (filter.byVendorView) { catalogActiveTab = tabsMapping.BY_VENDOR; - } else if (filter.itemsType && filter.itemsType === itemsType.ARCHIVED) { + } else if (filter.itemStatus && filter.itemStatus === itemStatus.ARCHIVED) { catalogActiveTab = tabsMapping.ARCHIVE; } @@ -89,7 +107,8 @@ export const mapStateToProps = ({ searchValue, vspOverlay, selectedVendor, - users: users.usersList + users: users.usersList, + filteredItems: updatedFilteredItems }; }; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardActionHelper.js index 87ec2d148e..2826e324b3 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardActionHelper.js @@ -1,25 +1,30 @@ -/*! - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. +/* + * Copyright © 2016-2018 European Support Limited * * 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 - * + * + * 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. + * 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 { tabsMapping, actionTypes } from './OnboardConstants.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import VersionsPageActionHelper from 'sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js'; -import { catalogItemStatuses } from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js'; + import { itemTypes } from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; import PermissionsActionHelper from 'sdc-app/onboarding/permissions/PermissionsActionHelper.js'; +import { actionTypes as filterActionTypes } from './filter/FilterConstants.js'; +import { + versionStatus, + itemStatus +} from 'sdc-app/common/helpers/ItemsHelperConstants.js'; const OnboardActionHelper = { resetOnboardStore(dispatch) { @@ -33,6 +38,18 @@ const OnboardActionHelper = { type: actionTypes.CHANGE_ACTIVE_ONBOARD_TAB, activeTab }); + dispatch({ + type: filterActionTypes.FILTER_DATA_CHANGED, + deltaData: + activeTab === tabsMapping.WORKSPACE + ? { + versionStatus: versionStatus.DRAFT, + itemStatus: itemStatus.ACTIVE + } + : { + versionStatus: versionStatus.CERTIFIED + } + }); }, changeSearchValue(dispatch, searchValue) { dispatch({ @@ -54,7 +71,7 @@ const OnboardActionHelper = { itemType: itemTypes.LICENSE_MODEL }).then(({ results }) => { results = results.filter( - version => version.status === catalogItemStatuses.DRAFT + version => version.status === versionStatus.DRAFT ); if (results.length !== 1) { ScreensHelper.loadScreen(dispatch, { @@ -104,7 +121,7 @@ const OnboardActionHelper = { itemType: itemTypes.SOFTWARE_PRODUCT }).then(({ results }) => { results = results.filter( - version => version.status === catalogItemStatuses.DRAFT + version => version.status === versionStatus.DRAFT ); if (results.length !== 1) { ScreensHelper.loadScreen(dispatch, { diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardView.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardView.jsx index dcaeaa787d..0fc64b328c 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardView.jsx @@ -16,7 +16,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import OnboardingCatalogView from './onboardingCatalog/OnboardingCatalogView.jsx'; +import OnboardingCatalogViewWithFilter from './onboardingCatalog/OnboardingCatalogViewWithFilter.jsx'; import WorkspaceView from './workspace/WorkspaceView.jsx'; +import WorkspaceViewWithFilter from './workspace/WorkspaceViewWithFilter.jsx'; import { tabsMapping } from './OnboardConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import classnames from 'classnames'; @@ -25,7 +27,8 @@ import objectValues from 'lodash/values.js'; import { catalogItemTypes } from './onboardingCatalog/OnboardingCatalogConstants.js'; import NotificationsView from 'sdc-app/onboarding/userNotifications/NotificationsView.jsx'; import Filter from 'sdc-app/onboarding/onboard/filter/Filter.jsx'; - +import featureToggle from 'sdc-app/features/featureToggle.js'; +import { featureToggleNames } from 'sdc-app/features/FeaturesConstants.js'; const OnboardHeaderTabs = ({ onTabClick, activeTab }) => ( <div className="onboard-header-tabs"> <div @@ -47,6 +50,16 @@ const OnboardHeaderTabs = ({ onTabClick, activeTab }) => ( </div> ); +const ToggledOnboardingCatalogView = featureToggle(featureToggleNames.FILTER)({ + OnComp: OnboardingCatalogViewWithFilter, + OffComp: OnboardingCatalogView +}); + +const ToggledWorkspaceView = featureToggle(featureToggleNames.FILTER)({ + OnComp: WorkspaceViewWithFilter, + OffComp: WorkspaceView +}); + const OnboardHeader = ({ onSearch, activeTab, onTabClick, searchValue }) => ( <div className="onboard-header"> <OnboardHeaderTabs activeTab={activeTab} onTabClick={onTabClick} /> @@ -85,11 +98,11 @@ class OnboardView extends React.Component { renderViewByTab(activeTab) { switch (activeTab) { case tabsMapping.WORKSPACE: - return <WorkspaceView {...this.props} />; + return <ToggledWorkspaceView {...this.props} />; case tabsMapping.CATALOG: - return <OnboardingCatalogView {...this.props} />; + return <ToggledOnboardingCatalogView {...this.props} />; default: - return <WorkspaceView {...this.props} />; + return <ToggledWorkspaceView {...this.props} />; } } diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/Filter.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/Filter.jsx index c80232de0a..a00357c7b9 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/Filter.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/Filter.jsx @@ -17,14 +17,19 @@ import { connect } from 'react-redux'; import React from 'react'; import PropTypes from 'prop-types'; -import i18n from 'nfvo-utils/i18n/i18n.js'; -import Input from 'nfvo-components/input/validation/Input.jsx'; -import Accordion from 'nfvo-components/accordion/Accordion.jsx'; -import { actionTypes } from './FilterConstants.js'; import featureToggle from 'sdc-app/features/featureToggle.js'; import { featureToggleNames } from 'sdc-app/features/FeaturesConstants.js'; import { tabsMapping as onboardTabsMapping } from '../OnboardConstants.js'; -import { itemsType as itemsTypeConstants } from './FilterConstants.js'; +import { actionTypes } from './FilterConstants.js'; + +import Panel from 'sdc-ui/lib/react/Panel.js'; +import { + ItemStatus, + ByVendorView, + EntityType, + Permissions, + OnboardingProcedure +} from './FilterComponents.jsx'; const mapStateToProps = ({ onboard: { filter, activeTab } }) => { return { @@ -35,145 +40,39 @@ const mapStateToProps = ({ onboard: { filter, activeTab } }) => { const mapActionsToProps = dispatch => { return { - onDataChanged: deltaData => + onDataChanged: deltaData => { dispatch({ type: actionTypes.FILTER_DATA_CHANGED, deltaData - }) + }); + } }; }; -const Filter = ({ - onDataChanged, - data: { - entityTypeVsp, - entityTypeVlm, - roleOwner, - roleContributor, - roleViewer, - procedureNetwork, - procedureManual, - recentlyUpdated, - byVendorView, - itemsType - }, - activeTab -}) => ( - <div className="catalog-filter"> - {activeTab === onboardTabsMapping.CATALOG && ( - <Input - type="select" - className="catalog-filter-items-type" - data-test-id="catalog-filter-items-type" - disabled={byVendorView} - value={itemsType} - onChange={e => onDataChanged({ itemsType: e.target.value })}> - <option - key={itemsTypeConstants.ACTIVE} - value={itemsTypeConstants.ACTIVE}> - Active Items - </option> - <option - key={itemsTypeConstants.ARCHIVED} - value={itemsTypeConstants.ARCHIVED}> - Archived Items - </option> - </Input> - )} - {activeTab === onboardTabsMapping.CATALOG && ( - <Input - label={i18n('By Vendor View')} - type="checkbox" - disabled={itemsType === itemsTypeConstants.ARCHIVED} - checked={byVendorView} - onChange={byVendorView => onDataChanged({ byVendorView })} - data-test-id="filter-by-vendor-view" - value="" - /> - )} - <Input - label={i18n('Recently Updated')} - type="checkbox" - checked={recentlyUpdated} - onChange={recentlyUpdated => onDataChanged({ recentlyUpdated })} - data-test-id="filter-recently-updated" - value="" - /> - - <Accordion title={i18n('ENTITY TYPE')}> - <Input - label={i18n('VSP')} - type="checkbox" - checked={entityTypeVsp} - onChange={entityTypeVsp => onDataChanged({ entityTypeVsp })} - data-test-id="filter-type-vsp" - value="" - /> - <Input - label={i18n('VLM')} - type="checkbox" - checked={entityTypeVlm} - onChange={entityTypeVlm => onDataChanged({ entityTypeVlm })} - data-test-id="filter-type-vlm" - value="" - /> - </Accordion> - - <Accordion title={i18n('ROLE')}> - <Input - label={i18n('Owner')} - type="checkbox" - checked={roleOwner} - onChange={roleOwner => onDataChanged({ roleOwner })} - data-test-id="filter-role-owner" - value="" - /> - <Input - label={i18n('Contributer')} - type="checkbox" - checked={roleContributor} - onChange={roleContributor => onDataChanged({ roleContributor })} - data-test-id="filter-role-contributor" - value="" - /> - <Input - label={i18n('Viewer')} - type="checkbox" - checked={roleViewer} - onChange={roleViewer => onDataChanged({ roleViewer })} - data-test-id="filter-role-viewr" - value="" - /> - </Accordion> - - <Accordion title={i18n('ONBOARDING PROCEDURE')}> - <Input - label={i18n('Network Package')} - type="checkbox" - checked={procedureNetwork} - onChange={procedureNetwork => - onDataChanged({ procedureNetwork }) - } - data-test-id="filter-procedure-network" - value="" - /> - <Input - label={i18n('Manual')} - type="checkbox" - checked={procedureManual} - onChange={procedureManual => onDataChanged({ procedureManual })} - data-test-id="filter-procedure-manual" - value="" - /> - </Accordion> - </div> -); +const Filter = ({ onDataChanged, data, activeTab }) => { + return ( + <Panel className="catalog-filter"> + <ItemStatus data={data} onDataChanged={onDataChanged} /> + <EntityType data={data} onDataChanged={onDataChanged} /> + <Permissions data={data} onDataChanged={onDataChanged} /> + <OnboardingProcedure data={data} onDataChanged={onDataChanged} /> + {activeTab === onboardTabsMapping.CATALOG && ( + <ByVendorView data={data} onDataChanged={onDataChanged} /> + )} + </Panel> + ); +}; Filter.PropTypes = { onDataChanged: PropTypes.func, - data: PropTypes.object + data: PropTypes.object, + activeTab: PropTypes.number }; export default featureToggle(featureToggleNames.FILTER)( connect(mapStateToProps, mapActionsToProps)(Filter) ); + +export const ConnectedFilter = connect(mapStateToProps, mapActionsToProps)( + Filter +); diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterActionHelper.js new file mode 100644 index 0000000000..f8155df49d --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterActionHelper.js @@ -0,0 +1,60 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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 { default as ItemsHelper } from 'sdc-app/common/helpers/ItemsHelper.js'; +import { + itemType, + versionStatus +} from 'sdc-app/common/helpers/ItemsHelperConstants.js'; +import { actionTypes } from './FilterConstants.js'; + +const FilterActionHelper = { + async updateFilteredItems(dispatch, filter) { + let permission = { ...filter.permission }; + if ( + filter.versionStatus === versionStatus.DRAFT && + !permission.Owner && + !permission.Contributor + ) { + permission.Owner = true; + permission.Contributor = true; + } + const items = await ItemsHelper.fetchItems({ + ...filter, + permission + }); + let vspList = []; + let vlmList = []; + items.results.map(item => { + if (item.type === itemType.VSP) { + const { properties, ...all } = item; + vspList.push({ ...all, ...properties }); + } else { + vlmList.push(item); + } + }); + + dispatch({ + type: actionTypes.UPDATE_FILTERED_LIST, + data: { + vspList, + vlmList + } + }); + } +}; + +export default FilterActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterComponents.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterComponents.jsx new file mode 100644 index 0000000000..65ec733fd5 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterComponents.jsx @@ -0,0 +1,145 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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 Input from 'nfvo-components/input/validation/Input.jsx'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import { itemStatus } from 'sdc-app/common/helpers/ItemsHelperConstants.js'; +import Accordion from 'sdc-ui/lib/react/Accordion.js'; +import Checklist from 'sdc-ui/lib/react/Checklist.js'; +import Checkbox from 'sdc-ui/lib/react/Checkbox.js'; + +export const ItemStatus = ({ data, onDataChanged, byVendorView }) => ( + <Input + type="select" + className="catalog-filter-items-type" + data-test-id="catalog-filter-items-type" + disabled={byVendorView} + value={data.itemStatus} + onChange={e => onDataChanged({ itemStatus: e.target.value }, data)}> + <option key={itemStatus.ACTIVE} value={itemStatus.ACTIVE}> + {i18n('Active Items')} + </option> + <option key={itemStatus.ARCHIVED} value={itemStatus.ARCHIVED}> + {i18n('Archived Items')} + </option> + </Input> +); + +const FilterList = ({ title, items, groupKey, onDataChanged, data }) => { + let onChange = value => { + let obj = {}; + obj[groupKey] = { ...data[groupKey], ...value }; + onDataChanged(obj); + }; + return ( + <Accordion title={title}> + <Checklist items={items} onChange={onChange} /> + </Accordion> + ); +}; + +export const ByVendorView = ({ data, onDataChanged }) => ( + <Checkbox + label={i18n('By Vendor View')} + className="catalog-filter-by-vendor-view" + disabled={data.itemsType === itemStatus.ARCHIVED} + checked={data.byVendorView} + onChange={byVendorView => onDataChanged({ byVendorView }, data)} + data-test-id="filter-by-vendor-view" + value="" + /> +); + +export const EntityType = ({ data, onDataChanged }) => { + const items = [ + { + label: i18n('VSP'), + dataTestId: 'catalog-filter-type-vsp', + value: 'vsp', + checked: data.itemType && data.itemType.vsp + }, + { + label: i18n('VLM'), + dataTestId: 'catalog-ilter-type-vlm', + value: 'vlm', + checked: data.itemType && data.itemType.vlm + } + ]; + return ( + <FilterList + title={i18n('ENTITY TYPE')} + items={items} + onDataChanged={onDataChanged} + data={data} + groupKey="itemType" + /> + ); +}; + +export const Permissions = ({ data, onDataChanged }) => { + const items = [ + { + label: i18n('Owner'), + dataTestId: 'catalog-filter-permission-owner', + value: 'Owner', + checked: data.permission && data.permission.Owner + }, + { + label: i18n('Contributor'), + dataTestId: 'catalog-filter-permission-contributor', + value: 'Contributor', + checked: data.permission && data.permission.Contributor + } + ]; + + return ( + <FilterList + title={i18n('PERMISSIONS')} + items={items} + onDataChanged={onDataChanged} + data={data} + groupKey="permission" + /> + ); +}; + +export const OnboardingProcedure = ({ data, onDataChanged }) => { + const items = [ + { + label: i18n('Network Package'), + dataTestId: 'catalog-filter-procedure-network', + value: 'NetworkPackage', + checked: + data.onboardingMethod && data.onboardingMethod.NetworkPackage + }, + { + label: i18n('Manual'), + dataTestId: 'catalog-filter-procedure-manual', + value: 'Manual', + checked: data.onboardingMethod && data.onboardingMethod.Manual + } + ]; + + return ( + <FilterList + title={i18n('ONBOARDING PROCEDURE')} + items={items} + onDataChanged={onDataChanged} + data={data} + groupKey="onboardingMethod" + /> + ); +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterConstants.js b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterConstants.js index edfe592877..9dce52dfd6 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterConstants.js @@ -17,10 +17,6 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - FILTER_DATA_CHANGED: null + FILTER_DATA_CHANGED: null, + UPDATE_FILTERED_LIST: null }); - -export const itemsType = { - ACTIVE: '1', - ARCHIVED: '2' -}; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterMiddleware.js b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterMiddleware.js new file mode 100644 index 0000000000..8490bfe675 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterMiddleware.js @@ -0,0 +1,32 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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 FilterActionHelper from './FilterActionHelper.js'; +import { actionTypes } from './FilterConstants.js'; + +const filterUpdater = store => next => action => { + if (action.type === actionTypes.FILTER_DATA_CHANGED) { + const filter = store.getState().onboard.filter; + + FilterActionHelper.updateFilteredItems(store.dispatch, { + ...filter, + ...action.deltaData + }); + } + return next(action); +}; + +export default filterUpdater; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterReducer.js b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterReducer.js index f1e857498a..28b34753a5 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterReducer.js @@ -14,8 +14,19 @@ * limitations under the License. */ import { actionTypes } from './FilterConstants.js'; +import { + itemStatus, + versionStatus +} from 'sdc-app/common/helpers/ItemsHelperConstants.js'; -export default (state = {}, action) => { +const defaultState = { + itemStatus: itemStatus.ACTIVE, + versionStatus: versionStatus.DRAFT, + entityType: {}, + permission: {}, + onboardingMethod: {} +}; +export default (state = defaultState, action) => { switch (action.type) { case actionTypes.FILTER_DATA_CHANGED: return { diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/ItemsReducer.js b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/ItemsReducer.js new file mode 100644 index 0000000000..fa1528d8d9 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/ItemsReducer.js @@ -0,0 +1,24 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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 './FilterConstants.js'; +export default (state = { vspList: [], vlmList: [] }, action) => { + switch (action.type) { + case actionTypes.UPDATE_FILTERED_LIST: + return action.data; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogView.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogView.jsx index 2cc32c2936..a416d36075 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogView.jsx @@ -83,8 +83,8 @@ const FilterCatalogHeader = () => ( ); const FeaturedCatalogHeader = featureToggle(featureToggleNames.FILTER)({ - AComp: FilterCatalogHeader, - BComp: CatalogHeader + OnComp: FilterCatalogHeader, + OffComp: CatalogHeader }); class OnboardingCatalogView extends React.Component { diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogViewWithFilter.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogViewWithFilter.jsx new file mode 100644 index 0000000000..86c437d888 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogViewWithFilter.jsx @@ -0,0 +1,147 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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 i18n from 'nfvo-utils/i18n/i18n.js'; +import DetailsCatalogView from 'sdc-app/onboarding/onboard/DetailsCatalogView.jsx'; +import VendorCatalogView from './VendorCatalogView.jsx'; +import { tabsMapping } from './OnboardingCatalogConstants.js'; +import { tabsMapping as WCTabsMapping } from 'sdc-app/onboarding/onboard/OnboardConstants.js'; + +const CatalogHeader = () => ( + <div className="catalog-header"> + <div className="catalog-header-tabs"> + <div className="catalog-header-tab active"> + {i18n('ONBOARD CATALOG')} + </div> + </div> + </div> +); + +class OnboardingCatalogView extends React.Component { + renderViewByTab(activeTab) { + const { + users, + vspOverlay, + onSelectLicenseModel, + onSelectSoftwareProduct, + onAddLicenseModelClick, + onAddSoftwareProductClick, + onVspOverlayChange, + onVendorSelect, + selectedVendor, + searchValue, + onMigrate, + filteredItems + } = this.props; + + const { vlmList, vspList } = filteredItems; + + switch (activeTab) { + case tabsMapping.ARCHIVE: + return ( + <DetailsCatalogView + VLMList={vlmList} + VSPList={vspList} + users={users} + onSelectVLM={(item, users) => + onSelectLicenseModel( + item, + users, + WCTabsMapping.CATALOG + ) + } + onSelectVSP={(item, users) => + onSelectSoftwareProduct( + item, + users, + WCTabsMapping.CATALOG + ) + } + filter={searchValue} + onMigrate={onMigrate} + /> + ); + case tabsMapping.ACTIVE: + return ( + <DetailsCatalogView + VLMList={vlmList} + VSPList={vspList} + users={users} + onAddVLM={onAddLicenseModelClick} + onAddVSP={onAddSoftwareProductClick} + onSelectVLM={(item, users) => + onSelectLicenseModel( + item, + users, + WCTabsMapping.CATALOG + ) + } + onSelectVSP={(item, users) => + onSelectSoftwareProduct( + item, + users, + WCTabsMapping.CATALOG + ) + } + filter={searchValue} + onMigrate={onMigrate} + /> + ); + case tabsMapping.BY_VENDOR: + default: + return ( + <VendorCatalogView + licenseModelList={vlmList} + users={users} + onAddVSP={onAddSoftwareProductClick} + onAddVLM={onAddLicenseModelClick} + onSelectVSP={(item, users) => + onSelectSoftwareProduct( + item, + users, + WCTabsMapping.CATALOG + ) + } + onSelectVLM={(item, users) => + onSelectLicenseModel( + item, + users, + WCTabsMapping.CATALOG + ) + } + vspOverlay={vspOverlay} + onVendorSelect={onVendorSelect} + selectedVendor={selectedVendor} + onVspOverlayChange={onVspOverlayChange} + onMigrate={onMigrate} + filter={searchValue} + /> + ); + } + } + + render() { + const { selectedVendor, catalogActiveTab: activeTab } = this.props; + return ( + <div className="catalog-wrapper"> + {!selectedVendor && <CatalogHeader />} + {this.renderViewByTab(activeTab)} + </div> + ); + } +} + +export default OnboardingCatalogView; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorItem.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorItem.jsx index bef47d5acf..12beff7a30 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorItem.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorItem.jsx @@ -60,8 +60,8 @@ class VendorItem extends React.Component { </TileInfoLine> <TileInfoLine> <Button - btnType="outline-rounded" - color="dark-gray" + btnType="secondary" + className="venodor-tile-btn" onClick={e => this.handleVspCountClick(e)} data-test-id="catalog-vsp-count" disabled={!softwareProductList.length}> diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/workspace/WorkspaceViewWithFilter.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/workspace/WorkspaceViewWithFilter.jsx new file mode 100644 index 0000000000..eec59622b3 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/workspace/WorkspaceViewWithFilter.jsx @@ -0,0 +1,57 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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 DetailsCatalogView from '../DetailsCatalogView.jsx'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import { tabsMapping } from 'sdc-app/onboarding/onboard/OnboardConstants.js'; + +const WorkspaceView = props => { + let { + onAddLicenseModelClick, + users, + onAddSoftwareProductClick, + onSelectLicenseModel, + onSelectSoftwareProduct, + searchValue, + onMigrate, + filteredItems: { vspList, vlmList } + } = props; + + return ( + <div className="catalog-wrapper workspace-view"> + <div className="catalog-header workspace-header"> + {i18n('WORKSPACE')} + </div> + <DetailsCatalogView + VLMList={vlmList} + VSPList={vspList} + users={users} + onAddVLM={onAddLicenseModelClick} + onAddVSP={onAddSoftwareProductClick} + onSelectVLM={(item, users) => + onSelectLicenseModel(item, users, tabsMapping.WORKSPACE) + } + onSelectVSP={(item, users) => + onSelectSoftwareProduct(item, users, tabsMapping.WORKSPACE) + } + onMigrate={onMigrate} + filter={searchValue} + /> + </div> + ); +}; + +export default WorkspaceView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js index 4a2d7a2ece..25bd32e468 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js @@ -45,8 +45,11 @@ import { CommitModalType } from 'nfvo-components/panel/versionController/compone import { actionTypes as commonActionTypes } from 'sdc-app/common/reducers/PlainDataReducerConstants.js'; import versionPageActionHelper from 'sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js'; import { itemTypes } from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; -import { catalogItemStatuses } from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js'; import getValue from 'nfvo-utils/getValue.js'; +import { + itemStatus, + versionStatus +} from 'sdc-app/common/helpers/ItemsHelperConstants.js'; function getLicensingData(licensingData = {}) { const { licenseAgreement, featureGroups } = licensingData; @@ -112,19 +115,17 @@ function putSoftwareProductAction(id, action, version) { function fetchSoftwareProductList() { return RestAPIUtil.fetch( - `${baseUrl()}?versionFilter=${catalogItemStatuses.DRAFT}` + `${baseUrl()}?versionFilter=${versionStatus.DRAFT}` ); } function fetchArchivedSoftwareProductList() { - return RestAPIUtil.fetch( - `${baseUrl()}?Status=${catalogItemStatuses.ARCHIVED}` - ); + return RestAPIUtil.fetch(`${baseUrl()}?Status=${itemStatus.ARCHIVED}`); } function fetchFinalizedSoftwareProductList() { return RestAPIUtil.fetch( - `${baseUrl()}?versionFilter=${catalogItemStatuses.CERTIFIED}` + `${baseUrl()}?versionFilter=${versionStatus.CERTIFIED}` ); } @@ -664,9 +665,8 @@ const SoftwareProductActionHelper = { version }).then(({ inMerge, isDirty, updatedVersion }) => { if ( - (updatedVersion.status === catalogItemStatuses.CERTIFIED || - updatedVersion.archivedStatus === - catalogItemStatuses.ARCHIVED) && + (updatedVersion.status === versionStatus.CERTIFIED || + updatedVersion.archivedStatus === itemStatus.ARCHIVED) && (action === VersionControllerActionsEnum.COMMIT || action === VersionControllerActionsEnum.SYNC) ) { @@ -675,8 +675,7 @@ const SoftwareProductActionHelper = { itemId: softwareProductId }); const msg = - updatedVersion.archivedStatus === - catalogItemStatuses.ARCHIVED + updatedVersion.archivedStatus === itemStatus.ARCHIVED ? i18n('Item was Archived') : i18n('Item version already Certified'); dispatch({ diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreation.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreation.js index 41584d94e2..9a7d257d7d 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreation.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreation.js @@ -14,9 +14,11 @@ * permissions and limitations under the License. */ import { connect } from 'react-redux'; - +import featureToggle from 'sdc-app/features/featureToggle.js'; +import { featureToggleNames } from 'sdc-app/features/FeaturesConstants.js'; import SoftwareProductCreationActionHelper from './SoftwareProductCreationActionHelper.js'; import SoftwareProductCreationView from './SoftwareProductCreationView.jsx'; +import SoftwareProductCreationViewWithFilter from './SoftwareProductCreationViewWithFilter.jsx'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import SoftwareProductActionHelper from '../SoftwareProductActionHelper.js'; import VersionsPageActionHelper from 'sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js'; @@ -24,6 +26,16 @@ import { itemTypes as versionItemTypes } from 'sdc-app/onboarding/versionsPage/V import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import PermissionsActionHelper from 'sdc-app/onboarding/permissions/PermissionsActionHelper.js'; +import UniqueTypesHelper from 'sdc-app/common/helpers/UniqueTypesHelper.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import { itemType } from 'sdc-app/common/helpers/ItemsHelperConstants.js'; + +const ToggledSoftwareProductCreationView = featureToggle( + featureToggleNames.FILTER +)({ + OnComp: SoftwareProductCreationViewWithFilter, + OffComp: SoftwareProductCreationView +}); export const mapStateToProps = ({ finalizedLicenseModelList, @@ -33,7 +45,7 @@ export const mapStateToProps = ({ finalizedSoftwareProductList, softwareProduct: { softwareProductCreation, softwareProductCategories } }) => { - let { genericFieldInfo } = softwareProductCreation; + let { genericFieldInfo, vendorList = [] } = softwareProductCreation; let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); let VSPNames = {}; @@ -52,6 +64,7 @@ export const mapStateToProps = ({ disableVendor: softwareProductCreation.disableVendor, softwareProductCategories, finalizedLicenseModelList, + vendorList, isFormValid, formReady: softwareProductCreation.formReady, genericFieldInfo, @@ -99,10 +112,22 @@ export const mapActionsToProps = dispatch => { }); }, onValidateForm: formName => - ValidationHelper.validateForm(dispatch, formName) + ValidationHelper.validateForm(dispatch, formName), + isNameUnique: (value, name, formName) => + UniqueTypesHelper.isNameUnique(dispatch, { + value, + name, + formName, + errorText: `${i18n( + 'Software product by the name' + )} ${value} ${i18n('already exists')}. ${i18n( + 'Software product name must be unique' + )}`, + itemType: itemType.VSP + }) }; }; export default connect(mapStateToProps, mapActionsToProps, null, { withRef: true -})(SoftwareProductCreationView); +})(ToggledSoftwareProductCreationView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationActionHelper.js index 1b1fd71fef..259b50ba4f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationActionHelper.js @@ -24,7 +24,11 @@ import { import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; import { actionTypes } from './SoftwareProductCreationConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; - +import ItemsHelper from 'sdc-app/common/helpers/ItemsHelper.js'; +import { + itemStatus, + versionStatus +} from 'sdc-app/common/helpers/ItemsHelperConstants.js'; function baseUrl() { const restPrefix = Configuration.get('restPrefix'); return `${restPrefix}/v1.0/vendor-software-products/`; @@ -45,7 +49,7 @@ const SoftwareProductCreationActionHelper = { type: actionTypes.OPEN, selectedVendorId: vendorId }); - + this.loadVendorList(dispatch); dispatch({ type: modalActionTypes.GLOBAL_MODAL_SHOW, data: { @@ -78,6 +82,19 @@ const SoftwareProductCreationActionHelper = { }); return result; }); + }, + async loadVendorList(dispatch) { + const { results } = await ItemsHelper.fetchItems({ + itemStatus: itemStatus.ACTIVE, + versionStatus: versionStatus.CERTIFIED, + itemType: { + vlm: true + } + }); + dispatch({ + type: actionTypes.VENDOR_LIST_LOADED, + vendorList: results + }); } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationConstants.js index ad1034602a..128b3edfd9 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationConstants.js @@ -18,7 +18,8 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ OPEN: null, RESET_DATA: null, - SOFTWARE_PRODUCT_CREATED: null + SOFTWARE_PRODUCT_CREATED: null, + VENDOR_LIST_LOADED: null }); export const SP_CREATION_FORM_NAME = 'SPCREATIONFORM'; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationReducer.js index 5f70f18f75..b019248ba0 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationReducer.js @@ -74,6 +74,11 @@ export default (state = {}, action) => { }, showModal: true }; + case actionTypes.VENDOR_LIST_LOADED: + return { + ...state, + vendorList: action.vendorList + }; case actionTypes.RESET_DATA: return {}; default: diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationViewWithFilter.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationViewWithFilter.jsx new file mode 100644 index 0000000000..810337dbed --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationViewWithFilter.jsx @@ -0,0 +1,329 @@ +/*! + * Copyright © 2016-2018 European Support Limited + * + * 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 PropTypes from 'prop-types'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Validator from 'nfvo-utils/Validator.js'; +import Input from 'nfvo-components/input/validation/Input.jsx'; +import Form from 'nfvo-components/input/validation/Form.jsx'; +import GridSection from 'nfvo-components/grid/GridSection.jsx'; +import GridItem from 'nfvo-components/grid/GridItem.jsx'; + +import { SP_CREATION_FORM_NAME } from './SoftwareProductCreationConstants.js'; +import sortByStringProperty from 'nfvo-utils/sortByStringProperty.js'; + +import SoftwareProductCategoriesHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductCategoriesHelper.js'; +import { onboardingMethod as onboardingMethodConst } from '../SoftwareProductConstants.js'; + +const SoftwareProductPropType = PropTypes.shape({ + id: PropTypes.string, + name: PropTypes.string, + description: PropTypes.string, + category: PropTypes.string, + subCategory: PropTypes.string, + vendorId: PropTypes.string +}); + +class SoftwareProductCreationView extends React.Component { + static propTypes = { + data: SoftwareProductPropType, + finalizedLicenseModelList: PropTypes.array, + softwareProductCategories: PropTypes.array, + VSPNames: PropTypes.object, + usersList: PropTypes.array, + onDataChanged: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired + }; + + render() { + let { + softwareProductCategories, + data = {}, + onDataChanged, + onCancel, + genericFieldInfo, + disableVendor + } = this.props; + let { + name, + description, + vendorId, + subCategory, + onboardingMethod + } = data; + + const vendorList = this.getVendorList(); + return ( + <div className="software-product-creation-page"> + {genericFieldInfo && ( + <Form + ref={validationForm => + (this.validationForm = validationForm) + } + hasButtons={true} + onSubmit={() => this.submit()} + onReset={() => onCancel()} + labledButtons={true} + isValid={this.props.isFormValid} + submitButtonText={i18n('Create')} + formReady={this.props.formReady} + onValidateForm={() => this.validate()}> + <GridSection hasLastColSet> + <GridItem colSpan="2"> + <Input + value={name} + label={i18n('Name')} + isRequired={true} + onChange={name => + onDataChanged( + { name }, + SP_CREATION_FORM_NAME + ) + } + onBlur={this.validateIsNameUnique} + isValid={genericFieldInfo.name.isValid} + errorText={genericFieldInfo.name.errorText} + type="text" + className="field-section" + data-test-id="new-vsp-name" + /> + <Input + label={i18n('Vendor')} + type="select" + value={vendorId} + overlayPos="bottom" + isRequired={true} + disabled={disableVendor} + onChange={e => this.onSelectVendor(e)} + isValid={genericFieldInfo.vendorId.isValid} + errorText={ + genericFieldInfo.vendorId.errorText + } + className="input-options-select" + groupClassName="bootstrap-input-options" + data-test-id="new-vsp-vendor"> + {vendorList.map(vendor => ( + <option + key={vendor.title} + value={vendor.enum}> + {vendor.title} + </option> + ))} + </Input> + <Input + label={i18n('Category')} + type="select" + value={subCategory} + isRequired={true} + onChange={e => this.onSelectSubCategory(e)} + isValid={ + genericFieldInfo.subCategory.isValid + } + errorText={ + genericFieldInfo.subCategory.errorText + } + className="input-options-select" + groupClassName="bootstrap-input-options" + data-test-id="new-vsp-category"> + <option key="" value=""> + {i18n('please select…')} + </option> + {softwareProductCategories.map( + category => + category.subcategories && ( + <optgroup + key={category.name} + label={category.name}> + {category.subcategories.map( + sub => ( + <option + key={ + sub.uniqueId + } + value={ + sub.uniqueId + }>{`${ + sub.name + } (${ + category.name + })`}</option> + ) + )} + </optgroup> + ) + )} + </Input> + </GridItem> + <GridItem colSpan="2" stretch lastColInRow> + <Input + value={description} + label={i18n('Description')} + isRequired={true} + overlayPos="bottom" + onChange={description => + onDataChanged( + { description }, + SP_CREATION_FORM_NAME + ) + } + isValid={ + genericFieldInfo.description.isValid + } + errorText={ + genericFieldInfo.description.errorText + } + type="textarea" + className="field-section" + data-test-id="new-vsp-description" + /> + </GridItem> + </GridSection> + <OnboardingProcedure + genericFieldInfo={genericFieldInfo} + onboardingMethod={onboardingMethod} + onDataChanged={onDataChanged} + /> + </Form> + )} + </div> + ); + } + + getVendorList() { + let { vendorList } = this.props; + + return [{ enum: '', title: i18n('please select...') }].concat( + sortByStringProperty(vendorList, 'name').map(vendor => { + return { + enum: vendor.id, + title: vendor.name + }; + }) + ); + } + + onSelectVendor(e) { + const selectedIndex = e.target.selectedIndex; + const vendorId = e.target.options[selectedIndex].value; + this.props.onDataChanged({ vendorId }, SP_CREATION_FORM_NAME); + } + + onSelectSubCategory(e) { + const selectedIndex = e.target.selectedIndex; + const subCategory = e.target.options[selectedIndex].value; + let { softwareProductCategories, onDataChanged } = this.props; + let category = SoftwareProductCategoriesHelper.getCurrentCategoryOfSubCategory( + subCategory, + softwareProductCategories + ); + onDataChanged({ category, subCategory }, SP_CREATION_FORM_NAME); + } + + submit() { + let { + data: softwareProduct, + finalizedLicenseModelList, + usersList + } = this.props; + softwareProduct.vendorName = finalizedLicenseModelList.find( + vendor => vendor.id === softwareProduct.vendorId + ).name; + this.props.onSubmit(softwareProduct, usersList); + } + + validateName(value) { + const { data: { id }, VSPNames } = this.props; + const isExists = Validator.isItemNameAlreadyExistsInList({ + itemId: id, + itemName: value, + list: VSPNames + }); + + return !isExists + ? { isValid: true, errorText: '' } + : { + isValid: false, + errorText: i18n( + "Software product by the name '" + + value + + "' already exists. Software product name must be unique" + ) + }; + } + + validateIsNameUnique = e => { + const value = e.target.value; + this.props.isNameUnique(value, 'name', SP_CREATION_FORM_NAME); + }; + + validate() { + this.props.onValidateForm(SP_CREATION_FORM_NAME); + } +} + +const OnboardingProcedure = ({ + onboardingMethod, + onDataChanged, + genericFieldInfo +}) => { + return ( + <GridSection title={i18n('Onboarding procedure')}> + <GridItem colSpan={4}> + <Input + label={i18n('Network Package')} + overlayPos="top" + isValid={genericFieldInfo.onboardingMethod.isValid} + checked={ + onboardingMethod === + onboardingMethodConst.NETWORK_PACKAGE + } + errorText={genericFieldInfo.onboardingMethod.errorText} + onChange={() => + onDataChanged( + { + onboardingMethod: + onboardingMethodConst.NETWORK_PACKAGE + }, + SP_CREATION_FORM_NAME + ) + } + type="radio" + data-test-id="new-vsp-creation-procedure-heat" + /> + </GridItem> + <GridItem colSpan={4}> + <Input + label={i18n('Manual')} + overlayPos="bottom" + checked={onboardingMethod === onboardingMethodConst.MANUAL} + isValid={genericFieldInfo.onboardingMethod.isValid} + errorText={genericFieldInfo.onboardingMethod.errorText} + onChange={() => + onDataChanged( + { onboardingMethod: onboardingMethodConst.MANUAL }, + SP_CREATION_FORM_NAME + ) + } + type="radio" + data-test-id="new-vsp-creation-procedure-manual" + /> + </GridItem> + </GridSection> + ); +}; + +export default SoftwareProductCreationView; diff --git a/openecomp-ui/test-utils/factories/common/ItemsHelperFactory.js b/openecomp-ui/test-utils/factories/common/ItemsHelperFactory.js new file mode 100644 index 0000000000..cdfd91be9d --- /dev/null +++ b/openecomp-ui/test-utils/factories/common/ItemsHelperFactory.js @@ -0,0 +1,45 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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 { Factory } from 'rosie'; +import randomstring from 'randomstring'; +import IdMixin from 'test-utils/factories/mixins/IdMixin.js'; + +export const itemFactory = new Factory() + .extend(IdMixin) + .option('isArchived', false) + .attrs({ + description: () => randomstring.generate(), + name: () => randomstring.generate(), + owner: () => randomstring.generate() + }) + .attr('status', ['isArchived'], isArchived => { + return isArchived ? 'ARCHIVE' : 'ACTIVE'; + }); + +export const vspFactory = new Factory().extend(itemFactory).attrs({ + type: 'vsp', + properties: { + onboardingMethod: 'NetworkPackage', + vendorId: randomstring.generate(33), + vendorName: randomstring.generate() + } +}); + +export const vlmFactory = new Factory().extend(itemFactory).attrs({ + type: 'vlm', + properties: {} +}); diff --git a/openecomp-ui/test-utils/factories/onboard/FilterFactories.js b/openecomp-ui/test-utils/factories/onboard/FilterFactories.js new file mode 100644 index 0000000000..a659c3d619 --- /dev/null +++ b/openecomp-ui/test-utils/factories/onboard/FilterFactories.js @@ -0,0 +1,24 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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 { Factory } from 'rosie'; + +export const FilterFactory = new Factory().attrs({ + entityType: {}, + itemStatus: 'ACTIVE', + onboardingMethod: {}, + permission: {}, + versionStatus: 'Draft' +}); diff --git a/openecomp-ui/test-utils/factories/onboard/OnboardFactories.js b/openecomp-ui/test-utils/factories/onboard/OnboardFactories.js index 3228694ccd..92b1255074 100644 --- a/openecomp-ui/test-utils/factories/onboard/OnboardFactories.js +++ b/openecomp-ui/test-utils/factories/onboard/OnboardFactories.js @@ -1,23 +1,22 @@ -/*! - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. +/* + * Copyright © 2016-2018 European Support Limited * * 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 - * + * + * 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. + * 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 {Factory} from 'rosie'; -import {storeCreator} from 'sdc-app/AppStore.js'; +import { Factory } from 'rosie'; +import { storeCreator } from 'sdc-app/AppStore.js'; const store = storeCreator(); const defaultStore = store.getState(); -export const OnboardStoreFactory = new Factory() - .attrs(defaultStore.onboard); +export const OnboardStoreFactory = new Factory().attrs(defaultStore.onboard); diff --git a/openecomp-ui/test/onboard/filter/filter.test.js b/openecomp-ui/test/onboard/filter/filter.test.js new file mode 100644 index 0000000000..1b89a306bf --- /dev/null +++ b/openecomp-ui/test/onboard/filter/filter.test.js @@ -0,0 +1,146 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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 { storeCreator } from 'sdc-app/AppStore.js'; +import mockRest from 'test-utils/MockRest.js'; +import { cloneAndSet } from 'test-utils/Util.js'; +import { actionTypes } from 'sdc-app/onboarding/onboard/filter/FilterConstants.js'; +import { + vspFactory, + vlmFactory +} from 'test-utils/factories/common/ItemsHelperFactory.js'; +import { FilterFactory } from 'test-utils/factories/onboard/FilterFactories.js'; +import { + itemStatus, + versionStatus +} from 'sdc-app/common/helpers/ItemsHelperConstants.js'; +import OnboardActionHelper from 'sdc-app/onboarding/onboard/OnboardActionHelper.js'; +import { tabsMapping } from 'sdc-app/onboarding/onboard/OnboardConstants.js'; + +const vsps = vspFactory.buildList(1); +const vlms = vlmFactory.buildList(1); + +const timeoutPromise = new Promise(resolve => { + setTimeout(function() { + resolve(); + }, 100); +}); + +describe('Onboard Filter Tests', () => { + it('basic test', done => { + const store = storeCreator(); + + mockRest.addHandler('fetch', ({ data, options, baseUrl }) => { + expect(baseUrl).toEqual( + `/onboarding-api/v1.0/items?&itemStatus=${ + itemStatus.ACTIVE + }&versionStatus=${versionStatus.DRAFT}` + ); + expect(data).toEqual(undefined); + expect(options).toEqual(undefined); + return { results: [] }; + }); + const expectedStore = store.getState(); + store.dispatch({ + type: actionTypes.FILTER_DATA_CHANGED, + deltaData: {} + }); + return timeoutPromise.then(function() { + expect(store.getState()).toEqual(expectedStore); + done(); + }); + }); + /** + * TODO Turn ON when FILTER TOGGLE Will BE REMOVED + */ + /* + it('load certifed data', done => { + const store = storeCreator(); + + mockRest.addHandler('fetch', ({ data, options, baseUrl }) => { + expect(baseUrl).toEqual( + `/onboarding-api/v1.0/items?&itemStatus=${ + itemStatus.ACTIVE + }&versionStatus=${versionStatus.CERTIFIED}` + ); + expect(data).toEqual(undefined); + expect(options).toEqual(undefined); + return { + results: [...vsps, ...vlms] + }; + }); + + const expectedStore = cloneAndSet( + store.getState(), + 'onboard.filter', + FilterFactory.build({ versionStatus: versionStatus.CERTIFIED }) + ); + + const expectedFilteredItems = { + vspList: [ + ...vsps.map(({ properties, ...other }) => ({ + ...other, + ...properties + })) + ], + vlmList: [...vlms] + }; + const expectedStoreWithFilteredLists = cloneAndSet( + expectedStore, + 'filteredItems', + expectedFilteredItems + ); + store.dispatch({ + type: actionTypes.FILTER_DATA_CHANGED, + deltaData: { versionStatus: versionStatus.CERTIFIED } + }); + + return timeoutPromise.then(function() { + expect(store.getState()).toEqual(expectedStoreWithFilteredLists); + done(); + }); + }); + */ + it('onboarding tabs switching filter updates', done => { + const store = storeCreator(); + + mockRest.addHandler('fetch', ({ data, options, baseUrl }) => { + expect(baseUrl).toEqual( + `/onboarding-api/v1.0/items?&itemStatus=${ + itemStatus.ACTIVE + }&versionStatus=${versionStatus.CERTIFIED}` + ); + expect(data).toEqual(undefined); + expect(options).toEqual(undefined); + return { results: [] }; + }); + + expect(store.getState().onboard.filter.versionStatus).toEqual( + versionStatus.DRAFT + ); + + OnboardActionHelper.changeActiveTab( + store.dispatch, + tabsMapping.CATALOG + ); + + return timeoutPromise.then(() => { + expect(store.getState().onboard.filter.versionStatus).toEqual( + versionStatus.CERTIFIED + ); + done(); + }); + }); +}); diff --git a/openecomp-ui/test/onboard/filter/filterView.test.js b/openecomp-ui/test/onboard/filter/filterView.test.js new file mode 100644 index 0000000000..536f02cf49 --- /dev/null +++ b/openecomp-ui/test/onboard/filter/filterView.test.js @@ -0,0 +1,34 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * 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 { mount } from 'enzyme'; +import { Provider } from 'react-redux'; +import { storeCreator } from 'sdc-app/AppStore.js'; +import { ConnectedFilter } from 'sdc-app/onboarding//onboard//filter/Filter.jsx'; + +describe('Filter component view Tests', () => { + it('simple jsx test', () => { + const store = storeCreator(); + const wrapper = mount( + <Provider store={store}> + <ConnectedFilter /> + </Provider> + ); + const filter = wrapper.find('.catalog-filter'); + expect(filter.hasClass('catalog-filter')).toBeTruthy(); + }); +}); diff --git a/openecomp-ui/test/onboard/test.js b/openecomp-ui/test/onboard/test.js index 232c5615c9..a75070bf26 100644 --- a/openecomp-ui/test/onboard/test.js +++ b/openecomp-ui/test/onboard/test.js @@ -13,50 +13,64 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {storeCreator} from 'sdc-app/AppStore.js'; -import {OnboardStoreFactory} from 'test-utils/factories/onboard/OnboardFactories.js'; +import { storeCreator } from 'sdc-app/AppStore.js'; +import { OnboardStoreFactory } from 'test-utils/factories/onboard/OnboardFactories.js'; import OnboardActionHelper from 'sdc-app/onboarding/onboard/OnboardActionHelper.js'; import OnboardingCatalogActionHelper from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogActionHelper.js'; -import {tabsMapping as onboardTabsMapping} from 'sdc-app/onboarding/onboard/OnboardConstants.js'; -import {tabsMapping as onboardCatalogTabsMapping} from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js'; +import { tabsMapping as onboardTabsMapping } from 'sdc-app/onboarding/onboard/OnboardConstants.js'; +import { tabsMapping as onboardCatalogTabsMapping } from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js'; +import { FilterFactory } from 'test-utils/factories/onboard/FilterFactories.js'; describe('Onboard Module Tests', () => { - it('should return default state', () => { - const store = storeCreator(); - const expectedStore = OnboardStoreFactory.build(); - expect(store.getState().onboard).toEqual(expectedStore); - }); + it('should return default state', () => { + const store = storeCreator(); + const expectedStore = OnboardStoreFactory.build(); + expect(store.getState().onboard).toEqual(expectedStore); + }); - it('should change active tab to Catalog', () => { - const store = storeCreator(); - const expectedStore = OnboardStoreFactory.build({activeTab: onboardTabsMapping.CATALOG}); - OnboardActionHelper.changeActiveTab(store.dispatch, onboardTabsMapping.CATALOG); - expect(store.getState().onboard).toEqual(expectedStore); - }); + it('should change active tab to Catalog', () => { + const store = storeCreator(); + const expectedStore = OnboardStoreFactory.build({ + activeTab: onboardTabsMapping.CATALOG, + filter: FilterFactory.build({ versionStatus: 'Certified' }) + }); + OnboardActionHelper.changeActiveTab( + store.dispatch, + onboardTabsMapping.CATALOG + ); + expect(store.getState().onboard).toEqual(expectedStore); + }); - it('should change searchValue', () => { - const store = storeCreator(); - const expectedStore = OnboardStoreFactory.build({searchValue: 'hello'}); - OnboardActionHelper.changeSearchValue(store.dispatch, 'hello'); - expect(store.getState().onboard).toEqual(expectedStore); - }); + it('should change searchValue', () => { + const store = storeCreator(); + const expectedStore = OnboardStoreFactory.build({ + searchValue: 'hello' + }); + OnboardActionHelper.changeSearchValue(store.dispatch, 'hello'); + expect(store.getState().onboard).toEqual(expectedStore); + }); - it('should clear searchValue', () => { - const store = storeCreator(); - const expectedStore = OnboardStoreFactory.build(); - OnboardActionHelper.changeSearchValue(store.dispatch, 'hello'); - OnboardActionHelper.clearSearchValue(store.dispatch); - expect(store.getState().onboard).toEqual(expectedStore); - }); - - it('should reset store', () => { - const store = storeCreator(); - const expectedStore = OnboardStoreFactory.build(); - OnboardActionHelper.changeSearchValue(store.dispatch, 'hello'); - OnboardActionHelper.changeActiveTab(store.dispatch, onboardTabsMapping.CATALOG); - OnboardingCatalogActionHelper.changeActiveTab(store.dispatch, onboardCatalogTabsMapping.ACTIVE); - OnboardActionHelper.resetOnboardStore(store.dispatch, 'hello'); - expect(store.getState().onboard).toEqual(expectedStore); - }); + it('should clear searchValue', () => { + const store = storeCreator(); + const expectedStore = OnboardStoreFactory.build(); + OnboardActionHelper.changeSearchValue(store.dispatch, 'hello'); + OnboardActionHelper.clearSearchValue(store.dispatch); + expect(store.getState().onboard).toEqual(expectedStore); + }); + it('should reset store', () => { + const store = storeCreator(); + const expectedStore = OnboardStoreFactory.build(); + OnboardActionHelper.changeSearchValue(store.dispatch, 'hello'); + OnboardActionHelper.changeActiveTab( + store.dispatch, + onboardTabsMapping.CATALOG + ); + OnboardingCatalogActionHelper.changeActiveTab( + store.dispatch, + onboardCatalogTabsMapping.ACTIVE + ); + OnboardActionHelper.resetOnboardStore(store.dispatch, 'hello'); + expect(store.getState().onboard).toEqual(expectedStore); + }); }); diff --git a/openecomp-ui/yarn.lock b/openecomp-ui/yarn.lock index e7b68d1f36..ac8d75704b 100644 --- a/openecomp-ui/yarn.lock +++ b/openecomp-ui/yarn.lock @@ -9459,9 +9459,9 @@ scss-tokenizer@^0.2.3: js-base64 "^2.1.8" source-map "^0.4.2" -sdc-ui@1.6.24: - version "1.6.24" - resolved "https://registry.yarnpkg.com/sdc-ui/-/sdc-ui-1.6.24.tgz#059b0fe6fdc36c962b65853a8012885aa38e78a7" +sdc-ui@1.6.27: + version "1.6.27" + resolved "https://registry.yarnpkg.com/sdc-ui/-/sdc-ui-1.6.27.tgz#d4ade66b5792355fe5758e2b7231a11c1d4c137f" dependencies: "@angular/common" "~2.4.8" "@angular/core" "~2.4.8" |