diff options
Diffstat (limited to 'openecomp-ui/src/sdc-app/onboarding/licenseModel')
48 files changed, 3970 insertions, 0 deletions
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/FinalizedLicenseModelListReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/FinalizedLicenseModelListReducer.js new file mode 100644 index 0000000000..a851e77dc8 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/FinalizedLicenseModelListReducer.js @@ -0,0 +1,30 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {actionTypes} from './LicenseModelConstants.js'; + +export default (state = [], action) => { + switch (action.type) { + case actionTypes.FINALIZED_LICENSE_MODELS_LIST_LOADED: + return [...action.response.results]; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js new file mode 100644 index 0000000000..ad91a0da65 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js @@ -0,0 +1,147 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {connect} from 'react-redux'; + +import i18n from 'nfvo-utils/i18n/i18n.js'; +import {statusEnum as versionStatusEnum} from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; +import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; +import TabulatedEditor from 'src/nfvo-components/editor/TabulatedEditor.jsx'; + +import {enums} from 'sdc-app/onboarding/OnboardingConstants.js'; +import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js'; + +import {navigationItems} from './LicenseModelConstants.js'; +import LicenseModelActionHelper from './LicenseModelActionHelper.js'; +import LicenseAgreementActionHelper from './licenseAgreement/LicenseAgreementActionHelper.js'; +import FeatureGroupsActionHelper from './featureGroups/FeatureGroupsActionHelper.js'; +import EntitlementPoolsActionHelper from './entitlementPools/EntitlementPoolsActionHelper.js'; +import LicenseKeyGroupsActionHelper from './licenseKeyGroups/LicenseKeyGroupsActionHelper.js'; + + +const buildNavigationBarProps = (licenseModel, screen) => { + const {id, vendorName, version} = licenseModel; + const meta = {version}; + + const groups = [{ + id, + name: vendorName, + items: [ + { + id: navigationItems.LICENSE_AGREEMENTS, + name: i18n('License Agreements'), + meta + }, + { + id: navigationItems.FEATURE_GROUPS, + name: i18n('Feature Groups'), + meta + }, + { + id: navigationItems.ENTITLEMENT_POOLS, + name: i18n('Entitlement Pools'), + meta + }, + { + id: navigationItems.LICENSE_KEY_GROUPS, + name: i18n('License Key Groups'), + meta + } + ] + }]; + + const activeItemId = ({ + [enums.SCREEN.LICENSE_AGREEMENTS]: navigationItems.LICENSE_AGREEMENTS, + [enums.SCREEN.FEATURE_GROUPS]: navigationItems.FEATURE_GROUPS, + [enums.SCREEN.ENTITLEMENT_POOLS]: navigationItems.ENTITLEMENT_POOLS, + [enums.SCREEN.LICENSE_KEY_GROUPS]: navigationItems.LICENSE_KEY_GROUPS + })[screen]; + + return { + activeItemId, groups + }; +}; + + +const buildVersionControllerProps = (licenseModel) => { + let {version, viewableVersions, status: currentStatus, lockingUser} = licenseModel; + let {status, isCheckedOut} = (currentStatus === versionStatusEnum.CHECK_OUT_STATUS) ? + VersionControllerUtils.getCheckOutStatusKindByUserID(currentStatus, lockingUser) : + {status: currentStatus, isCheckedOut: false}; + + return { + version, + viewableVersions, + status, + isCheckedOut + }; +}; + + +const mapStateToProps = ({licenseModel: {licenseModelEditor}}, {currentScreen: {screen}}) => { + return { + versionControllerProps: buildVersionControllerProps(licenseModelEditor.data), + navigationBarProps: buildNavigationBarProps(licenseModelEditor.data, screen) + }; +}; + + +const mapActionsToProps = (dispatch, {currentScreen: {screen, props: {licenseModelId}}}) => { + return { + onVersionControllerAction: action => + LicenseModelActionHelper.performVCAction(dispatch, {licenseModelId, action}).then(() => { + switch(screen) { + case enums.SCREEN.LICENSE_AGREEMENTS: + LicenseAgreementActionHelper.fetchLicenseAgreementList(dispatch, {licenseModelId}); + break; + case enums.SCREEN.FEATURE_GROUPS: + FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, {licenseModelId}); + break; + case enums.SCREEN.ENTITLEMENT_POOLS: + EntitlementPoolsActionHelper.fetchEntitlementPoolsList(dispatch, {licenseModelId}); + break; + case enums.SCREEN.LICENSE_KEY_GROUPS: + LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList(dispatch, {licenseModelId}); + break; + } + }), + onVersionSwitching: version => LicenseAgreementActionHelper.switchVersion(dispatch, {licenseModelId, version}), + onClose: () => OnboardingActionHelper.navigateToOnboardingCatalog(dispatch), + + onNavigate: ({id, meta: {version}}) => { + switch(id) { + case navigationItems.LICENSE_AGREEMENTS: + OnboardingActionHelper.navigateToLicenseAgreements(dispatch, {licenseModelId, version}); + break; + case navigationItems.FEATURE_GROUPS: + OnboardingActionHelper.navigateToFeatureGroups(dispatch, {licenseModelId, version}); + break; + case navigationItems.ENTITLEMENT_POOLS: + OnboardingActionHelper.navigateToEntitlementPools(dispatch, {licenseModelId, version}); + break; + case navigationItems.LICENSE_KEY_GROUPS: + OnboardingActionHelper.navigateToLicenseKeyGroups(dispatch, {licenseModelId, version}); + break; + } + } + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(TabulatedEditor); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js new file mode 100644 index 0000000000..a379a2c40f --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js @@ -0,0 +1,101 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; +import Configuration from 'sdc-app/config/Configuration.js'; +import {actionTypes} from './LicenseModelConstants.js'; +import {actionsEnum as vcActionsEnum} from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import NotificationConstants from 'nfvo-components/notifications/NotificationConstants.js'; + +function baseUrl() { + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-license-models/`; +} + +function fetchLicenseModels() { + return RestAPIUtil.fetch(baseUrl()); +} + +function fetchFinalizedLicenseModels() { + return RestAPIUtil.fetch(`${baseUrl()}?versionFilter=Final`); +} + +function fetchLicenseModelById(licenseModelId, version) { + let versionQuery = version ? `?version=${version}` : ''; + return RestAPIUtil.fetch(`${baseUrl()}${licenseModelId}${versionQuery}`); +} + +function putLicenseModelAction(id, action) { + return RestAPIUtil.save(`${baseUrl()}${id}/actions`, {action: action}); +} + +const LicenseModelActionHelper = { + + fetchLicenseModels(dispatch) { + return fetchLicenseModels().then(response => { + dispatch({ + type: actionTypes.LICENSE_MODELS_LIST_LOADED, + response + }); + }); + }, + + fetchFinalizedLicenseModels(dispatch) { + return fetchFinalizedLicenseModels().then(response => dispatch({ + type: actionTypes.FINALIZED_LICENSE_MODELS_LIST_LOADED, + response + })); + + }, + + fetchLicenseModelById(dispatch, {licenseModelId, version}) { + return fetchLicenseModelById(licenseModelId, version).then(response => { + if(version) { + response.version = version; + } + dispatch({ + type: actionTypes.LICENSE_MODEL_LOADED, + response + }); + }); + }, + + addLicenseModel(dispatch, {licenseModel}){ + dispatch({ + type: actionTypes.ADD_LICENSE_MODEL, + licenseModel + }); + }, + + performVCAction(dispatch, {licenseModelId, action}) { + return putLicenseModelAction(licenseModelId, action).then(() => { + if(action === vcActionsEnum.SUBMIT){ + dispatch({ + type: NotificationConstants.NOTIFY_SUCCESS, + data: {title: i18n('Submit Succeeded'), msg: i18n('This license model successfully submitted'), timeout: 2000} + }); + } + return LicenseModelActionHelper.fetchLicenseModelById(dispatch, {licenseModelId}); + }); + } +}; + +export default LicenseModelActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelConstants.js new file mode 100644 index 0000000000..13fa9f5284 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelConstants.js @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import keyMirror from 'nfvo-utils/KeyMirror.js'; + +export const actionTypes = keyMirror({ + LICENSE_MODEL_LOADED: null, + LICENSE_MODELS_LIST_LOADED: null, + FINALIZED_LICENSE_MODELS_LIST_LOADED: null, + ADD_LICENSE_MODEL: null, + EDIT_LICENSE_MODEL: null +}); + +export const navigationItems = keyMirror({ + LICENSE_AGREEMENTS: 'License Agreements', + FEATURE_GROUPS: 'Feature Groups', + ENTITLEMENT_POOLS: 'Entitlement Pools', + LICENSE_KEY_GROUPS: 'License Key Groups' +}); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelEditorReducer.js new file mode 100644 index 0000000000..e92e32aa9e --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelEditorReducer.js @@ -0,0 +1,33 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {actionTypes} from './LicenseModelConstants.js'; + +export default (state = {}, action) => { + switch (action.type) { + case actionTypes.LICENSE_MODEL_LOADED: + return { + ...state, + data: action.response + }; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelListReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelListReducer.js new file mode 100644 index 0000000000..8874c4ce21 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelListReducer.js @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {actionTypes} from './LicenseModelConstants.js'; + +export default (state = [], action) => { + switch (action.type) { + case actionTypes.LICENSE_MODELS_LIST_LOADED: + return [...action.response.results]; + case actionTypes.ADD_LICENSE_MODEL: + return [...state, action.licenseModel]; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js new file mode 100644 index 0000000000..5982b9f8ab --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {combineReducers} from 'redux'; + +import licenseModelCreationReducer from './creation/LicenseModelCreationReducer.js'; +import licenseModelEditorReducer from './LicenseModelEditorReducer.js'; + +import licenseAgreementListReducer from './licenseAgreement/LicenseAgreementListReducer.js'; +import licenseAgreementEditorReducer from './licenseAgreement/LicenseAgreementEditorReducer.js'; +import {actionTypes as licenseAgreementActionTypes} from './licenseAgreement/LicenseAgreementConstants.js'; + +import featureGroupsEditorReducer from './featureGroups/FeatureGroupsEditorReducer.js'; +import featureGroupsListReducer from './featureGroups/FeatureGroupsListReducer.js'; +import {actionTypes as featureGroupsActionConstants} from './featureGroups/FeatureGroupsConstants'; + +import entitlementPoolsListReducer from './entitlementPools/EntitlementPoolsListReducer.js'; +import entitlementPoolsEditorReducer from './entitlementPools/EntitlementPoolsEditorReducer.js'; +import {actionTypes as entitlementPoolsConstants} from './entitlementPools/EntitlementPoolsConstants'; + +import licenseKeyGroupsEditorReducer from './licenseKeyGroups/LicenseKeyGroupsEditorReducer.js'; +import licenseKeyGroupsListReducer from './licenseKeyGroups/LicenseKeyGroupsListReducer.js'; +import {actionTypes as licenseKeyGroupsConstants} from './licenseKeyGroups/LicenseKeyGroupsConstants.js'; + +export default combineReducers({ + licenseModelCreation: licenseModelCreationReducer, + licenseModelEditor: licenseModelEditorReducer, + + licenseAgreement: combineReducers({ + licenseAgreementEditor: licenseAgreementEditorReducer, + licenseAgreementList: licenseAgreementListReducer, + licenseAgreementToDelete: (state = false, action) => action.type === licenseAgreementActionTypes.LICENSE_AGREEMENT_DELETE_CONFIRM ? action.licenseAgreementToDelete : state + }), + featureGroup: combineReducers({ + featureGroupEditor: featureGroupsEditorReducer, + featureGroupsList: featureGroupsListReducer, + featureGroupToDelete: (state = false, action) => action.type === featureGroupsActionConstants.FEATURE_GROUPS_DELETE_CONFIRM ? action.featureGroupToDelete : state + }), + entitlementPool: combineReducers({ + entitlementPoolEditor: entitlementPoolsEditorReducer, + entitlementPoolsList: entitlementPoolsListReducer, + entitlementPoolToDelete: (state = false, action) => action.type === entitlementPoolsConstants.ENTITLEMENT_POOLS_DELETE_CONFIRM ? action.entitlementPoolToDelete : state + }), + licenseKeyGroup: combineReducers({ + licenseKeyGroupsEditor: licenseKeyGroupsEditorReducer, + licenseKeyGroupsList: licenseKeyGroupsListReducer, + licenseKeyGroupToDelete: (state = false, action) => action.type === licenseKeyGroupsConstants.LICENSE_KEY_GROUPS_DELETE_CONFIRM ? action.licenseKeyGroupToDelete : state + }), +}); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreation.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreation.js new file mode 100644 index 0000000000..63d0f27b6a --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreation.js @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {connect} from 'react-redux'; +import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js'; +import LicenseModelCreationActionHelper from './LicenseModelCreationActionHelper.js'; +import LicenseModelCreationView from './LicenseModelCreationView.jsx'; + +const mapStateToProps = ({licenseModel: {licenseModelCreation}}) => licenseModelCreation; + +const mapActionsToProps = (dispatch) => { + return { + onDataChanged: deltaData => LicenseModelCreationActionHelper.dataChanged(dispatch, {deltaData}), + onCancel: () => LicenseModelCreationActionHelper.close(dispatch), + onSubmit: (licenseModel) => { + LicenseModelCreationActionHelper.close(dispatch); + LicenseModelCreationActionHelper.createLicenseModel(dispatch, {licenseModel}).then(licenseModelId => { + OnboardingActionHelper.navigateToLicenseAgreements(dispatch, {licenseModelId}); + }); + } + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(LicenseModelCreationView); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationActionHelper.js new file mode 100644 index 0000000000..c2a0409bd2 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationActionHelper.js @@ -0,0 +1,72 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; +import Configuration from 'sdc-app/config/Configuration.js'; +import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js'; +import {actionTypes} from './LicenseModelCreationConstants.js'; + +function baseUrl() { + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-license-models/`; +} + +function createLicenseModel(licenseModel) { + return RestAPIUtil.create(baseUrl(), { + vendorName: licenseModel.vendorName, + description: licenseModel.description, + iconRef: 'icon' + }); +} + + +export default { + + open(dispatch) { + dispatch({ + type: actionTypes.OPEN + }); + }, + + close(dispatch){ + dispatch({ + type: actionTypes.CLOSE + }); + }, + + dataChanged(dispatch, {deltaData}){ + dispatch({ + type: actionTypes.DATA_CHANGED, + deltaData + }); + }, + + createLicenseModel(dispatch, {licenseModel}){ + return createLicenseModel(licenseModel).then(response => { + LicenseModelActionHelper.addLicenseModel(dispatch, { + licenseModel: { + ...licenseModel, + id: response.value + } + }); + return response.value; + }); + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationConstants.js new file mode 100644 index 0000000000..603d177048 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationConstants.js @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import keyMirror from 'nfvo-utils/KeyMirror.js'; + +export const actionTypes = keyMirror({ + OPEN: null, + CLOSE: null, + DATA_CHANGED: null +}); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationReducer.js new file mode 100644 index 0000000000..a54d1b3089 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationReducer.js @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {actionTypes} from './LicenseModelCreationConstants.js'; + +export default (state = {}, action) => { + switch (action.type) { + case actionTypes.OPEN: + return { + ...state, + data: {} + }; + case actionTypes.CLOSE: + return {}; + case actionTypes.DATA_CHANGED: + return { + ...state, + data: { + ...state.data, + ...action.deltaData + } + }; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationView.jsx new file mode 100644 index 0000000000..4dccc9e1c4 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationView.jsx @@ -0,0 +1,60 @@ +import React from 'react'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import ValidationInput from 'nfvo-components/input/validation/ValidationInput.jsx'; +import ValidationForm from 'nfvo-components/input/validation/ValidationForm.jsx'; + +const LicenseModelPropType = React.PropTypes.shape({ + id: React.PropTypes.string, + vendorName: React.PropTypes.string, + description: React.PropTypes.string +}); + +class LicenseModelCreationView extends React.Component { + + static propTypes = { + data: LicenseModelPropType, + onDataChanged: React.PropTypes.func.isRequired, + onSubmit: React.PropTypes.func.isRequired, + onCancel: React.PropTypes.func.isRequired + }; + + render() { + let {data = {}, onDataChanged} = this.props; + let {vendorName, description} = data; + return ( + <div> + <ValidationForm + ref='validationForm' + hasButtons={true} + onSubmit={ () => this.submit() } + onReset={ () => this.props.onCancel() } + labledButtons={true}> + <ValidationInput + value={vendorName} + label={i18n('Vendor Name')} + ref='vendor-name' + onChange={vendorName => onDataChanged({vendorName})} + validations={{maxLength: 25, required: true}} + type='text' + className='field-section'/> + <ValidationInput + value={description} + label={i18n('Description')} + ref='description' + onChange={description => onDataChanged({description})} + validations={{maxLength: 1000, required: true}} + type='textarea' + className='field-section'/> + </ValidationForm> + </div> + ); + } + + + submit() { + const {data:licenseModel} = this.props; + this.props.onSubmit(licenseModel); + } +} + +export default LicenseModelCreationView; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js new file mode 100644 index 0000000000..631597a5b0 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js @@ -0,0 +1,149 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; +import Configuration from 'sdc-app/config/Configuration.js'; +import {actionTypes as entitlementPoolsActionTypes } from './EntitlementPoolsConstants.js'; +import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js'; + +function baseUrl(licenseModelId) { + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-license-models/${licenseModelId}/entitlement-pools`; +} + +function fetchEntitlementPoolsList(licenseModelId, version) { + let versionQuery = version ? `?version=${version}` : ''; + return RestAPIUtil.fetch(`${baseUrl(licenseModelId)}${versionQuery}`); +} + +function postEntitlementPool(licenseModelId, entitlementPool) { + return RestAPIUtil.create(baseUrl(licenseModelId), { + name: entitlementPool.name, + description: entitlementPool.description, + thresholdValue: entitlementPool.thresholdValue, + thresholdUnits: entitlementPool.thresholdUnits, + entitlementMetric: entitlementPool.entitlementMetric, + increments: entitlementPool.increments, + aggregationFunction: entitlementPool.aggregationFunction, + operationalScope: entitlementPool.operationalScope, + time: entitlementPool.time, + manufacturerReferenceNumber: entitlementPool.manufacturerReferenceNumber + }); +} + + +function putEntitlementPool(licenseModelId, previousEntitlementPool, entitlementPool) { + return RestAPIUtil.save(`${baseUrl(licenseModelId)}/${entitlementPool.id}`, { + name: entitlementPool.name, + description: entitlementPool.description, + thresholdValue: entitlementPool.thresholdValue, + thresholdUnits: entitlementPool.thresholdUnits, + entitlementMetric: entitlementPool.entitlementMetric, + increments: entitlementPool.increments, + aggregationFunction: entitlementPool.aggregationFunction, + operationalScope: entitlementPool.operationalScope, + time: entitlementPool.time, + manufacturerReferenceNumber: entitlementPool.manufacturerReferenceNumber + }); +} + +function deleteEntitlementPool(licenseModelId, entitlementPoolId) { + return RestAPIUtil.destroy(`${baseUrl(licenseModelId)}/${entitlementPoolId}`); +} + + +export default { + fetchEntitlementPoolsList(dispatch, {licenseModelId, version}) { + return fetchEntitlementPoolsList(licenseModelId, version).then(response => dispatch({ + type: entitlementPoolsActionTypes.ENTITLEMENT_POOLS_LIST_LOADED, + response + })); + }, + + openEntitlementPoolsEditor(dispatch, {entitlementPool} = {}) { + dispatch({ + type: entitlementPoolsActionTypes.entitlementPoolsEditor.OPEN, + entitlementPool + }); + }, + + deleteEntitlementPool(dispatch, {licenseModelId, entitlementPoolId}) { + return deleteEntitlementPool(licenseModelId, entitlementPoolId).then(() => { + dispatch({ + type: entitlementPoolsActionTypes.DELETE_ENTITLEMENT_POOL, + entitlementPoolId + }); + }); + }, + + entitlementPoolsEditorDataChanged(dispatch, {deltaData}) { + dispatch({ + type: entitlementPoolsActionTypes.entitlementPoolsEditor.DATA_CHANGED, + deltaData + }); + }, + + closeEntitlementPoolsEditor(dispatch) { + dispatch({ + type: entitlementPoolsActionTypes.entitlementPoolsEditor.CLOSE + }); + }, + + saveEntitlementPool(dispatch, {licenseModelId, previousEntitlementPool, entitlementPool}) { + if (previousEntitlementPool) { + return putEntitlementPool(licenseModelId, previousEntitlementPool, entitlementPool).then(() => { + dispatch({ + type: entitlementPoolsActionTypes.EDIT_ENTITLEMENT_POOL, + entitlementPool + }); + }); + } + else { + return postEntitlementPool(licenseModelId, entitlementPool).then(response => { + dispatch({ + type: entitlementPoolsActionTypes.ADD_ENTITLEMENT_POOL, + entitlementPool: { + ...entitlementPool, + id: response.value + } + }); + }); + } + }, + + hideDeleteConfirm(dispatch) { + dispatch({ + type: entitlementPoolsActionTypes.ENTITLEMENT_POOLS_DELETE_CONFIRM, + entitlementPoolToDelete: false + }); + }, + openDeleteEntitlementPoolConfirm(dispatch, {entitlementPool}) { + dispatch({ + type: entitlementPoolsActionTypes.ENTITLEMENT_POOLS_DELETE_CONFIRM, + entitlementPoolToDelete: entitlementPool + }); + }, + + switchVersion(dispatch, {licenseModelId, version}) { + LicenseModelActionHelper.fetchLicenseModelById(dispatch, {licenseModelId, version}).then(() => { + this.fetchEntitlementPoolsList(dispatch, {licenseModelId, version}); + }); + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConfirmationModal.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConfirmationModal.jsx new file mode 100644 index 0000000000..04f038f5f0 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConfirmationModal.jsx @@ -0,0 +1,51 @@ +import React from 'react'; +import {connect} from 'react-redux'; +import ConfirmationModalView from 'nfvo-components/confirmations/ConfirmationModalView.jsx'; +import EntitlementPoolsActionHelper from './EntitlementPoolsActionHelper.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +function renderMsg(entitlementPoolToDelete) { + let poolName = entitlementPoolToDelete ? entitlementPoolToDelete.name : ''; + let msg = i18n('Are you sure you want to delete "{poolName}"?', {poolName}); + let subMsg = entitlementPoolToDelete + && entitlementPoolToDelete.referencingFeatureGroups + && entitlementPoolToDelete.referencingFeatureGroups.length > 0 ? + i18n('This entitlement pool is associated with one or more feature groups') : + ''; + return ( + <div> + <p>{msg}</p> + <p>{subMsg}</p> + </div> + ); +}; + +const mapStateToProps = ({licenseModel: {entitlementPool}}, {licenseModelId}) => { + let {entitlementPoolToDelete} = entitlementPool; + const show = entitlementPoolToDelete !== false; + return { + show, + title: 'Warning!', + type: 'warning', + msg: renderMsg(entitlementPoolToDelete), + confirmationDetails: {entitlementPoolToDelete, licenseModelId} + }; +}; + +const mapActionsToProps = (dispatch) => { + return { + onConfirmed: ({entitlementPoolToDelete, licenseModelId}) => { + EntitlementPoolsActionHelper.deleteEntitlementPool(dispatch, { + licenseModelId, + entitlementPoolId: entitlementPoolToDelete.id + }); + EntitlementPoolsActionHelper.hideDeleteConfirm(dispatch); + }, + onDeclined: () => { + EntitlementPoolsActionHelper.hideDeleteConfirm(dispatch); + } + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(ConfirmationModalView); + diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js new file mode 100644 index 0000000000..8a855076f3 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js @@ -0,0 +1,112 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import keyMirror from 'nfvo-utils/KeyMirror.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +export const actionTypes = keyMirror({ + + ENTITLEMENT_POOLS_LIST_LOADED: null, + ADD_ENTITLEMENT_POOL: null, + EDIT_ENTITLEMENT_POOL: null, + DELETE_ENTITLEMENT_POOL: null, + ENTITLEMENT_POOLS_DELETE_CONFIRM: null, + + entitlementPoolsEditor: { + OPEN: null, + CLOSE: null, + DATA_CHANGED: null, + } + +}); + +export const enums = keyMirror({ + SELECTED_FEATURE_GROUP_TAB: { + GENERAL: 1, + ENTITLEMENT_POOLS: 2, + LICENCE_KEY_GROUPS: 3 + }, + SELECTED_ENTITLEMENT_POOLS_BUTTONTAB: { + ASSOCIATED_ENTITLEMENT_POOLS: 1, + AVAILABLE_ENTITLEMENT_POOLS: 2 + } +}); + +export const defaultState = { + ENTITLEMENT_POOLS_EDITOR_DATA: { + entitlementMetric: {choice: '', other: ''}, + aggregationFunction: {choice: '', other: ''}, + operationalScope: {choices: [], other: ''}, + time: {choice: '', other: ''} + } +}; + +export const thresholdUnitType = { + ABSOLUTE: 'Absolute', + PERCENTAGE: 'Percentage' +}; + +export const optionsInputValues = { + OPERATIONAL_SCOPE: [ + {enum: '', title: i18n('please select…')}, + {enum: 'Network_Wide', title: 'Network Wide'}, + {enum: 'Availability_Zone', title: 'Availability Zone'}, + {enum: 'Data_Center', title: 'Data Center'}, + {enum: 'Tenant', title: 'Tenant'}, + {enum: 'VM', title: 'VM'}, + {enum: 'CPU', title: 'CPU'}, + {enum: 'Core', title: 'Core'} + ], + TIME: [ + {enum: '', title: i18n('please select…')}, + {enum: 'Hour', title: 'Hour'}, + {enum: 'Day', title: 'Day'}, + {enum: 'Month', title: 'Month'} + ], + AGGREGATE_FUNCTION: [ + {enum: '', title: i18n('please select…')}, + {enum: 'Peak', title: 'Peak'}, + {enum: 'Average', title: 'Average'} + ], + ENTITLEMENT_METRIC: [ + {enum: '', title: i18n('please select…')}, + {enum: 'Software_Instances_Count', title: 'Software Instances'}, + {enum: 'Core', title: 'Core'}, + {enum: 'CPU', title: 'CPU'}, + {enum: 'Trunks', title: 'Trunks'}, + {enum: 'User', title: 'User'}, + {enum: 'Subscribers', title: 'Subscribers'}, + {enum: 'Tenants', title: 'Tenants'}, + {enum: 'Tokens', title: 'Tokens'}, + {enum: 'Seats', title: 'Seats'}, + {enum: 'Units_TB', title: 'Units-TB'}, + {enum: 'Units_GB', title: 'Units-GB'}, + {enum: 'Units_MB', title: 'Units-MB'} + ], + THRESHOLD_UNITS: [ + {enum: '', title: i18n('please select…')}, + {enum: thresholdUnitType.ABSOLUTE, title: 'Absolute'}, + {enum: thresholdUnitType.PERCENTAGE, title: '%'} + ] +}; + + + + diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditor.js new file mode 100644 index 0000000000..d5bd07e929 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditor.js @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {connect} from 'react-redux'; +import EntitlementPoolsActionHelper from './EntitlementPoolsActionHelper.js'; +import EntitlementPoolsEditorView from './EntitlementPoolsEditorView.jsx'; + +const mapStateToProps = ({licenseModel: {entitlementPool}}) => { + + + let {data} = entitlementPool.entitlementPoolEditor; + + let previousData; + const entitlementPoolId = data ? data.id : null; + if(entitlementPoolId) { + previousData = entitlementPool.entitlementPoolsList.find(entitlementPool => entitlementPool.id === entitlementPoolId); + } + + return { + data, + previousData + }; +}; + +const mapActionsToProps = (dispatch, {licenseModelId}) => { + return { + onDataChanged: deltaData => EntitlementPoolsActionHelper.entitlementPoolsEditorDataChanged(dispatch, {deltaData}), + onCancel: () => EntitlementPoolsActionHelper.closeEntitlementPoolsEditor(dispatch), + onSubmit: ({previousEntitlementPool, entitlementPool}) => { + EntitlementPoolsActionHelper.closeEntitlementPoolsEditor(dispatch); + EntitlementPoolsActionHelper.saveEntitlementPool(dispatch, {licenseModelId, previousEntitlementPool, entitlementPool}); + } + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(EntitlementPoolsEditorView); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorReducer.js new file mode 100644 index 0000000000..86e97ecf8d --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorReducer.js @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {actionTypes, defaultState} from './EntitlementPoolsConstants.js'; + +export default (state = {}, action) => { + switch (action.type) { + case actionTypes.entitlementPoolsEditor.OPEN: + return { + ...state, + data: action.entitlementPool ? {...action.entitlementPool} : defaultState.ENTITLEMENT_POOLS_EDITOR_DATA + }; + case actionTypes.entitlementPoolsEditor.DATA_CHANGED: + return { + ...state, + data: { + ...state.data, + ...action.deltaData + } + }; + case actionTypes.entitlementPoolsEditor.CLOSE: + return {}; + default: + return state; + } + +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorView.jsx new file mode 100644 index 0000000000..77c5a12e03 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorView.jsx @@ -0,0 +1,167 @@ +import React from 'react'; + + +import i18n from 'nfvo-utils/i18n/i18n.js'; + +import ValidationForm from 'nfvo-components/input/validation/ValidationForm.jsx'; +import ValidationInput from 'nfvo-components/input/validation/ValidationInput.jsx'; +import {optionsInputValues as EntitlementPoolsOptionsInputValues, thresholdUnitType} from './EntitlementPoolsConstants.js'; +import {other as optionInputOther} from 'nfvo-components/input/inputOptions/InputOptions.jsx'; + + +const EntitlementPoolPropType = React.PropTypes.shape({ + id: React.PropTypes.string, + name: React.PropTypes.string, + description: React.PropTypes.string, + manufacturerReferenceNumber: React.PropTypes.string, + operationalScope: React.PropTypes.shape({ + choices: React.PropTypes.array, + other: React.PropTypes.string + }), + aggregationFunction: React.PropTypes.shape({ + choice: React.PropTypes.string, + other: React.PropTypes.string + }), + increments: React.PropTypes.string, + time: React.PropTypes.shape({ + choice: React.PropTypes.string, + other: React.PropTypes.string + }), + entitlementMetric: React.PropTypes.shape({ + choice: React.PropTypes.string, + other: React.PropTypes.string + }) +}); + +class EntitlementPoolsEditorView extends React.Component { + + static propTypes = { + data: EntitlementPoolPropType, + previousData: EntitlementPoolPropType, + isReadOnlyMode: React.PropTypes.bool, + onDataChanged: React.PropTypes.func.isRequired, + onSubmit: React.PropTypes.func.isRequired, + onCancel: React.PropTypes.func.isRequired + }; + + static defaultProps = { + data: {} + }; + + render() { + let {data = {}, onDataChanged, isReadOnlyMode} = this.props; + let { + name, description, manufacturerReferenceNumber, operationalScope, aggregationFunction, thresholdUnits, thresholdValue, + increments, time, entitlementMetric} = data; + let thresholdValueValidation = thresholdUnits === thresholdUnitType.PERCENTAGE ? {numeric: true, required: true, maxValue: 100} : {numeric: true, required: true}; + let timeValidation = time && time.choice === optionInputOther.OTHER ? {numeric: true, required: true} : {required: true}; + + return ( + <ValidationForm + ref='validationForm' + hasButtons={true} + onSubmit={ () => this.submit() } + onReset={ () => this.props.onCancel() } + labledButtons={true} + isReadOnlyMode={isReadOnlyMode} + className='entitlement-pools-form'> + <div className='entitlement-pools-form-row'> + <ValidationInput + onChange={name => onDataChanged({name})} + label={i18n('Name')} + value={name} + validations={{maxLength: 120, required: true}} + type='text'/> + + <ValidationInput + isMultiSelect={true} + onEnumChange={operationalScope => onDataChanged({operationalScope:{choices: operationalScope, other: ''}})} + onOtherChange={operationalScope => onDataChanged({operationalScope:{choices: [optionInputOther.OTHER], other: operationalScope}})} + multiSelectedEnum={operationalScope && operationalScope.choices} + label={i18n('Operational Scope')} + otherValue={operationalScope && operationalScope.other} + validations={{required: true}} + values={EntitlementPoolsOptionsInputValues.OPERATIONAL_SCOPE}/> + + </div> + <div className='entitlement-pools-form-row'> + <ValidationInput + onChange={description => onDataChanged({description})} + label={i18n('Description')} + value={description} + validations={{maxLength: 1000, required: true}} + type='textarea'/> + <div className='entitlement-pools-form-row-group'> + <div className='entitlement-pools-form-row'> + <ValidationInput + onEnumChange={thresholdUnits => onDataChanged({thresholdUnits})} + selectedEnum={thresholdUnits} + label={i18n('Threshold Value')} + type='select' + values={EntitlementPoolsOptionsInputValues.THRESHOLD_UNITS} + validations={{required: true}}/> + <ValidationInput + className='entitlement-pools-form-row-threshold-value' + onChange={thresholdValue => onDataChanged({thresholdValue})} + value={thresholdValue} + validations={thresholdValueValidation} + type='text'/> + </div> + + <ValidationInput + onEnumChange={entitlementMetric => onDataChanged({entitlementMetric:{choice: entitlementMetric, other: ''}})} + onOtherChange={entitlementMetric => onDataChanged({entitlementMetric:{choice: optionInputOther.OTHER, other: entitlementMetric}})} + selectedEnum={entitlementMetric && entitlementMetric.choice} + otherValue={entitlementMetric && entitlementMetric.other} + label={i18n('Entitlement Metric')} + validations={{required: true}} + values={EntitlementPoolsOptionsInputValues.ENTITLEMENT_METRIC}/> + <ValidationInput + onEnumChange={aggregationFunction => onDataChanged({aggregationFunction:{choice: aggregationFunction, other: ''}})} + onOtherChange={aggregationFunction => onDataChanged({aggregationFunction:{choice: optionInputOther.OTHER, other: aggregationFunction}})} + selectedEnum={aggregationFunction && aggregationFunction.choice} + otherValue={aggregationFunction && aggregationFunction.other} + validations={{required: true}} + label={i18n('Aggregate Function')} + values={EntitlementPoolsOptionsInputValues.AGGREGATE_FUNCTION}/> + + </div> + </div> + <div className='entitlement-pools-form-row'> + + <ValidationInput + onChange={manufacturerReferenceNumber => onDataChanged({manufacturerReferenceNumber})} + label={i18n('Manufacturer Reference Number')} + value={manufacturerReferenceNumber} + validations={{maxLength: 100, required: true}} + type='text'/> + + <ValidationInput + onEnumChange={time => onDataChanged({time:{choice: time, other: ''}})} + onOtherChange={time => onDataChanged({time:{choice: optionInputOther.OTHER, other: time}})} + selectedEnum={time && time.choice} + otherValue={time && time.other} + validations={timeValidation} + label={i18n('Time')} + values={EntitlementPoolsOptionsInputValues.TIME}/> + </div> + <div className='entitlement-pools-form-row'> + <ValidationInput + onChange={increments => onDataChanged({increments})} + label={i18n('Increments')} + value={increments} + validations={{maxLength: 120}} + type='text'/> + + </div> + </ValidationForm> + ); + } + + submit() { + const {data: entitlementPool, previousData: previousEntitlementPool} = this.props; + this.props.onSubmit({entitlementPool, previousEntitlementPool}); + } +} + +export default EntitlementPoolsEditorView; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditor.js new file mode 100644 index 0000000000..4b21a2fea8 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditor.js @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {connect} from 'react-redux'; +import EntitlementPoolsActionHelper from './EntitlementPoolsActionHelper.js'; +import EntitlementPoolsListEditorView from './EntitlementPoolsListEditorView.jsx'; +import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; + +const mapStateToProps = ({licenseModel: {entitlementPool, licenseModelEditor}}) => { + let {entitlementPoolsList} = entitlementPool; + let {data} = entitlementPool.entitlementPoolEditor; + + let {vendorName} = licenseModelEditor.data; + let isReadOnlyMode = VersionControllerUtils.isReadOnly(licenseModelEditor.data); + + return { + vendorName, + entitlementPoolsList, + isReadOnlyMode, + isDisplayModal: Boolean(data), + isModalInEditMode: Boolean(data && data.id), + }; +}; + +const mapActionsToProps = (dispatch, {licenseModelId}) => { + return { + onAddEntitlementPoolClick: () => EntitlementPoolsActionHelper.openEntitlementPoolsEditor(dispatch), + onEditEntitlementPoolClick: entitlementPool => EntitlementPoolsActionHelper.openEntitlementPoolsEditor(dispatch, {entitlementPool}), + onDeleteEntitlementPool: entitlementPool => EntitlementPoolsActionHelper.openDeleteEntitlementPoolConfirm(dispatch, { + licenseModelId, + entitlementPool + }) + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(EntitlementPoolsListEditorView); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditorView.jsx new file mode 100644 index 0000000000..52df102503 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditorView.jsx @@ -0,0 +1,132 @@ +import React from 'react'; + +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Modal from 'nfvo-components/modal/Modal.jsx'; +import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; +import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx'; + +import EntitlementPoolsEditor from './EntitlementPoolsEditor.js'; +import InputOptions, {other as optionInputOther} from 'nfvo-components/input/inputOptions/InputOptions.jsx'; +import {optionsInputValues} from './EntitlementPoolsConstants'; +import EntitlementPoolsConfirmationModal from './EntitlementPoolsConfirmationModal.jsx'; + + +class EntitlementPoolsListEditorView extends React.Component { + static propTypes = { + vendorName: React.PropTypes.string, + licenseModelId: React.PropTypes.string.isRequired, + entitlementPoolsList: React.PropTypes.array, + isReadOnlyMode: React.PropTypes.bool.isRequired, + isDisplayModal: React.PropTypes.bool, + isModalInEditMode: React.PropTypes.bool, + onAddEntitlementPoolClick: React.PropTypes.func, + onEditEntitlementPoolClick: React.PropTypes.func, + onDeleteEntitlementPool: React.PropTypes.func, + }; + + static defaultProps = { + entitlementPoolsList: [] + }; + + state = { + localFilter: '' + }; + + render() { + let {licenseModelId, vendorName, isReadOnlyMode, isDisplayModal, isModalInEditMode} = this.props; + let {onAddEntitlementPoolClick} = this.props; + const {localFilter} = this.state; + + return ( + <div className='entitlement-pools-list-editor'> + <ListEditorView + title={i18n('Entitlement Pools for {vendorName} License Model', {vendorName})} + plusButtonTitle={i18n('Add Entitlement Pool')} + onAdd={onAddEntitlementPoolClick} + filterValue={localFilter} + onFilter={filter => this.setState({localFilter: filter})} + isReadOnlyMode={isReadOnlyMode}> + {this.filterList().map(entitlementPool => this.renderEntitlementPoolListItem(entitlementPool, isReadOnlyMode))} + </ListEditorView> + <Modal show={isDisplayModal} bsSize='large' animation={true} className='entitlement-pools-modal'> + <Modal.Header> + <Modal.Title>{`${isModalInEditMode ? i18n('Edit Entitlement Pool') : i18n('Create New Entitlement Pool')}`}</Modal.Title> + </Modal.Header> + <Modal.Body> + { + isDisplayModal && ( + <EntitlementPoolsEditor licenseModelId={licenseModelId} isReadOnlyMode={isReadOnlyMode}/> + ) + } + </Modal.Body> + </Modal> + + <EntitlementPoolsConfirmationModal licenseModelId={licenseModelId}/> + </div> + ); + } + + filterList() { + let {entitlementPoolsList} = this.props; + let {localFilter} = this.state; + if(localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return entitlementPoolsList.filter(({name = '', description = ''}) => { + return escape(name).match(filter) || escape(description).match(filter); + }); + } + else { + return entitlementPoolsList; + } + } + + renderEntitlementPoolListItem(entitlementPool, isReadOnlyMode) { + let {id, name, description, thresholdValue, thresholdUnits, entitlementMetric, aggregationFunction, + manufacturerReferenceNumber, time} = entitlementPool; + let {onEditEntitlementPoolClick, onDeleteEntitlementPool} = this.props; + return ( + <ListEditorItemView + key={id} + onSelect={() => onEditEntitlementPoolClick(entitlementPool)} + onDelete={() => onDeleteEntitlementPool(entitlementPool)} + className='list-editor-item-view' + isReadOnlyMode={isReadOnlyMode}> + <div className='list-editor-item-view-field'> + <div className='title'>{i18n('Name')}</div> + <div className='text name'>{name}</div> + </div> + + <div className='list-editor-item-view-field'> + <div className='title'>{i18n('Entitlement')}</div> + <div className='entitlement-parameters'>{`${this.extractValue(aggregationFunction)} ${this.extractValue(entitlementMetric)} per ${this.extractValue(time)}`}</div> + <div className='entitlement-pools-count'>{`${thresholdValue ? thresholdValue : ''} ${this.extractUnits(thresholdUnits)}`}</div> + </div> + + <div className='list-editor-item-view-field'> + <div className='title'>{i18n('Manufacturer Reference Number')}</div> + <div className='text contract-number'>{manufacturerReferenceNumber}</div> + </div> + + <div className='list-editor-item-view-field'> + <div className='title'>{i18n('Description')}</div> + <div className='text description'>{description}</div> + </div> + </ListEditorItemView> + ); + } + + + + extractUnits(units) { + if (units === undefined) {return '';} //TODO fix it later + return units === 'Absolute' ? '' : '%'; + } + + extractValue(item) { + if (item === undefined) {return '';} //TODO fix it later + + return item ? item.choice === optionInputOther.OTHER ? item.other : InputOptions.getTitleByName(optionsInputValues, item.choice) : ''; + } +} + +export default EntitlementPoolsListEditorView; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListReducer.js new file mode 100644 index 0000000000..63e351fce7 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListReducer.js @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {actionTypes} from './EntitlementPoolsConstants'; +export default (state = [], action) => { + switch (action.type) { + case actionTypes.ENTITLEMENT_POOLS_LIST_LOADED: + return [...action.response.results]; + case actionTypes.ADD_ENTITLEMENT_POOL: + return [...state, action.entitlementPool]; + case actionTypes.EDIT_ENTITLEMENT_POOL: + const indexForEdit = state.findIndex(entitlementPool => entitlementPool.id === action.entitlementPool.id); + return [...state.slice(0, indexForEdit), action.entitlementPool, ...state.slice(indexForEdit + 1)]; + case actionTypes.DELETE_ENTITLEMENT_POOL: + return state.filter(entitlementPool => entitlementPool.id !== action.entitlementPoolId); + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditor.js new file mode 100644 index 0000000000..c2b269bcf9 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditor.js @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {connect} from 'react-redux'; + +import FeatureGroupsActionHelper from './FeatureGroupsActionHelper.js'; +import FeatureGroupEditorView from './FeatureGroupEditorView.jsx'; + +const mapStateToProps = ({licenseModel: {featureGroup, entitlementPool, licenseKeyGroup}}) => { + + const {featureGroupEditor} = featureGroup; + + let {data, selectedTab, selectedEntitlementPoolsButtonTab, selectedLicenseKeyGroupsButtonTab} = featureGroupEditor; + + let previousData; + const featureGroupId = data ? data.id : null; + if (featureGroupId) { + previousData = featureGroup.featureGroupsList.find(featureGroup => featureGroup.id === featureGroupId); + } + let {entitlementPoolsList = []} = entitlementPool; + let {licenseKeyGroupsList = []} = licenseKeyGroup; + + return { + data, + previousData, + selectedTab, + selectedEntitlementPoolsButtonTab, + selectedLicenseKeyGroupsButtonTab, + entitlementPoolsList, + licenseKeyGroupsList + }; +}; + + +const mapActionsToProps = (dispatch, {licenseModelId}) => { + return { + onTabSelect: tab => FeatureGroupsActionHelper.selectEntitlementPoolsEditorTab(dispatch, {tab}), + onEntitlementPoolsButtonTabSelect: buttonTab => FeatureGroupsActionHelper.selectFeatureGroupsEditorEntitlementPoolsButtonTab(dispatch, {buttonTab}), + onLicenseKeyGroupsButtonTabSelect: buttonTab => FeatureGroupsActionHelper.selectFeatureGroupsEditorLicenseKeyGroupsButtonTab(dispatch, {buttonTab}), + onDataChanged: deltaData => FeatureGroupsActionHelper.featureGroupsEditorDataChanged(dispatch, {deltaData}), + onSubmit: (previousFeatureGroup, featureGroup) => { + FeatureGroupsActionHelper.closeFeatureGroupsEditor(dispatch); + FeatureGroupsActionHelper.saveFeatureGroup(dispatch, {licenseModelId, previousFeatureGroup, featureGroup}); + } + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(FeatureGroupEditorView); + diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditorView.jsx new file mode 100644 index 0000000000..6fecd16b71 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditorView.jsx @@ -0,0 +1,339 @@ +import React from 'react'; +import ValidationTabs from 'nfvo-components/input/validation/ValidationTabs.jsx'; +import ValidationTab from 'nfvo-components/input/validation/ValidationTab.jsx'; +import ButtonGroup from 'react-bootstrap/lib/ButtonGroup.js'; +import Button from 'react-bootstrap/lib/Button.js'; + +import ValidationForm from 'nfvo-components/input/validation/ValidationForm.jsx'; +import DualListboxView from 'nfvo-components/input/dualListbox/DualListboxView.jsx'; +import ValidationInput from 'nfvo-components/input/validation/ValidationInput.jsx'; +import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; +import ListEditorViewItem from 'nfvo-components/listEditor/ListEditorItemView.jsx'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +import {state as FeatureGroupStateConstants} from './FeatureGroupsConstants.js'; + +const FeatureGroupsPropType = React.PropTypes.shape({ + id: React.PropTypes.string, + name: React.PropTypes.string, + description: React.PropTypes.string, + partNumber: React.PropTypes.string, + entitlementPoolsIds: React.PropTypes.array(React.PropTypes.string), + licenseKeyGroupsIds: React.PropTypes.array(React.PropTypes.string) +}); + +class FeatureGroupEditorView extends React.Component { + + + static propTypes = { + data: FeatureGroupsPropType, + previousData: FeatureGroupsPropType, + isReadOnlyMode: React.PropTypes.bool, + + onSubmit: React.PropTypes.func, + onCancel: React.PropTypes.func, + + selectedTab: React.PropTypes.number, + onTabSelect: React.PropTypes.func, + + selectedEntitlementPoolsButtonTab: React.PropTypes.number, + selectedLicenseKeyGroupsButtonTab: React.PropTypes.number, + onEntitlementPoolsButtonTabSelect: React.PropTypes.func, + onLicenseKeyGroupsButtonTabSelect: React.PropTypes.func, + + entitlementPoolsList: DualListboxView.propTypes.availableList, + licenseKeyGroupsList: DualListboxView.propTypes.availableList + }; + + + static defaultProps = { + data: {}, + selectedTab: FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.GENERAL, + selectedEntitlementPoolsButtonTab: FeatureGroupStateConstants.SELECTED_ENTITLEMENT_POOLS_BUTTONTAB.ASSOCIATED_ENTITLEMENT_POOLS, + selectedLicenseKeyGroupsButtonTab: FeatureGroupStateConstants.SELECTED_LICENSE_KEY_GROUPS_BUTTONTAB.ASSOCIATED_LICENSE_KEY_GROUPS + }; + + state = { + localEntitlementPoolsListFilter: '', + localLicenseKeyGroupsListFilter: '' + }; + + + render() { + let {selectedTab, onTabSelect, isReadOnlyMode} = this.props; + return ( + <ValidationForm + ref='validationForm' + hasButtons={true} + onSubmit={ () => this.submit() } + onReset={ () => this.props.onCancel() } + labledButtons={true} + isReadOnlyMode={isReadOnlyMode} + name='feature-group-validation-form' + className='feature-group-form'> + <ValidationTabs activeKey={onTabSelect ? selectedTab : undefined} onSelect={onTabSelect}> + {this.renderGeneralTab()} + {this.renderEntitlementPoolsTab()} + {this.renderLicenseKeyGroupsTab()} + </ValidationTabs> + + </ValidationForm> + ); + } + + submit() { + const {data: featureGroup, previousData: previousFeatureGroup} = this.props; + this.props.onSubmit(previousFeatureGroup, featureGroup); + } + + renderGeneralTab() { + let {data = {}, onDataChanged} = this.props; + let {name, description, partNumber} = data; + return ( + <ValidationTab eventKey={FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.GENERAL} title={i18n('General')}> + <div> + <ValidationInput + groupClassName='field-section' + onChange={name => onDataChanged({name})} + ref='name' + label={i18n('Name')} + value={name} + name='feature-group-name' + validations={{maxLength: 120, required: true}} + type='text'/> + <ValidationInput + groupClassName='field-section' + className='description-field' + onChange={description => onDataChanged({description})} + ref='description' + label={i18n('Description')} + value={description} + name='feature-group-description' + validations={{maxLength: 1000, required: true}} + type='textarea'/> + <ValidationInput + groupClassName='field-section' + onChange={partNumber => onDataChanged({partNumber})} + label={i18n('Part Number')} + value={partNumber} + validations={{required: true}} + type='text'/> + </div> + </ValidationTab> + ); + } + + renderEntitlementPoolsTab() { + let {selectedEntitlementPoolsButtonTab, onEntitlementPoolsButtonTabSelect, entitlementPoolsList} = this.props; + if (entitlementPoolsList.length > 0) { + return ( + <ValidationTab + eventKey={FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.ENTITLEMENT_POOLS} + title={i18n('Entitlement Pools')}> + <ButtonGroup> + { + this.renderButtonsTab( + FeatureGroupStateConstants.SELECTED_ENTITLEMENT_POOLS_BUTTONTAB.ASSOCIATED_ENTITLEMENT_POOLS, + selectedEntitlementPoolsButtonTab, + i18n('Associated Entitlement Pools'), + onEntitlementPoolsButtonTabSelect + ) + } + { + this.renderButtonsTab( + FeatureGroupStateConstants.SELECTED_ENTITLEMENT_POOLS_BUTTONTAB.AVAILABLE_ENTITLEMENT_POOLS, + selectedEntitlementPoolsButtonTab, + i18n('Available Entitlement Pools'), + onEntitlementPoolsButtonTabSelect + ) + } + </ButtonGroup> + {this.renderEntitlementPoolsButtonTabContent(selectedEntitlementPoolsButtonTab)} + </ValidationTab> + ); + } else { + return ( + <ValidationTab + eventKey={FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.ENTITLEMENT_POOLS} + title={i18n('Entitlement Pools')}> + <p>{i18n('There is no available entitlement pools.')}</p> + </ValidationTab> + ); + } + } + + renderLicenseKeyGroupsTab() { + let {selectedLicenseKeyGroupsButtonTab, onLicenseKeyGroupsButtonTabSelect, licenseKeyGroupsList} = this.props; + if (licenseKeyGroupsList.length > 0) { + return ( + <ValidationTab + eventKey={FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.LICENCE_KEY_GROUPS} + title={i18n('License Key Groups')}> + <ButtonGroup> + { + this.renderButtonsTab( + FeatureGroupStateConstants.SELECTED_LICENSE_KEY_GROUPS_BUTTONTAB.ASSOCIATED_LICENSE_KEY_GROUPS, + selectedLicenseKeyGroupsButtonTab, + i18n('Associated License Key Groups'), + onLicenseKeyGroupsButtonTabSelect + ) + } + { + this.renderButtonsTab( + FeatureGroupStateConstants.SELECTED_LICENSE_KEY_GROUPS_BUTTONTAB.AVAILABLE_LICENSE_KEY_GROUPS, + selectedLicenseKeyGroupsButtonTab, + i18n('Available License Key Groups'), + onLicenseKeyGroupsButtonTabSelect + ) + } + </ButtonGroup> + {this.renderLicenseKeyGroupsTabContent(selectedLicenseKeyGroupsButtonTab)} + </ValidationTab> + ); + } else { + return ( + <ValidationTab + eventKey={FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.LICENCE_KEY_GROUPS} + title={i18n('License Key Groups')}> + <p>{i18n('There is no available license key groups')}</p> + </ValidationTab>); + } + } + + renderButtonsTab(buttonTab, selectedButtonTab, title, onClick) { + const isSelected = buttonTab === selectedButtonTab; + return ( + <Button + className='button-tab' + active={isSelected} + onClick={() => !isSelected && onClick(buttonTab)}> + { title } + </Button> + ); + } + + renderEntitlementPoolsButtonTabContent(selectedFeatureGroupsButtonTab) { + const {entitlementPoolsList = [], data: {entitlementPoolsIds = []}} = this.props; + let dualBoxTitle = { + left: i18n('Available Entitlement Pools'), + right: i18n('Selected Entitlement Pools') + }; + + if (entitlementPoolsList.length) { + const {localEntitlementPoolsListFilter} = this.state; + let selectedEntitlementPools = entitlementPoolsIds.map(entitlementPoolId => entitlementPoolsList.find(entitlementPool => entitlementPool.id === entitlementPoolId)); + + switch (selectedFeatureGroupsButtonTab) { + case FeatureGroupStateConstants.SELECTED_ENTITLEMENT_POOLS_BUTTONTAB.ASSOCIATED_ENTITLEMENT_POOLS: + if (selectedEntitlementPools.length) { + return ( + <ListEditorView + className='thinner-list' + filterValue={localEntitlementPoolsListFilter} + onFilter={localEntitlementPoolsListFilter => this.setState({localEntitlementPoolsListFilter})}> + {this.filterAssociatedItems(selectedEntitlementPools, localEntitlementPoolsListFilter) + .map(entitlementPool => this.renderAssociatedListItem(entitlementPool + , FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.ENTITLEMENT_POOLS))} + </ListEditorView> + ); + } + else { + return ( + <div> + <br/>{i18n('There are currently no entitlement pools associated with this feature group. Click "Available Entitlement Pools" to associate.')} + </div> + ); + } + case FeatureGroupStateConstants.SELECTED_ENTITLEMENT_POOLS_BUTTONTAB.AVAILABLE_ENTITLEMENT_POOLS: + return ( + <DualListboxView + filterTitle={dualBoxTitle} + selectedValuesList={entitlementPoolsIds} + availableList={entitlementPoolsList} + onChange={ selectedValuesList => this.props.onDataChanged( { entitlementPoolsIds: selectedValuesList } )}/> + ); + } + } + } + + renderLicenseKeyGroupsTabContent(selectedFeatureGroupsButtonTab) { + const {licenseKeyGroupsList = [], data: {licenseKeyGroupsIds = []}} = this.props; + let dualBoxFilterTitle = { + left: i18n('Available License Key Groups'), + right: i18n('Selected License Key Groups') + }; + + if (licenseKeyGroupsList.length) { + const {localLicenseKeyGroupsListFilter} = this.state; + let selectedLicenseKeyGroups = licenseKeyGroupsIds.map(licenseKeyGroupId => licenseKeyGroupsList.find(licenseKeyGroup => licenseKeyGroup.id === licenseKeyGroupId)); + + switch (selectedFeatureGroupsButtonTab) { + case FeatureGroupStateConstants.SELECTED_LICENSE_KEY_GROUPS_BUTTONTAB.ASSOCIATED_LICENSE_KEY_GROUPS: + if (selectedLicenseKeyGroups.length) { + return ( + <ListEditorView + className='thinner-list' + filterValue={localLicenseKeyGroupsListFilter} + onFilter={localLicenseKeyGroupsListFilter => this.setState({localLicenseKeyGroupsListFilter})}> + {this.filterAssociatedItems(selectedLicenseKeyGroups, localLicenseKeyGroupsListFilter) + .map(licenseKeyGroup => this.renderAssociatedListItem(licenseKeyGroup + , FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.LICENCE_KEY_GROUPS))} + </ListEditorView> + ); + } else { + return ( + <div className='no-items-msg'> + {i18n('There are currently no license key groups associated with this feature group. Click "Available License Key Groups" to associate.')} + </div> + ); + } + case FeatureGroupStateConstants.SELECTED_LICENSE_KEY_GROUPS_BUTTONTAB.AVAILABLE_LICENSE_KEY_GROUPS: + return ( + <DualListboxView + filterTitle={dualBoxFilterTitle} + selectedValuesList={this.props.data.licenseKeyGroupsIds} + availableList={this.props.licenseKeyGroupsList} + onChange={ selectedValuesList => this.props.onDataChanged( { licenseKeyGroupsIds: selectedValuesList } )}/> + ); + } + } + } + + + renderAssociatedListItem(listItem, itemType) { + let {isReadOnlyMode} = this.props; + return ( + <ListEditorViewItem + key={listItem.id} + onDelete={() => this.deleteAssociatedItem(listItem.id, itemType)} + isReadOnlyMode={isReadOnlyMode}> + <div className='name'>{listItem.name}</div> + <div className='description'>{listItem.description}</div> + </ListEditorViewItem> + ); + } + + filterAssociatedItems(list, localList) { + if (localList) { + const filter = new RegExp(escape(localList), 'i'); + return list.filter(({name = '', description = ''}) => name.match(filter) || description.match(filter)); + } + else { + return list; + } + } + + deleteAssociatedItem(id, type) { + const {data: {licenseKeyGroupsIds = [], entitlementPoolsIds = []}} = this.props; + if (type === FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.LICENCE_KEY_GROUPS) { + this.props.onDataChanged({licenseKeyGroupsIds: licenseKeyGroupsIds.filter(listId => listId !== id)}); + } else { + this.props.onDataChanged({entitlementPoolsIds: entitlementPoolsIds.filter(listId => listId !== id)}); + } + + } +} + + +export default FeatureGroupEditorView; + diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditor.js new file mode 100644 index 0000000000..9ea5a31490 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditor.js @@ -0,0 +1,56 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {connect} from 'react-redux'; +import FeatureGroupsActionHelper from './FeatureGroupsActionHelper.js'; +import FeatureGroupListEditorView from './FeatureGroupListEditorView.jsx'; +import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; + +const mapStateToProps = ({licenseModel: {featureGroup, licenseModelEditor}}) => { + const {featureGroupEditor: {data}, featureGroupsList} = featureGroup; + let {vendorName} = licenseModelEditor.data; + let isReadOnlyMode = VersionControllerUtils.isReadOnly(licenseModelEditor.data); + + return { + vendorName, + featureGroupsModal: { + show: Boolean(data), + editMode: Boolean(data && data.id) + }, + featureGroupsList, + isReadOnlyMode + }; +}; + + +const mapActionsToProps = (dispatch, {licenseModelId}) => { + return { + onDeleteFeatureGroupClick: (featureGroup) => FeatureGroupsActionHelper.openDeleteFeatureGroupConfirm(dispatch, {licenseModelId, featureGroup}), + onCancelFeatureGroupsEditor: () => FeatureGroupsActionHelper.closeFeatureGroupsEditor(dispatch), + + onAddFeatureGroupClick: () => FeatureGroupsActionHelper.openFeatureGroupsEditor(dispatch, {licenseModelId}), + onEditFeatureGroupClick: featureGroup => FeatureGroupsActionHelper.openFeatureGroupsEditor(dispatch, { + featureGroup, + licenseModelId + }) + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(FeatureGroupListEditorView); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditorView.jsx new file mode 100644 index 0000000000..d998f9216f --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditorView.jsx @@ -0,0 +1,136 @@ +import React from 'react'; + +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Modal from 'nfvo-components/modal/Modal.jsx'; +import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; +import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx'; + +import FeatureGroupEditor from './FeatureGroupEditor.js'; +import FeatureGroupsConfirmationModal from './FeatureGroupsConfirmationModal.jsx'; + +class FeatureGroupListEditorView extends React.Component { + static propTypes = { + vendorName: React.PropTypes.string, + licenseModelId: React.PropTypes.string.isRequired, + featureGroupsModal: React.PropTypes.shape({ + show: React.PropTypes.bool, + editMode: React.PropTypes.bool + }), + isReadOnlyMode: React.PropTypes.bool.isRequired, + onAddFeatureGroupClick: React.PropTypes.func, + onEditFeatureGroupClick: React.PropTypes.func, + onDeleteFeatureGroupClick: React.PropTypes.func, + onCancelFeatureGroupsEditor: React.PropTypes.func, + featureGroupsList: React.PropTypes.array + }; + + static defaultProps = { + featureGroupsList: [], + featureGroupsModal: { + show: false, + editMode: false + } + }; + + state = { + localFilter: '' + }; + + render() { + let {vendorName, licenseModelId, featureGroupsModal, isReadOnlyMode, onAddFeatureGroupClick} = this.props; + const {localFilter} = this.state; + + return ( + <div className='feature-groups-list-editor'> + <ListEditorView + title={i18n('Feature Groups for {vendorName} License Model', {vendorName})} + plusButtonTitle={i18n('Add Feature Group')} + filterValue={localFilter} + onFilter={filter => this.setState({localFilter: filter})} + onAdd={() => onAddFeatureGroupClick()} + isReadOnlyMode={isReadOnlyMode}> + {this.filterList().map(listItem => this.renderFeatureGroupListItem(listItem, isReadOnlyMode))} + </ListEditorView> + <Modal show={featureGroupsModal.show} bsSize='large' animation={true} className='feature-group-modal'> + <Modal.Header> + <Modal.Title>{`${featureGroupsModal.editMode ? i18n('Edit Feature Group') : i18n('Create New Feature Group')}`}</Modal.Title> + </Modal.Header> + <Modal.Body> + <FeatureGroupEditor + onCancel={() => this.closeFeatureGroupsEditor()} + licenseModelId={licenseModelId} + isReadOnlyMode={isReadOnlyMode}/> + </Modal.Body> + </Modal> + + <FeatureGroupsConfirmationModal licenseModelId={licenseModelId}/> + + </div> + ); + } + + + renderFeatureGroupListItem(listItem, isReadOnlyMode) { + let {name, description, entitlementPoolsIds = [], licenseKeyGroupsIds = []} = listItem; + return ( + <ListEditorItemView + key={listItem.id} + onDelete={() => this.deleteFeatureGroupItem(listItem)} + onSelect={() => this.editFeatureGroupItem(listItem)} + className='list-editor-item-view' + isReadOnlyMode={isReadOnlyMode}> + <div className='list-editor-item-view-field'> + <div className='title'>{i18n('Name')}</div> + <div className='text name'>{name}</div> + </div> + + <div className='list-editor-item-view-field'> + <div className='feature-groups-count-field'> + <div className='title'>{i18n('Entitlement')}</div> + <div className='title'>{i18n('Pools')}</div> + <div className='feature-groups-count-ep'>{entitlementPoolsIds.length || 0}</div> + </div> + <div className='feature-groups-count-field'> + <div className='title'>{i18n('License key')}</div> + <div className='title'>{i18n('Groups')}</div> + <div className='feature-groups-count-lk'>{licenseKeyGroupsIds.length || 0}</div> + </div> + </div> + + <div className='list-editor-item-view-field'> + <div className='title'>{i18n('Description')}</div> + <div className='text description'>{description}</div> + </div> + + </ListEditorItemView> + ); + } + + filterList() { + let {featureGroupsList} = this.props; + let {localFilter} = this.state; + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return featureGroupsList.filter(({name = '', description = ''}) => { + return escape(name).match(filter) || escape(description).match(filter); + }); + } + else { + return featureGroupsList; + } + } + + closeFeatureGroupsEditor() { + this.props.onCancelFeatureGroupsEditor(); + } + + editFeatureGroupItem(featureGroup) { + this.props.onEditFeatureGroupClick(featureGroup); + } + + deleteFeatureGroupItem(featureGroup) { + this.props.onDeleteFeatureGroupClick(featureGroup); + } +} + +export default FeatureGroupListEditorView; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js new file mode 100644 index 0000000000..3776c01263 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js @@ -0,0 +1,165 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; +import Configuration from 'sdc-app/config/Configuration.js'; +import {actionTypes as featureGroupsActionConstants} from './FeatureGroupsConstants.js'; +import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js'; +import EntitlementPoolsActionHelper from 'sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js'; +import LicenseKeyGroupsActionHelper from 'sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsActionHelper.js'; + +function baseUrl(licenseModelId) { + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-license-models/${licenseModelId}/feature-groups`; +} + +function fetchFeatureGroupsList(licenseModelId, version) { + let versionQuery = version ? `?version=${version}` : ''; + return RestAPIUtil.fetch(`${baseUrl(licenseModelId)}${versionQuery}`); +} + +function deleteFeatureGroup(licenseModelId, featureGroupId) { + return RestAPIUtil.destroy(`${baseUrl(licenseModelId)}/${featureGroupId}`); +} + +function addFeatureGroup(licenseModelId, featureGroup) { + return RestAPIUtil.create(baseUrl(licenseModelId), { + name: featureGroup.name, + description: featureGroup.description, + partNumber: featureGroup.partNumber, + addedLicenseKeyGroupsIds: featureGroup.licenseKeyGroupsIds, + addedEntitlementPoolsIds: featureGroup.entitlementPoolsIds + }); +} + +function updateFeatureGroup(licenseModelId, previousFeatureGroup, featureGroup) { + + const {licenseKeyGroupsIds = []} = featureGroup; + const {licenseKeyGroupsIds: prevLicenseKeyGroupsIds = []} = previousFeatureGroup; + const {entitlementPoolsIds = []} = featureGroup; + const {entitlementPoolsIds: prevEntitlementPoolsIds = []} = previousFeatureGroup; + return RestAPIUtil.save(`${baseUrl(licenseModelId)}/${featureGroup.id}`, { + name: featureGroup.name, + description: featureGroup.description, + partNumber: featureGroup.partNumber, + addedLicenseKeyGroupsIds: licenseKeyGroupsIds.filter(licenseKeyGroupId => prevLicenseKeyGroupsIds.indexOf(licenseKeyGroupId) === -1), + removedLicenseKeyGroupsIds: prevLicenseKeyGroupsIds.filter(prevLicenseKeyGroupId => licenseKeyGroupsIds.indexOf(prevLicenseKeyGroupId) === -1), + addedEntitlementPoolsIds: entitlementPoolsIds.filter(entitlementPoolId => prevEntitlementPoolsIds.indexOf(entitlementPoolId) === -1), + removedEntitlementPoolsIds: prevEntitlementPoolsIds.filter(prevEntitlementPoolId => entitlementPoolsIds.indexOf(prevEntitlementPoolId) === -1) + + }); +} + +export default { + fetchFeatureGroupsList(dispatch, {licenseModelId, version}) { + return fetchFeatureGroupsList(licenseModelId, version).then(response => dispatch({ + type: featureGroupsActionConstants.FEATURE_GROUPS_LIST_LOADED, + response + })); + }, + + deleteFeatureGroup(dispatch, {licenseModelId, featureGroupId}) { + return deleteFeatureGroup(licenseModelId, featureGroupId).then(() => dispatch({ + type: featureGroupsActionConstants.DELETE_FEATURE_GROUPS, + featureGroupId + })); + }, + + saveFeatureGroup(dispatch, {licenseModelId, previousFeatureGroup, featureGroup}) { + if (previousFeatureGroup) { + return updateFeatureGroup(licenseModelId, previousFeatureGroup, featureGroup).then(() => dispatch({ + type: featureGroupsActionConstants.EDIT_FEATURE_GROUPS, + featureGroup + })); + } + else { + return addFeatureGroup(licenseModelId, featureGroup).then(response => dispatch({ + type: featureGroupsActionConstants.ADD_FEATURE_GROUPS, + featureGroup: { + ...featureGroup, + id: response.value + } + })); + } + }, + + selectEntitlementPoolsEditorTab(dispatch, {tab}) { + dispatch({ + type: featureGroupsActionConstants.featureGroupsEditor.SELECT_TAB, + tab + }); + }, + + selectFeatureGroupsEditorEntitlementPoolsButtonTab(dispatch, {buttonTab}) { + dispatch({ + type: featureGroupsActionConstants.featureGroupsEditor.SELECTED_ENTITLEMENT_POOLS_BUTTONTAB, + buttonTab + }); + }, + + selectFeatureGroupsEditorLicenseKeyGroupsButtonTab(dispatch, {buttonTab}) { + dispatch({ + type: featureGroupsActionConstants.featureGroupsEditor.SELECTED_LICENSE_KEY_GROUPS_BUTTONTAB, + buttonTab + }); + }, + + openFeatureGroupsEditor(dispatch, {featureGroup, licenseModelId}) { + EntitlementPoolsActionHelper.fetchEntitlementPoolsList(dispatch, {licenseModelId}); + LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList(dispatch, {licenseModelId}); + dispatch({ + type: featureGroupsActionConstants.featureGroupsEditor.OPEN, + featureGroup + }); + }, + + closeFeatureGroupsEditor(dispatch) { + dispatch({ + type: featureGroupsActionConstants.featureGroupsEditor.CLOSE + }); + }, + + featureGroupsEditorDataChanged(dispatch, {deltaData}) { + dispatch({ + type: featureGroupsActionConstants.featureGroupsEditor.DATA_CHANGED, + deltaData + }); + }, + + hideDeleteConfirm(dispatch) { + dispatch({ + type: featureGroupsActionConstants.FEATURE_GROUPS_DELETE_CONFIRM, + featureGroupToDelete: false + }); + }, + + openDeleteFeatureGroupConfirm(dispatch, {featureGroup}) { + dispatch({ + type: featureGroupsActionConstants.FEATURE_GROUPS_DELETE_CONFIRM, + featureGroupToDelete: featureGroup + }); + }, + + switchVersion(dispatch, {licenseModelId, version}) { + LicenseModelActionHelper.fetchLicenseModelById(dispatch, {licenseModelId, version}).then(() => { + this.fetchFeatureGroupsList(dispatch, {licenseModelId, version}); + }); + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConfirmationModal.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConfirmationModal.jsx new file mode 100644 index 0000000000..142ec3c4c8 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConfirmationModal.jsx @@ -0,0 +1,48 @@ +import React from 'react'; +import {connect} from 'react-redux'; +import ConfirmationModalView from 'nfvo-components/confirmations/ConfirmationModalView.jsx'; +import FeatureGroupsActionHelper from './FeatureGroupsActionHelper.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +function renderMsg(featureGroupToDelete) { + let name = featureGroupToDelete ? featureGroupToDelete.name : ''; + let msg = i18n('Are you sure you want to delete "{name}"?', {name}); + let subMsg = featureGroupToDelete + && featureGroupToDelete.referencingLicenseAgreements + && featureGroupToDelete.referencingLicenseAgreements.length > 0 ? + i18n('This feature group is associated with one ore more license agreements') : + ''; + return ( + <div> + <p>{msg}</p> + <p>{subMsg}</p> + </div> + ); +}; + +const mapStateToProps = ({licenseModel: {featureGroup}}, {licenseModelId}) => { + let {featureGroupToDelete} = featureGroup; + const show = featureGroupToDelete !== false; + return { + show, + title: 'Warning!', + type: 'warning', + msg: renderMsg(featureGroupToDelete), + confirmationDetails: {featureGroupToDelete, licenseModelId} + }; +}; + +const mapActionsToProps = (dispatch) => { + return { + onConfirmed: ({featureGroupToDelete, licenseModelId}) => { + FeatureGroupsActionHelper.deleteFeatureGroup(dispatch, {featureGroupId: featureGroupToDelete.id, licenseModelId}); + FeatureGroupsActionHelper.hideDeleteConfirm(dispatch); + }, + onDeclined: () => { + FeatureGroupsActionHelper.hideDeleteConfirm(dispatch); + } + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(ConfirmationModalView); + diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConstants.js new file mode 100644 index 0000000000..e02c54595d --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConstants.js @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import keyMirror from 'nfvo-utils/KeyMirror.js'; + +export const actionTypes = keyMirror({ + FEATURE_GROUPS_LIST_LOADED: null, + ADD_FEATURE_GROUPS: null, + EDIT_FEATURE_GROUPS: null, + DELETE_FEATURE_GROUPS: null, + FEATURE_GROUPS_DELETE_CONFIRM: null, + + + ENTITLEMENT_POOLS_LIST_LOADED: null, + + featureGroupsEditor: { + OPEN: null, + CLOSE: null, + DATA_CHANGED: null, + SELECT_TAB: null, + SELECTED_ENTITLEMENT_POOLS_BUTTONTAB: null, + SELECTED_LICENSE_KEY_GROUPS_BUTTONTAB: null + } +}); + +export const state = keyMirror({ + SELECTED_FEATURE_GROUP_TAB: { + GENERAL: 1, + ENTITLEMENT_POOLS: 2, + LICENCE_KEY_GROUPS: 3 + }, + SELECTED_ENTITLEMENT_POOLS_BUTTONTAB: { + ASSOCIATED_ENTITLEMENT_POOLS: 1, + AVAILABLE_ENTITLEMENT_POOLS: 2 + }, + SELECTED_LICENSE_KEY_GROUPS_BUTTONTAB: { + ASSOCIATED_LICENSE_KEY_GROUPS: 1, + AVAILABLE_LICENSE_KEY_GROUPS: 2 + }, +}); + + + diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsEditorReducer.js new file mode 100644 index 0000000000..576a5358e6 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsEditorReducer.js @@ -0,0 +1,62 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {actionTypes} from './FeatureGroupsConstants.js'; + + + +export default (state = {}, action) => { + switch (action.type) { + case actionTypes.featureGroupsEditor.OPEN: + return { + ...state, + data: action.featureGroup || {} + }; + case actionTypes.featureGroupsEditor.DATA_CHANGED: + return { + ...state, + data: { + ...state.data, + ...action.deltaData + } + }; + case actionTypes.featureGroupsEditor.CLOSE: + return {}; + case actionTypes.featureGroupsEditor.SELECT_TAB: + return { + ...state, + selectedTab: action.tab + }; + + case actionTypes.featureGroupsEditor.SELECTED_ENTITLEMENT_POOLS_BUTTONTAB: + return { + ...state, + selectedEntitlementPoolsButtonTab: action.buttonTab + }; + case actionTypes.featureGroupsEditor.SELECTED_LICENSE_KEY_GROUPS_BUTTONTAB: + return { + ...state, + selectedLicenseKeyGroupsButtonTab: action.buttonTab + }; + default: + return state; + } + +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsListReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsListReducer.js new file mode 100644 index 0000000000..5cf3248919 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsListReducer.js @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {actionTypes} from './FeatureGroupsConstants.js'; +export default (state = [], action) => { + switch (action.type) { + case actionTypes.FEATURE_GROUPS_LIST_LOADED: + return [...action.response.results]; + case actionTypes.ADD_FEATURE_GROUPS: + return [...state, action.featureGroup]; + case actionTypes.EDIT_FEATURE_GROUPS: + const indexForEdit = state.findIndex(featureGroup => featureGroup.id === action.featureGroup.id); + return [...state.slice(0, indexForEdit), action.featureGroup, ...state.slice(indexForEdit + 1)]; + case actionTypes.DELETE_FEATURE_GROUPS: + return state.filter(featureGroup => featureGroup.id !== action.featureGroupId); + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js new file mode 100644 index 0000000000..9616b60b76 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js @@ -0,0 +1,160 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; +import Configuration from 'sdc-app/config/Configuration.js'; +import {actionTypes as licenseAgreementActionTypes} from './LicenseAgreementConstants.js'; +import FeatureGroupsActionHelper from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js'; +import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js'; + +function baseUrl(licenseModelId) { + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-license-models/${licenseModelId}/license-agreements`; +} + +function fetchLicenseAgreementList(licenseModelId, version) { + let versionQuery = version ? `?version=${version}` : ''; + return RestAPIUtil.fetch(`${baseUrl(licenseModelId)}${versionQuery}`); +} + +function postLicenseAgreement(licenseModelId, licenseAgreement) { + return RestAPIUtil.create(baseUrl(licenseModelId), { + name: licenseAgreement.name, + description: licenseAgreement.description, + licenseTerm: licenseAgreement.licenseTerm, + requirementsAndConstrains: licenseAgreement.requirementsAndConstrains, + addedFeatureGroupsIds: licenseAgreement.featureGroupsIds + }); +} + +function putLicenseAgreement(licenseModelId, previousLicenseAgreement, licenseAgreement) { + const {featureGroupsIds = []} = licenseAgreement; + const {featureGroupsIds: prevFeatureGroupsIds = []} = previousLicenseAgreement; + return RestAPIUtil.save(`${baseUrl(licenseModelId)}/${licenseAgreement.id}`, { + name: licenseAgreement.name, + description: licenseAgreement.description, + licenseTerm: licenseAgreement.licenseTerm, + requirementsAndConstrains: licenseAgreement.requirementsAndConstrains, + addedFeatureGroupsIds: featureGroupsIds.filter(featureGroupId => prevFeatureGroupsIds.indexOf(featureGroupId) === -1), + removedFeatureGroupsIds: prevFeatureGroupsIds.filter(prevFeatureGroupsId => featureGroupsIds.indexOf(prevFeatureGroupsId) === -1) + }); +} + +function deleteLicenseAgreement(licenseModelId, licenseAgreementId) { + return RestAPIUtil.destroy(`${baseUrl(licenseModelId)}/${licenseAgreementId}`); +} + +export default { + + fetchLicenseAgreementList(dispatch, {licenseModelId, version}) { + return fetchLicenseAgreementList(licenseModelId, version).then(response => dispatch({ + type: licenseAgreementActionTypes.LICENSE_AGREEMENT_LIST_LOADED, + response + })); + }, + + openLicenseAgreementEditor(dispatch, {licenseModelId, licenseAgreement}) { + FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, {licenseModelId}); + dispatch({ + type: licenseAgreementActionTypes.licenseAgreementEditor.OPEN, + licenseAgreement + }); + }, + + licenseAgreementEditorDataChanged(dispatch, {deltaData}) { + dispatch({ + type: licenseAgreementActionTypes.licenseAgreementEditor.DATA_CHANGED, + deltaData + }); + }, + + closeLicenseAgreementEditor(dispatch) { + dispatch({ + type: licenseAgreementActionTypes.licenseAgreementEditor.CLOSE + }); + }, + + + saveLicenseAgreement(dispatch, {licenseModelId, previousLicenseAgreement, licenseAgreement}) { + if (previousLicenseAgreement) { + return putLicenseAgreement(licenseModelId, previousLicenseAgreement, licenseAgreement).then(() => { + dispatch({ + type: licenseAgreementActionTypes.EDIT_LICENSE_AGREEMENT, + licenseAgreement + }); + }); + } + else { + return postLicenseAgreement(licenseModelId, licenseAgreement).then(response => { + dispatch({ + type: licenseAgreementActionTypes.ADD_LICENSE_AGREEMENT, + licenseAgreement: { + ...licenseAgreement, + id: response.value + } + }); + }); + } + }, + + deleteLicenseAgreement(dispatch, {licenseModelId, licenseAgreementId}) { + return deleteLicenseAgreement(licenseModelId, licenseAgreementId).then(() => { + dispatch({ + type: licenseAgreementActionTypes.DELETE_LICENSE_AGREEMENT, + licenseAgreementId + }); + }); + }, + + selectLicenseAgreementEditorTab(dispatch, {tab}) { + dispatch({ + type: licenseAgreementActionTypes.licenseAgreementEditor.SELECT_TAB, + tab + }); + }, + + selectLicenseAgreementEditorFeatureGroupsButtonTab(dispatch, {buttonTab}) { + dispatch({ + type: licenseAgreementActionTypes.licenseAgreementEditor.SELECT_FEATURE_GROUPS_BUTTONTAB, + buttonTab + }); + }, + + hideDeleteConfirm(dispatch) { + dispatch({ + type: licenseAgreementActionTypes.LICENSE_AGREEMENT_DELETE_CONFIRM, + licenseAgreementToDelete: false + }); + }, + + openDeleteLicenseAgreementConfirm(dispatch, {licenseAgreement} ) { + dispatch({ + type: licenseAgreementActionTypes.LICENSE_AGREEMENT_DELETE_CONFIRM, + licenseAgreementToDelete: licenseAgreement + }); + }, + + switchVersion(dispatch, {licenseModelId, version}) { + LicenseModelActionHelper.fetchLicenseModelById(dispatch, {licenseModelId, version}).then(() => { + this.fetchLicenseAgreementList(dispatch, {licenseModelId, version}); + }); + } +}; + diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConfirmationModal.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConfirmationModal.jsx new file mode 100644 index 0000000000..42f2407696 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConfirmationModal.jsx @@ -0,0 +1,43 @@ +import React from 'react'; +import {connect} from 'react-redux'; +import ConfirmationModalView from 'nfvo-components/confirmations/ConfirmationModalView.jsx'; +import LicenseAgreementActionHelper from './LicenseAgreementActionHelper.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +function renderMsg(licenseAgreementToDelete) { + let name = licenseAgreementToDelete ? licenseAgreementToDelete.name : ''; + let msg = i18n('Are you sure you want to delete "{name}"?', {name}); + return( + <div> + <p>{msg}</p> + </div> + ); +}; + +const mapStateToProps = ({licenseModel: {licenseAgreement}}, {licenseModelId}) => { + let {licenseAgreementToDelete} = licenseAgreement; + const show = licenseAgreementToDelete !== false; + return { + show, + title: 'Warning!', + type: 'warning', + msg: renderMsg(licenseAgreementToDelete), + confirmationDetails: {licenseAgreementToDelete, licenseModelId} + }; +}; + +const mapActionsToProps = (dispatch) => { + return { + onConfirmed: ({licenseAgreementToDelete, licenseModelId}) => { + + LicenseAgreementActionHelper.deleteLicenseAgreement(dispatch, {licenseModelId, licenseAgreementId: licenseAgreementToDelete.id}); + LicenseAgreementActionHelper.hideDeleteConfirm(dispatch); + }, + onDeclined: () => { + LicenseAgreementActionHelper.hideDeleteConfirm(dispatch); + } + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(ConfirmationModalView); + diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js new file mode 100644 index 0000000000..af5c454e22 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import keyMirror from 'nfvo-utils/KeyMirror.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +export const actionTypes = keyMirror({ + LICENSE_AGREEMENT_LIST_LOADED: null, + ADD_LICENSE_AGREEMENT: null, + EDIT_LICENSE_AGREEMENT: null, + DELETE_LICENSE_AGREEMENT: null, + LICENSE_AGREEMENT_DELETE_CONFIRM: null, + + licenseAgreementEditor: { + OPEN: null, + CLOSE: null, + DATA_CHANGED: null, + SELECT_TAB: null, + SELECT_FEATURE_GROUPS_BUTTONTAB: null, + } + +}); + +export const enums = keyMirror({ + SELECTED_LICENSE_AGREEMENT_TAB: { + GENERAL: 1, + FEATURE_GROUPS: 2 + }, + + SELECTED_FEATURE_GROUPS_BUTTONTAB: { + ASSOCIATED_FEATURE_GROUPS: 1, + AVAILABLE_FEATURE_GROUPS: 2 + } +}); + +export const defaultState = { + LICENSE_AGREEMENT_EDITOR_DATA: { + licenseTerm: {choice: '', other: ''} + } +}; + +export const optionsInputValues = { + LICENSE_MODEL_TYPE: [ + {enum: '', title: i18n('please select…')}, + {enum: 'Fixed_Term', title: 'Fixed Term'}, + {enum: 'Perpetual', title: 'Perpetual'}, + {enum: 'Unlimited', title: 'Unlimited'} + ] +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditor.js new file mode 100644 index 0000000000..6a3e4dbc73 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditor.js @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {connect} from 'react-redux'; +import LicenseAgreementActionHelper from './LicenseAgreementActionHelper.js'; +import LicenseAgreementEditorView from './LicenseAgreementEditorView.jsx'; + +export const mapStateToProps = ({licenseModel: {licenseAgreement, featureGroup}}) => { + + + let {data, selectedTab, selectedFeatureGroupsButtonTab} = licenseAgreement.licenseAgreementEditor; + + let previousData; + const licenseAgreementId = data ? data.id : null; + if(licenseAgreementId) { + previousData = licenseAgreement.licenseAgreementList.find(licenseAgreement => licenseAgreement.id === licenseAgreementId); + } + + const {featureGroupsList = []} = featureGroup; + + return { + data, + previousData, + selectedTab, + selectedFeatureGroupsButtonTab, + featureGroupsList + }; +}; + +export const mapActionsToProps = (dispatch, {licenseModelId}) => { + return { + onDataChanged: deltaData => LicenseAgreementActionHelper.licenseAgreementEditorDataChanged(dispatch, {deltaData}), + onTabSelect: tab => LicenseAgreementActionHelper.selectLicenseAgreementEditorTab(dispatch, {tab}), + onFeatureGroupsButtonTabSelect: buttonTab => LicenseAgreementActionHelper.selectLicenseAgreementEditorFeatureGroupsButtonTab(dispatch, {buttonTab}), + onCancel: () => LicenseAgreementActionHelper.closeLicenseAgreementEditor(dispatch), + onSubmit: ({previousLicenseAgreement, licenseAgreement}) => { + LicenseAgreementActionHelper.closeLicenseAgreementEditor(dispatch); + LicenseAgreementActionHelper.saveLicenseAgreement(dispatch, {licenseModelId, previousLicenseAgreement, licenseAgreement}); + } + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(LicenseAgreementEditorView); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorReducer.js new file mode 100644 index 0000000000..74e2f6e8c1 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorReducer.js @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {actionTypes, defaultState} from './LicenseAgreementConstants.js'; + +export default (state = {}, action) => { + switch (action.type) { + case actionTypes.licenseAgreementEditor.OPEN: + return { + ...state, + data: action.licenseAgreement ? { ...action.licenseAgreement } : defaultState.LICENSE_AGREEMENT_EDITOR_DATA + }; + case actionTypes.licenseAgreementEditor.DATA_CHANGED: + return { + ...state, + data: { + ...state.data, + ...action.deltaData + } + }; + case actionTypes.licenseAgreementEditor.CLOSE: + return {}; + case actionTypes.licenseAgreementEditor.SELECT_TAB: + return { + ...state, + selectedTab: action.tab + }; + case actionTypes.licenseAgreementEditor.SELECT_FEATURE_GROUPS_BUTTONTAB: + return { + ...state, + selectedFeatureGroupsButtonTab: action.buttonTab + }; + default: + return state; + } + +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorView.jsx new file mode 100644 index 0000000000..b21f943fed --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorView.jsx @@ -0,0 +1,247 @@ +import React from 'react'; +import ButtonGroup from 'react-bootstrap/lib/ButtonGroup.js'; +import Button from 'react-bootstrap/lib/Button.js'; +import ValidationForm from 'nfvo-components/input/validation/ValidationForm.jsx'; +import ValidationTabs from 'nfvo-components/input/validation/ValidationTabs.jsx'; +import ValidationTab from 'nfvo-components/input/validation/ValidationTab.jsx'; +import ValidationInput from 'nfvo-components/input/validation/ValidationInput.jsx'; +import DualListboxView from 'nfvo-components/input/dualListbox/DualListboxView.jsx'; +import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; +import ListEditorViewItem from 'nfvo-components/listEditor/ListEditorItemView.jsx'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +import {enums as LicenseAgreementEnums, optionsInputValues as LicenseAgreementOptionsInputValues} from './LicenseAgreementConstants.js'; + + +const LicenseAgreementPropType = React.PropTypes.shape({ + id: React.PropTypes.string, + name: React.PropTypes.string, + description: React.PropTypes.string, + requirementsAndConstrains: React.PropTypes.string, + licenseTerm: React.PropTypes.object, + featureGroupsIds: React.PropTypes.arrayOf(React.PropTypes.string) +}); + +class LicenseAgreementEditorView extends React.Component { + + static propTypes = { + data: LicenseAgreementPropType, + previousData: LicenseAgreementPropType, + isReadOnlyMode: React.PropTypes.bool, + onDataChanged: React.PropTypes.func.isRequired, + onSubmit: React.PropTypes.func.isRequired, + onCancel: React.PropTypes.func.isRequired, + + selectedTab: React.PropTypes.number, + onTabSelect: React.PropTypes.func, + + selectedFeatureGroupsButtonTab: React.PropTypes.number, + onFeatureGroupsButtonTabSelect: React.PropTypes.func, + featureGroupsList: DualListboxView.propTypes.availableList + }; + + static defaultProps = { + selectedTab: LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB.GENERAL, + selectedFeatureGroupsButtonTab: LicenseAgreementEnums.SELECTED_FEATURE_GROUPS_BUTTONTAB.AVAILABLE_FEATURE_GROUPS, + data: {} + }; + + state = { + localFeatureGroupsListFilter: '' + }; + + render() { + let {selectedTab, onTabSelect, isReadOnlyMode} = this.props; + return ( + <ValidationForm + ref='validationForm' + hasButtons={true} + onSubmit={ () => this.submit() } + onReset={ () => this.props.onCancel() } + labledButtons={true} + isReadOnlyMode={isReadOnlyMode} + className='license-agreement-form'> + <ValidationTabs activeKey={onTabSelect ? selectedTab : undefined} onSelect={onTabSelect}> + {this.renderGeneralTab()} + {this.renderFeatureGroupsTab()} + </ValidationTabs> + </ValidationForm> + ); + } + + submit() { + const {data: licenseAgreement, previousData: previousLicenseAgreement} = this.props; + this.props.onSubmit({licenseAgreement, previousLicenseAgreement}); + } + + renderGeneralTab() { + let {data = {}, onDataChanged} = this.props; + let {name, description, requirementsAndConstrains, licenseTerm} = data; + return ( + <ValidationTab + eventKey={LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB.GENERAL} + title={i18n('General')}> + <div className='license-agreement-form-row'> + <div className='license-agreement-form-col'> + <ValidationInput + onChange={name => onDataChanged({name})} + label={i18n('Name')} + value={name} + name='license-agreement-name' + validations={{maxLength: 25, required: true}} + type='text'/> + <ValidationInput + onChange={requirementsAndConstrains => onDataChanged({requirementsAndConstrains})} + label={i18n('Requirements and Constraints')} + value={requirementsAndConstrains} + name='license-agreement-requirements-and-constraints' + validations={{maxLength: 1000}} + type='textarea'/> + </div> + <ValidationInput + onChange={description => onDataChanged({description})} + label={i18n('Description')} + value={description} + name='license-agreement-description' + validations={{maxLength: 1000, required: true}} + type='textarea'/> + </div> + <div className='license-agreement-form-row'> + <ValidationInput + onEnumChange={licenseTerm => onDataChanged({licenseTerm:{choice: licenseTerm, other: ''}})} + selectedEnum={licenseTerm && licenseTerm.choice} + validations={{required: true}} + type='select' + label={i18n('License Term')} + values={LicenseAgreementOptionsInputValues.LICENSE_MODEL_TYPE}/> + </div> + </ValidationTab> + ); + } + + renderFeatureGroupsTab() { + let {onFeatureGroupsButtonTabSelect, selectedFeatureGroupsButtonTab, featureGroupsList} = this.props; + if (featureGroupsList.length > 0) { + return ( + <ValidationTab + eventKey={LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB.FEATURE_GROUPS} + title={i18n('Feature Groups')}> + <ButtonGroup> + { + this.renderFeatureGroupsButtonTab( + LicenseAgreementEnums.SELECTED_FEATURE_GROUPS_BUTTONTAB.ASSOCIATED_FEATURE_GROUPS, + selectedFeatureGroupsButtonTab, + i18n('Associated Feature Groups'), + onFeatureGroupsButtonTabSelect + ) + } + { + this.renderFeatureGroupsButtonTab( + LicenseAgreementEnums.SELECTED_FEATURE_GROUPS_BUTTONTAB.AVAILABLE_FEATURE_GROUPS, + selectedFeatureGroupsButtonTab, + i18n('Available Feature Groups'), + onFeatureGroupsButtonTabSelect + ) + } + </ButtonGroup> + {this.renderFeatureGroupsButtonTabContent(selectedFeatureGroupsButtonTab)} + </ValidationTab> + ); + } else { + return ( + <ValidationTab + eventKey={LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB.FEATURE_GROUPS} + title={i18n('Feature Groups')}> + <p>{i18n('There is no available feature groups')}</p> + </ValidationTab> + ); + } + } + + renderFeatureGroupsButtonTabContent(selectedFeatureGroupsButtonTab) { + const {featureGroupsList = [], data: {featureGroupsIds = []}} = this.props; + const {localFeatureGroupsListFilter} = this.state; + let selectedFeatureGroups = featureGroupsIds.map(featureGroupId => featureGroupsList.find(featureGroup => featureGroup.id === featureGroupId)); + + const dualBoxFilterTitle = { + left: i18n('Available Feature Groups'), + right: i18n('Selected Feature Groups') + }; + + switch (selectedFeatureGroupsButtonTab) { + case LicenseAgreementEnums.SELECTED_FEATURE_GROUPS_BUTTONTAB.ASSOCIATED_FEATURE_GROUPS: + if (!selectedFeatureGroups.length) { + return ( + <div className='no-items-msg'> + {i18n('There are currently no feature groups associated with this license agreement. Click "Available Feature Groups" to associate.')} + </div> + ); + } + if (featureGroupsList.length) { + return ( + <ListEditorView + className='thinner-list' + filterValue={localFeatureGroupsListFilter} + onFilter={localFeatureGroupsListFilter => this.setState({localFeatureGroupsListFilter})}> + {this.filterAssociatedFeatureGroupsList(selectedFeatureGroups).map(featureGroup => this.renderAssociatedFeatureGroupListItem(featureGroup))} + </ListEditorView> + ); + } + return; + case LicenseAgreementEnums.SELECTED_FEATURE_GROUPS_BUTTONTAB.AVAILABLE_FEATURE_GROUPS: + return ( + <DualListboxView + filterTitle={dualBoxFilterTitle} + selectedValuesList={this.props.data.featureGroupsIds} + availableList={this.props.featureGroupsList} + onChange={ selectedValuesList => this.props.onDataChanged( { featureGroupsIds: selectedValuesList } )}/> + ); + } + } + + renderFeatureGroupsButtonTab(buttonTab, selectedButtonTab, title, onClick) { + const isSelected = buttonTab === selectedButtonTab; + return ( + <Button + className='button-tab' + active={isSelected} + onClick={() => !isSelected && onClick(buttonTab)}> + { title } + </Button> + ); + } + + renderAssociatedFeatureGroupListItem({id, name, entitlementPoolsIds = [], licenseKeyGroupsIds = []}) { + const {onDataChanged, data: {featureGroupsIds}, isReadOnlyMode} = this.props; + return ( + <ListEditorViewItem + key={id} + onDelete={() => onDataChanged({featureGroupsIds: featureGroupsIds.filter(featureGroupId => featureGroupId !== id)})} + isReadOnlyMode={isReadOnlyMode}> + <div className='name'>{name}</div> + <div className='inner-objects-count'>{ + i18n( + 'Entitlement Pools({entitlementPoolsCounter}), License Key Groups({licenseKeyGroupsCount})', + { + entitlementPoolsCounter: entitlementPoolsIds.length, + licenseKeyGroupsCount: licenseKeyGroupsIds.length + } + ) + }</div> + </ListEditorViewItem> + ); + } + + filterAssociatedFeatureGroupsList(featureGroupsList) { + let {localFeatureGroupsListFilter} = this.state; + if (localFeatureGroupsListFilter) { + const filter = new RegExp(escape(localFeatureGroupsListFilter), 'i'); + return featureGroupsList.filter(({name}) => name.match(filter)); + } + else { + return featureGroupsList; + } + } +} + +export default LicenseAgreementEditorView; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditor.js new file mode 100644 index 0000000000..ca18bfab79 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditor.js @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {connect} from 'react-redux'; +import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js'; +import LicenseAgreementActionHelper from './LicenseAgreementActionHelper.js'; +import LicenseAgreementListEditorView from './LicenseAgreementListEditorView.jsx'; +import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; +import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js'; + +const mapStateToProps = ({licenseModel: {licenseAgreement, licenseModelEditor}}) => { + let {licenseAgreementList} = licenseAgreement; + let {data} = licenseAgreement.licenseAgreementEditor; + let {vendorName} = licenseModelEditor.data; + + let isReadOnlyMode = VersionControllerUtils.isReadOnly(licenseModelEditor.data); + + return { + vendorName, + licenseAgreementList, + isReadOnlyMode, + isDisplayModal: Boolean(data), + isModalInEditMode: Boolean(data && data.id) + }; +}; + +const mapActionsToProps = (dispatch, {licenseModelId}) => { + return { + onAddLicenseAgreementClick: () => LicenseAgreementActionHelper.openLicenseAgreementEditor(dispatch, {licenseModelId}), + onEditLicenseAgreementClick: licenseAgreement => LicenseAgreementActionHelper.openLicenseAgreementEditor(dispatch, {licenseModelId, licenseAgreement}), + onDeleteLicenseAgreement: licenseAgreement => LicenseAgreementActionHelper.openDeleteLicenseAgreementConfirm(dispatch, {licenseAgreement}), + onCallVCAction: action => { + LicenseModelActionHelper.performVCAction(dispatch, {licenseModelId, action}).then(() => { + LicenseAgreementActionHelper.fetchLicenseAgreementList(dispatch, {licenseModelId}); + }); + }, + switchLicenseModelVersion: version => LicenseAgreementActionHelper.switchVersion(dispatch, {licenseModelId, version}), + onClose: () => OnboardingActionHelper.navigateToOnboardingCatalog(dispatch) + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(LicenseAgreementListEditorView); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditorView.jsx new file mode 100644 index 0000000000..4d7e704ba3 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditorView.jsx @@ -0,0 +1,126 @@ +import React from 'react'; + +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Modal from 'nfvo-components/modal/Modal.jsx'; + +import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; +import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx'; +import LicenseAgreementEditor from './LicenseAgreementEditor.js'; +import InputOptions, {other as optionInputOther} from 'nfvo-components/input/inputOptions/InputOptions.jsx'; +import {optionsInputValues} from './LicenseAgreementConstants'; +import LicenseAgreementConfirmationModal from './LicenseAgreementConfirmationModal.jsx'; + + +class LicenseAgreementListEditorView extends React.Component { + static propTypes = { + vendorName: React.PropTypes.string, + licenseModelId: React.PropTypes.string.isRequired, + licenseAgreementList: React.PropTypes.array, + isReadOnlyMode: React.PropTypes.bool.isRequired, + isDisplayModal: React.PropTypes.bool, + isModalInEditMode: React.PropTypes.bool, + onAddLicenseAgreementClick: React.PropTypes.func, + onEditLicenseAgreementClick: React.PropTypes.func, + onDeleteLicenseAgreement: React.PropTypes.func, + onCallVCAction: React.PropTypes.func + }; + + static defaultProps = { + licenseAgreementList: [] + }; + + state = { + localFilter: '' + }; + + render() { + const {licenseModelId, vendorName, isReadOnlyMode, isDisplayModal, isModalInEditMode} = this.props; + const {onAddLicenseAgreementClick} = this.props; + const {localFilter} = this.state; + + return ( + <div className='license-agreement-list-editor'> + <ListEditorView + title={i18n('License Agreements for {vendorName} License Model', {vendorName})} + plusButtonTitle={i18n('Add License Agreement')} + onAdd={onAddLicenseAgreementClick} + filterValue={localFilter} + onFilter={filter => this.setState({localFilter: filter})} + isReadOnlyMode={isReadOnlyMode}> + {this.filterList().map(licenseAgreement => this.renderLicenseAgreementListItem(licenseAgreement, isReadOnlyMode))} + </ListEditorView> + <Modal show={isDisplayModal} bsSize='large' animation={true} className='license-agreement-modal'> + <Modal.Header> + <Modal.Title>{`${isModalInEditMode ? i18n('Edit License Agreement') : i18n('Create New License Agreement')}`}</Modal.Title> + </Modal.Header> + <Modal.Body> + { + isDisplayModal && ( + <LicenseAgreementEditor licenseModelId={licenseModelId} isReadOnlyMode={isReadOnlyMode} /> + ) + } + </Modal.Body> + </Modal> + <LicenseAgreementConfirmationModal licenseModelId={licenseModelId}/> + + </div> + ); + } + + filterList() { + let {licenseAgreementList} = this.props; + let {localFilter} = this.state; + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return licenseAgreementList.filter(({name = '', description = '', licenseTerm = ''}) => { + return escape(name).match(filter) || escape(description).match(filter) || escape(this.extractValue(licenseTerm)).match(filter); + }); + } + else { + return licenseAgreementList; + } + } + + renderLicenseAgreementListItem(licenseAgreement, isReadOnlyMode) { + let {id, name, description, licenseTerm, featureGroupsIds = []} = licenseAgreement; + let {onEditLicenseAgreementClick, onDeleteLicenseAgreement} = this.props; + return ( + <ListEditorItemView + key={id} + onSelect={() => onEditLicenseAgreementClick(licenseAgreement)} + onDelete={() => onDeleteLicenseAgreement(licenseAgreement)} + className='list-editor-item-view' + isReadOnlyMode={isReadOnlyMode}> + <div className='list-editor-item-view-field'> + <div className='title'>{i18n('Name')}</div> + <div className='text name'>{name}</div> + </div> + <div className='list-editor-item-view-field'> + <div className='list-editor-item-view-field-tight'> + <div className='title'>{i18n('Type')}</div> + <div className='text type'>{this.extractValue(licenseTerm)}</div> + </div> + <div className='list-editor-item-view-field-tight'> + <div className='title'>{i18n('Feature')}</div> + <div className='title'>{i18n('Groups')}</div> + <div className='feature-groups-count'>{featureGroupsIds.length}</div> + </div> + </div> + <div className='list-editor-item-view-field'> + <div className='title'>{i18n('Description')}</div> + <div className='text description'>{description}</div> + </div> + </ListEditorItemView> + ); + } + + extractValue(item) { + if (item === undefined) { + return ''; + } //TODO fix it later + + return item ? item.choice === optionInputOther.OTHER ? item.other : InputOptions.getTitleByName(optionsInputValues, item.choice) : ''; + } +} + +export default LicenseAgreementListEditorView; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListReducer.js new file mode 100644 index 0000000000..5b5fa00df1 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListReducer.js @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {actionTypes as licenseAgreementActionTypes} from './LicenseAgreementConstants'; + +export default (state = [], action) => { + switch (action.type) { + case licenseAgreementActionTypes.LICENSE_AGREEMENT_LIST_LOADED: + return [...action.response.results]; + case licenseAgreementActionTypes.ADD_LICENSE_AGREEMENT: + return [...state, action.licenseAgreement]; + case licenseAgreementActionTypes.EDIT_LICENSE_AGREEMENT: + const indexForEdit = state.findIndex(licenseAgreement => licenseAgreement.id === action.licenseAgreement.id); + return [...state.slice(0, indexForEdit), action.licenseAgreement, ...state.slice(indexForEdit + 1)]; + case licenseAgreementActionTypes.DELETE_LICENSE_AGREEMENT: + return state.filter(licenseAgreement => licenseAgreement.id !== action.licenseAgreementId); + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsActionHelper.js new file mode 100644 index 0000000000..50ac2c85a3 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsActionHelper.js @@ -0,0 +1,139 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; +import Configuration from 'sdc-app/config/Configuration.js'; +import {actionTypes as licenseKeyGroupsConstants} from './LicenseKeyGroupsConstants.js'; +import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js'; + +function baseUrl(licenseModelId) { + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-license-models/${licenseModelId}/license-key-groups`; +} + +function fetchLicenseKeyGroupsList(licenseModelId, version) { + let versionQuery = version ? `?version=${version}` : ''; + return RestAPIUtil.fetch(`${baseUrl(licenseModelId)}${versionQuery}`); +} + +function deleteLicenseKeyGroup(licenseModelId, licenseKeyGroupId) { + return RestAPIUtil.destroy(`${baseUrl(licenseModelId)}/${licenseKeyGroupId}`); +} + +function postLicenseKeyGroup(licenseModelId, licenseKeyGroup) { + return RestAPIUtil.create(baseUrl(licenseModelId), { + name: licenseKeyGroup.name, + description: licenseKeyGroup.description, + operationalScope: licenseKeyGroup.operationalScope, + type: licenseKeyGroup.type + }); +} + +function putLicenseKeyGroup(licenseModelId, licenseKeyGroup) { + return RestAPIUtil.save(`${baseUrl(licenseModelId)}/${licenseKeyGroup.id}`, { + name: licenseKeyGroup.name, + description: licenseKeyGroup.description, + operationalScope: licenseKeyGroup.operationalScope, + type: licenseKeyGroup.type + }); +} + + +export default { + fetchLicenseKeyGroupsList(dispatch, {licenseModelId, version}) { + return fetchLicenseKeyGroupsList(licenseModelId, version).then(response => dispatch({ + type: licenseKeyGroupsConstants.LICENSE_KEY_GROUPS_LIST_LOADED, + response + })); + }, + + openLicenseKeyGroupsEditor(dispatch, {licenseKeyGroup} = {}) { + dispatch({ + type: licenseKeyGroupsConstants.licenseKeyGroupsEditor.OPEN, + licenseKeyGroup + }); + }, + + closeLicenseKeyGroupEditor(dispatch){ + dispatch({ + type: licenseKeyGroupsConstants.licenseKeyGroupsEditor.CLOSE + }); + }, + + saveLicenseKeyGroup(dispatch, {licenseModelId, previousLicenseKeyGroup, licenseKeyGroup}) { + if (previousLicenseKeyGroup) { + return putLicenseKeyGroup(licenseModelId, licenseKeyGroup).then(() => { + dispatch({ + type: licenseKeyGroupsConstants.EDIT_LICENSE_KEY_GROUP, + licenseKeyGroup + }); + }); + } + else { + return postLicenseKeyGroup(licenseModelId, licenseKeyGroup).then(response => { + dispatch({ + type: licenseKeyGroupsConstants.ADD_LICENSE_KEY_GROUP, + licenseKeyGroup: { + ...licenseKeyGroup, + id: response.value + } + }); + }); + } + + + }, + + deleteLicenseKeyGroup(dispatch, {licenseModelId, licenseKeyGroupId}){ + return deleteLicenseKeyGroup(licenseModelId, licenseKeyGroupId).then(()=> { + dispatch({ + type: licenseKeyGroupsConstants.DELETE_LICENSE_KEY_GROUP, + licenseKeyGroupId + }); + }); + }, + + licenseKeyGroupEditorDataChanged(dispatch, {deltaData}) { + dispatch({ + type: licenseKeyGroupsConstants.licenseKeyGroupsEditor.DATA_CHANGED, + deltaData + }); + }, + + hideDeleteConfirm(dispatch) { + dispatch({ + type: licenseKeyGroupsConstants.LICENSE_KEY_GROUPS_DELETE_CONFIRM, + licenseKeyGroupToDelete: false + }); + }, + + openDeleteLicenseAgreementConfirm(dispatch, {licenseKeyGroup}) { + dispatch({ + type: licenseKeyGroupsConstants.LICENSE_KEY_GROUPS_DELETE_CONFIRM, + licenseKeyGroupToDelete: licenseKeyGroup + }); + }, + + switchVersion(dispatch, {licenseModelId, version}) { + LicenseModelActionHelper.fetchLicenseModelById(dispatch, {licenseModelId, version}).then(() => { + this.fetchLicenseKeyGroupsList(dispatch, {licenseModelId, version}); + }); + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsConfirmationModal.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsConfirmationModal.jsx new file mode 100644 index 0000000000..2413db51d0 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsConfirmationModal.jsx @@ -0,0 +1,49 @@ +import React from 'react'; +import {connect} from 'react-redux'; +import ConfirmationModalView from 'nfvo-components/confirmations/ConfirmationModalView.jsx'; +import LicenseKeyGroupsActionHelper from './LicenseKeyGroupsActionHelper.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +function renderMsg(licenseKeyGroupToDelete) { + let name = licenseKeyGroupToDelete ? licenseKeyGroupToDelete.name : ''; + let msg = i18n('Are you sure you want to delete "{name}"?', {name}); + let subMsg = licenseKeyGroupToDelete + && licenseKeyGroupToDelete.referencingFeatureGroups + && licenseKeyGroupToDelete.referencingFeatureGroups.length > 0 ? + i18n('This license key group is associated with one or more feature groups') : + ''; + return( + <div> + <p>{msg}</p> + <p>{subMsg}</p> + </div> + ); +}; + +const mapStateToProps = ({licenseModel: {licenseKeyGroup}}, {licenseModelId}) => { + let {licenseKeyGroupToDelete} = licenseKeyGroup; + const show = licenseKeyGroupToDelete !== false; + return { + show, + title: 'Warning!', + type: 'warning', + msg: renderMsg(licenseKeyGroupToDelete), + confirmationDetails: {licenseKeyGroupToDelete, licenseModelId} + }; +}; + +const mapActionsToProps = (dispatch) => { + return { + onConfirmed: ({licenseKeyGroupToDelete, licenseModelId}) => { + + LicenseKeyGroupsActionHelper.deleteLicenseKeyGroup(dispatch, {licenseModelId, licenseKeyGroupId:licenseKeyGroupToDelete.id}); + LicenseKeyGroupsActionHelper.hideDeleteConfirm(dispatch); + }, + onDeclined: () => { + LicenseKeyGroupsActionHelper.hideDeleteConfirm(dispatch); + } + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(ConfirmationModalView); + diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsConstants.js new file mode 100644 index 0000000000..d32bc52744 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsConstants.js @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import keyMirror from 'nfvo-utils/KeyMirror.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +export const actionTypes = keyMirror({ + + LICENSE_KEY_GROUPS_LIST_LOADED: null, + DELETE_LICENSE_KEY_GROUP: null, + EDIT_LICENSE_KEY_GROUP: null, + ADD_LICENSE_KEY_GROUP: null, + LICENSE_KEY_GROUPS_DELETE_CONFIRM: null, + licenseKeyGroupsEditor: { + OPEN: null, + CLOSE: null, + DATA_CHANGED: null, + } +}); + +export const defaultState = { + licenseKeyGroupsEditor: { + type: '', + operationalScope: {choices: [], other: ''} + } +}; + +export const optionsInputValues = { + OPERATIONAL_SCOPE: [ + {enum: '', title: i18n('please select…')}, + {enum: 'Network_Wide', title: 'Network Wide'}, + {enum: 'Availability_Zone', title: 'Availability Zone'}, + {enum: 'Data_Center', title: 'Data Center'}, + {enum: 'Tenant', title: 'Tenant'}, + {enum: 'VM', title: 'VM'}, + {enum: 'CPU', title: 'CPU'}, + {enum: 'Core', title: 'Core'} + ], + TYPE: [ + {enum: '', title: i18n('please select…')}, + {enum: 'Universal', title: 'Universal'}, + {enum: 'Unique', title: 'Unique'}, + {enum: 'One_Time', title: 'One Time'} + ] +}; + + diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditor.js new file mode 100644 index 0000000000..3940ec594a --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditor.js @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {connect} from 'react-redux'; +import LicenseKeyGroupsActionHelper from './LicenseKeyGroupsActionHelper.js'; +import LicenseKeyGroupsEditorView from './LicenseKeyGroupsEditorView.jsx'; + +const mapStateToProps = ({licenseModel: {licenseKeyGroup}}) => { + + + let {data} = licenseKeyGroup.licenseKeyGroupsEditor; + + let previousData; + const licenseKeyGroupId = data ? data.id : null; + if(licenseKeyGroupId) { + previousData = licenseKeyGroup.licenseKeyGroupsList.find(licenseKeyGroup => licenseKeyGroup.id === licenseKeyGroupId); + } + + return { + data, + previousData + }; +}; + +const mapActionsToProps = (dispatch, {licenseModelId}) => { + return { + onDataChanged: deltaData => LicenseKeyGroupsActionHelper.licenseKeyGroupEditorDataChanged(dispatch, {deltaData}), + onCancel: () => LicenseKeyGroupsActionHelper.closeLicenseKeyGroupEditor(dispatch), + onSubmit: ({previousLicenseKeyGroup, licenseKeyGroup}) => { + LicenseKeyGroupsActionHelper.closeLicenseKeyGroupEditor(dispatch); + LicenseKeyGroupsActionHelper.saveLicenseKeyGroup(dispatch, {licenseModelId, previousLicenseKeyGroup, licenseKeyGroup}); + } + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(LicenseKeyGroupsEditorView); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditorReducer.js new file mode 100644 index 0000000000..a74498269a --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditorReducer.js @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {actionTypes, defaultState} from './LicenseKeyGroupsConstants.js'; + +export default (state = {}, action) => { + switch (action.type) { + case actionTypes.licenseKeyGroupsEditor.OPEN: + return { + ...state, + data: action.licenseKeyGroup ? {...action.licenseKeyGroup} : defaultState.licenseKeyGroupsEditor + }; + case actionTypes.licenseKeyGroupsEditor.CLOSE: + return {}; + case actionTypes.licenseKeyGroupsEditor.DATA_CHANGED: + return { + ...state, + data: { + ...state.data, + ...action.deltaData + } + }; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditorView.jsx new file mode 100644 index 0000000000..102e713060 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditorView.jsx @@ -0,0 +1,92 @@ +import React from 'react'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +import ValidationForm from 'nfvo-components/input/validation/ValidationForm.jsx'; +import ValidationInput from 'nfvo-components/input/validation/ValidationInput.jsx'; +import {optionsInputValues as licenseKeyGroupOptionsInputValues} from './LicenseKeyGroupsConstants.js'; +import {other as optionInputOther} from 'nfvo-components/input/inputOptions/InputOptions.jsx'; + +const LicenseKeyGroupPropType = React.PropTypes.shape({ + id: React.PropTypes.string, + name: React.PropTypes.string, + description: React.PropTypes.string, + operationalScope: React.PropTypes.shape({ + choices: React.PropTypes.array, + other: React.PropTypes.string + }), + type: React.PropTypes.string +}); + +class LicenseKeyGroupsEditorView extends React.Component { + static propTypes = { + data: LicenseKeyGroupPropType, + previousData: LicenseKeyGroupPropType, + isReadOnlyMode: React.PropTypes.bool, + onDataChanged: React.PropTypes.func.isRequired, + onSubmit: React.PropTypes.func.isRequired, + onCancel: React.PropTypes.func.isRequired + }; + + static defaultProps = { + data: {} + }; + + render() { + let {data = {}, onDataChanged, isReadOnlyMode} = this.props; + let {name, description, operationalScope, type} = data; + return ( + <ValidationForm + ref='validationForm' + hasButtons={true} + onSubmit={ () => this.submit() } + onReset={ () => this.props.onCancel() } + labledButtons={true} + isReadOnlyMode={isReadOnlyMode} + className='license-key-groups-form'> + <div className='license-key-groups-form-row'> + <ValidationInput + onChange={name => onDataChanged({name})} + ref='name' + label={i18n('Name')} + value={name} + validations={{maxLength: 120, required: true}} + type='text'/> + <ValidationInput + isMultiSelect={true} + isRequired={true} + onEnumChange={operationalScope => onDataChanged({operationalScope:{choices: operationalScope, other: ''}})} + onOtherChange={operationalScope => onDataChanged({operationalScope:{choices: [optionInputOther.OTHER], other: operationalScope}})} + label={i18n('Operational Scope')} + validations={{required: true}} + multiSelectedEnum={operationalScope && operationalScope.choices} + otherValue={operationalScope && operationalScope.other} + values={licenseKeyGroupOptionsInputValues.OPERATIONAL_SCOPE}/> + </div> + <div className='license-key-groups-form-row'> + <ValidationInput + onChange={description => onDataChanged({description})} + ref='description' + label={i18n('Description')} + value={description} + validations={{maxLength: 1000, required: true}} + type='textarea'/> + <ValidationInput + isRequired={true} + onEnumChange={type => onDataChanged({type})} + selectedEnum={type} + label={i18n('Type')} + type='select' + validations={{required: true}} + values={licenseKeyGroupOptionsInputValues.TYPE}/> + </div> + </ValidationForm> + ); + } + + submit() { + const {data: licenseKeyGroup, previousData: previousLicenseKeyGroup} = this.props; + this.props.onSubmit({licenseKeyGroup, previousLicenseKeyGroup}); + } +} + +export default LicenseKeyGroupsEditorView; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditor.js new file mode 100644 index 0000000000..e1b610f973 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditor.js @@ -0,0 +1,50 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {connect} from 'react-redux'; +import LicenseKeyGroupsActionHelper from './LicenseKeyGroupsActionHelper.js'; +import LicenseKeyGroupsListEditorView from './LicenseKeyGroupsListEditorView.jsx'; +import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; + +const mapStateToProps = ({licenseModel: {licenseKeyGroup, licenseModelEditor}}) => { + let {licenseKeyGroupsList} = licenseKeyGroup; + let {data} = licenseKeyGroup.licenseKeyGroupsEditor; + let {vendorName} = licenseModelEditor.data; + let isReadOnlyMode = VersionControllerUtils.isReadOnly(licenseModelEditor.data); + + return { + vendorName, + licenseKeyGroupsList, + isReadOnlyMode, + isDisplayModal: Boolean(data), + isModalInEditMode: Boolean(data && data.id) + }; +}; + +const mapActionsToProps = (dispatch) => { + return { + onAddLicenseKeyGroupClick: () => LicenseKeyGroupsActionHelper.openLicenseKeyGroupsEditor(dispatch), + onEditLicenseKeyGroupClick: licenseKeyGroup => LicenseKeyGroupsActionHelper.openLicenseKeyGroupsEditor(dispatch, {licenseKeyGroup}), + onDeleteLicenseKeyGroupClick: licenseKeyGroup => LicenseKeyGroupsActionHelper.openDeleteLicenseAgreementConfirm(dispatch, {licenseKeyGroup}) + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(LicenseKeyGroupsListEditorView); + diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditorView.jsx new file mode 100644 index 0000000000..1ed1d2093a --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditorView.jsx @@ -0,0 +1,138 @@ +import React from 'react'; + +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Modal from 'nfvo-components/modal/Modal.jsx'; +import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; +import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx'; + +import LicenseKeyGroupsEditor from './LicenseKeyGroupsEditor.js'; +import InputOptions, {other as optionInputOther} from 'nfvo-components/input/inputOptions/InputOptions.jsx'; +import {optionsInputValues} from './LicenseKeyGroupsConstants'; +import LicenseKeyGroupsConfirmationModal from './LicenseKeyGroupsConfirmationModal.jsx'; + + +class LicenseKeyGroupsListEditorView extends React.Component { + static propTypes = { + vendorName: React.PropTypes.string, + licenseModelId: React.PropTypes.string.isRequired, + licenseKeyGroupsList: React.PropTypes.array, + isReadOnlyMode: React.PropTypes.bool.isRequired, + isDisplayModal: React.PropTypes.bool, + isModalInEditMode: React.PropTypes.bool, + onAddLicenseKeyGroupClick: React.PropTypes.func, + onEditLicenseKeyGroupClick: React.PropTypes.func, + onDeleteLicenseKeyGroupClick: React.PropTypes.func + }; + + static defaultProps = { + licenseKeyGroupsList: [] + }; + + state = { + localFilter: '' + }; + + render() { + let {licenseModelId, vendorName, isReadOnlyMode, isDisplayModal, isModalInEditMode} = this.props; + let {onAddLicenseKeyGroupClick} = this.props; + const {localFilter} = this.state; + + return ( + <div className='license-key-groups-list-editor'> + <ListEditorView + title={i18n('License Key Groups for {vendorName} License Model', {vendorName})} + plusButtonTitle={i18n('Add License Key Group')} + onAdd={onAddLicenseKeyGroupClick} + filterValue={localFilter} + onFilter={filter => this.setState({localFilter: filter})} + isReadOnlyMode={isReadOnlyMode}> + {this.filterList().map(licenseKeyGroup => (this.renderLicenseKeyGroupListItem(licenseKeyGroup, isReadOnlyMode)))} + </ListEditorView> + <Modal show={isDisplayModal} bsSize='large' animation={true} className='license-key-groups-modal'> + <Modal.Header> + <Modal.Title>{`${isModalInEditMode ? i18n('Edit License Key Group') : i18n('Create New License Key Group')}`}</Modal.Title> + </Modal.Header> + <Modal.Body> + { + isDisplayModal && ( + <LicenseKeyGroupsEditor licenseModelId={licenseModelId} isReadOnlyMode={isReadOnlyMode}/> + ) + } + </Modal.Body> + </Modal> + <LicenseKeyGroupsConfirmationModal licenseModelId={licenseModelId}/> + + </div> + ); + } + + filterList() { + let {licenseKeyGroupsList} = this.props; + let {localFilter} = this.state; + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return licenseKeyGroupsList.filter(({name = '', description = '', operationalScope = '', type = ''}) => { + return escape(name).match(filter) || escape(description).match(filter) || escape(this.extractValue(operationalScope)).match(filter) || escape(type).match(filter); + }); + } + else { + return licenseKeyGroupsList; + } + } + + renderLicenseKeyGroupListItem(licenseKeyGroup, isReadOnlyMode) { + let {id, name, description, operationalScope, type} = licenseKeyGroup; + let {onEditLicenseKeyGroupClick, onDeleteLicenseKeyGroupClick} = this.props; + return ( + <ListEditorItemView + key={id} + onSelect={() => onEditLicenseKeyGroupClick(licenseKeyGroup)} + onDelete={() => onDeleteLicenseKeyGroupClick(licenseKeyGroup)} + className='list-editor-item-view' + isReadOnlyMode={isReadOnlyMode}> + <div className='list-editor-item-view-field'> + <div className='title'>{i18n('Name')}</div> + <div className='text name'>{name}</div> + </div> + + <div className='list-editor-item-view-field'> + <div className='title'>{i18n('Operational Scope')}</div> + <div className='text operational-scope'>{operationalScope && this.getOperationalScopes(operationalScope)}</div> + + <div className='title'>{i18n('Type')}</div> + <div className='text type'>{InputOptions.getTitleByName(optionsInputValues, type)}</div> + </div> + <div className='list-editor-item-view-field'> + <div className='title'>{i18n('Description')}</div> + <div className='text description'>{description}</div> + </div> + </ListEditorItemView> + ); + } + + getOperationalScopes(operationalScope) { + if(operationalScope.choices.toString() === i18n(optionInputOther.OTHER) && operationalScope.other !== '') { + return operationalScope.other; + } + else { + let allOpScopes = ''; + for (let opScope of operationalScope.choices) { + allOpScopes += allOpScopes === '' ? InputOptions.getTitleByName(optionsInputValues, opScope) : `, ${InputOptions.getTitleByName(optionsInputValues, opScope)}`; + } + return allOpScopes; + } + } + + extractValue(item) { + if (item === undefined) { + return ''; + } //TODO fix it later + + return item ? item.choice === optionInputOther.OTHER ? item.other : InputOptions.getTitleByName(optionsInputValues, item.choice) : ''; + } +} + +export default LicenseKeyGroupsListEditorView; + + + diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListReducer.js new file mode 100644 index 0000000000..54ce4e3955 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListReducer.js @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import {actionTypes} from './LicenseKeyGroupsConstants.js'; +export default (state = [], action) => { + switch (action.type) { + case actionTypes.LICENSE_KEY_GROUPS_LIST_LOADED: + return [...action.response.results]; + case actionTypes.DELETE_LICENSE_KEY_GROUP: + return state.filter(licenseKeyGroup => licenseKeyGroup.id !== action.licenseKeyGroupId); + case actionTypes.ADD_LICENSE_KEY_GROUP: + return [...state, action.licenseKeyGroup]; + case actionTypes.EDIT_LICENSE_KEY_GROUP: + const indexForEdit = state.findIndex(licenseKeyGroup => licenseKeyGroup.id === action.licenseKeyGroup.id); + return [...state.slice(0, indexForEdit), action.licenseKeyGroup, ...state.slice(indexForEdit + 1)]; + default: + return state; + } +}; + |