/*! * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an 'AS IS' BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing * permissions and limitations under the License. */ import {actionTypes, rules, dataRules, SyncStates} from './MergeEditorConstants.js'; import cloneDeep from 'lodash/cloneDeep.js'; import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; import ItemsHelper from '../../common/helpers/ItemsHelper.js'; import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import {optionsInputValues as epOptionsValues} from 'sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js'; import {optionsInputValues as laOptionsValues} from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js'; import {optionsInputValues as processOptionValues} from 'sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesConstants.js'; import {selectValues as limitSelectValues} from 'sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js'; import FeatureGroupsActionHelper from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js'; import LicenseAgreementActionHelper from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js'; import moment from 'moment'; import {DATE_FORMAT} from 'sdc-app/onboarding/OnboardingConstants.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; function softwareProductCategoriesUrl() { const restCatalogPrefix = Configuration.get('restCatalogPrefix'); return `${restCatalogPrefix}/v1/categories/resources/`; } function versionUrl(itemId, versionId) { const restPrefix = Configuration.get('restPrefix'); return `${restPrefix}/v1.0/items/${itemId}/versions/${versionId}`; } function baseUrl(itemId, version, conflictId) { const versionId = version.id; const restPrefix = Configuration.get('restPrefix'); let baseUrl = `${restPrefix}/v1.0/items/${itemId}/versions/${versionId}/conflicts`; return conflictId ? `${baseUrl}/${conflictId}` : baseUrl; } function fetchConflicts({itemId, version}) { return RestAPIUtil.fetch(`${baseUrl(itemId, version)}`); } function fetchConflictById({itemId, version, cid}) { return RestAPIUtil.fetch(`${baseUrl(itemId, version, cid)}`); } function resolveConflict({itemId, version, conflictId, resolution}) { return RestAPIUtil.put(`${baseUrl(itemId, version, conflictId)}`, {resolution}); } function fetchCategories() { return RestAPIUtil.fetch(softwareProductCategoriesUrl()); } function fetchVersion({vendorId, licensingVersion}) { return RestAPIUtil.fetch(versionUrl(vendorId, licensingVersion)); } function createCategoryStr(data, {categories}) { let {category, subCategory} = data; let foundCat = categories.find(element => element.uniqueId === category); if (!foundCat) { return ''; } let catName = foundCat.name; let foundSub = foundCat.subcategories.find(element => element.uniqueId === subCategory); if (!foundSub) { return `${catName}`; } let subcatName = foundSub.name; return `${catName} - ${subcatName}`; } function getEnumValues({enums, list}) { if (!list) { return ''; } return list.map(item => enums.find(el => el.enum === item).title); } const MergeEditorActionHelper = { analyzeSyncResult(dispatch, {itemId, version}) { return ItemsHelper.checkItemStatus(dispatch, {itemId, versionId: version.id}).then((response) => { let inMerge = response && response.state && response.state.synchronizationState === SyncStates.MERGE; if (inMerge) { MergeEditorActionHelper.fetchConflicts(dispatch, {itemId, version}).then(() => dispatch({ type: modalActionTypes.GLOBAL_MODAL_SHOW, data: { modalComponentName: modalContentMapper.MERGE_EDITOR, modalClassName: 'merge-editor-modal', title: `${i18n('Merge Required')} - ${version.description}`, onDeclined: () => { dispatch({ type: modalActionTypes.GLOBAL_MODAL_CLOSE }); }, modalComponentProps: { size: 'lg', type: 'default' } } }) ); } return Promise.resolve({updatedVersion: response, inMerge, isDirty: response.state.dirty}); }); }, fetchConflicts(dispatch, {itemId, version}) { return fetchConflicts({itemId, version}).then( (data) => { dispatch({ type: actionTypes.LOAD_CONFLICTS, data }); return data; } ); }, fetchConflict(dispatch, {itemId, version, cid}) { fetchConflictById({itemId, version, cid}).then( (data) => { let newData = {}; newData = MergeEditorActionHelper.processConflict(dispatch, {conflict: data, itemId, cid, version}); dispatch({ type: actionTypes.LOAD_CONFLICT, data: newData }); } ); }, resolveConflict(dispatch, {itemId, version, conflictId, resolution, currentScreen}) { resolveConflict({itemId, version, conflictId, resolution}).then(() => { MergeEditorActionHelper.fetchConflicts(dispatch, {itemId, version}).then(conflicts => { if(conflicts.conflictInfoList && conflicts.conflictInfoList.length === 0) { dispatch({ type: modalActionTypes.GLOBAL_MODAL_CLOSE }); ScreensHelper.loadLandingScreen(dispatch, {previousScreenName: currentScreen.screen, props: currentScreen.props}); ItemsHelper.checkItemStatus(dispatch, {itemId, versionId: version.id}); } }); }); }, createConflictObject(data, {cid, conflict, dispatch, itemId, version, isYours}) { let newData = {}; for (let key in data) { if (data.hasOwnProperty(key)) { let value = data[key]; let fieldRule = dataRules[conflict.type] && dataRules[conflict.type][key] || dataRules.general[key]; if (fieldRule) { switch (fieldRule.rule) { case rules.SKIP: break; case rules.BOOLEAN: let {trueValue, falseValue} = fieldRule; newData[key] = value === trueValue ? true : value === falseValue ? false : undefined; break; case rules.PARSE: let {moveFields, subFields} = fieldRule; if (moveFields) { let fields = subFields || Object.keys(value); fields.forEach(field => { newData[field] = MergeEditorActionHelper.createConflictObject( value[field], {cid, conflict, dispatch, itemId, version, isYours} ); }); } else { newData[key] = MergeEditorActionHelper.createConflictObject( value, {cid, conflict, dispatch, itemId, version, isYours} ); } break; case rules.FUNCTION: let {args, functionName} = fieldRule; newData[key] = MergeEditorActionHelper[functionName](data, { cid, conflict, dispatch, version, fieldName: key, isYours, itemId, args }); break; default: newData[key] = value; break; } } else { newData[key] = value; } } } return newData; }, getNamesFromIDs(data, {version, cid, dispatch, itemId, fieldName, isYours, args}) { let idList = data[fieldName] || []; let {fetchFunction, fetchField} = args; let promises = idList.map(id => new Promise(resolve => MergeEditorActionHelper[fetchFunction]( dispatch, {licenseModelId: itemId, [fetchField]: id, version} ).then(item => resolve(item.name)) ) ); Promise.all(promises).then(fetchedItems => { let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; dispatch({ type: actionTypes.DATA_PROCESSED, data: { cid, [yoursOrTheirs]: { name: fieldName, value: fetchedItems } } }); }); return idList; }, getFeatureGroups(data, {version, cid, dispatch, itemId, fieldName, isYours}) { let featureGroups = data[fieldName] || []; if (!(featureGroups instanceof Array)) { featureGroups = [featureGroups]; } let promises = featureGroups.map(featureGroupId => new Promise(resolve => FeatureGroupsActionHelper.fetchFeatureGroup( dispatch, {licenseModelId: itemId, featureGroupId, version} ).then(featureGroup => resolve(featureGroup.name)) .catch(reason => console.log(`getFeatureGroups Promise rejected ('${reason}')`)) ) ); Promise.all(promises).then(fetchedGroups => { let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; dispatch({ type: actionTypes.DATA_PROCESSED, data: { cid, [yoursOrTheirs]: { name: fieldName, value: fetchedGroups } } }); }); return featureGroups; }, getLicenseAgreements(data, {version, cid, dispatch, itemId, fieldName, isYours}) { let licenseAgreements = data[fieldName] || []; if (!(licenseAgreements instanceof Array)) { licenseAgreements = [licenseAgreements]; } let promises = licenseAgreements.map(licenseAgreementId => new Promise(resolve => LicenseAgreementActionHelper.fetchLicenseAgreement( dispatch, {licenseModelId: itemId, licenseAgreementId, version} ).then(licenseAgreement => resolve(licenseAgreement.name)) .catch(reason => console.log(`getLicenseAgreements Promise rejected ('${reason}')`)) ) ); Promise.all(promises).then(fetchedAgreements => { let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; dispatch({ type: actionTypes.DATA_PROCESSED, data: { cid, [yoursOrTheirs]: { name: fieldName, value: fetchedAgreements } } }); }); return licenseAgreements; }, processConflict(dispatch, {conflict, cid, version, itemId,}) { let {id, type, yours, theirs} = conflict; let newYours = MergeEditorActionHelper.createConflictObject( cloneDeep(yours), {cid, conflict, dispatch, itemId, version, isYours: true} ); let newTheirs = MergeEditorActionHelper.createConflictObject( cloneDeep(theirs), {cid, conflict, dispatch, itemId, version, isYours: false} ); return { id, type, yours: newYours, theirs: newTheirs }; }, reduceList(data, {fieldName, args}) { let {subField} = args; return data[fieldName].map(el => el[subField]); }, getEnumList({fieldName}) { const enumLists = { 'licenseTerm': laOptionsValues.LICENSE_MODEL_TYPE, 'operationalScope': epOptionsValues.OPERATIONAL_SCOPE, 'processType': processOptionValues.PROCESS_TYPE, 'limitType': [ {title: 'Service Provider', enum: 'ServiceProvider'}, {title: 'Vendor', enum: 'Vendor'} ], 'limitUnit': limitSelectValues.UNIT }; return enumLists[fieldName]; }, getEnumValue(data, {fieldName, args = {}}) { let value = data[fieldName]; let enumValues = MergeEditorActionHelper.getEnumList({fieldName: args.listName || fieldName}); let enumValue = enumValues.find(el => el.enum === value); return enumValue && enumValue.title || value; }, processChoice(data, {fieldName, args = {}}) { let value = data[fieldName]; let enumValues = MergeEditorActionHelper.getEnumList({fieldName: args.listName || fieldName}); let newValue = value.other || enumValues && enumValues.find(el => el.enum === value.choice).title || value.choice; return newValue; }, processChoices(data, {fieldName, args = {}}) { let value = data[fieldName]; let enumValues = MergeEditorActionHelper.getEnumList({fieldName: args.listName || fieldName}); let newValue = value.other || getEnumValues({enums: enumValues, list: value.choices}) || value.choices; return newValue; }, convertArrayToObject(data, {fieldName}) { let value = data[fieldName]; let newValue = {}; value.forEach((el, index) => { newValue[index] = el; }); return newValue; }, fetchCategory(data, {cid, isYours, fieldName, dispatch}) { fetchCategories().then((categories) => { let value = createCategoryStr(data, {categories}); let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; dispatch({ type: actionTypes.DATA_PROCESSED, data: { cid, [yoursOrTheirs]: { name: fieldName, value } } }); }); }, fetchLMVersion(data, {cid, dispatch, isYours}) { let {licensingVersion, vendorId} = data; let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; if (licensingVersion) { fetchVersion({licensingVersion, vendorId}).then(response => { dispatch({ type: actionTypes.DATA_PROCESSED, data: { cid, [yoursOrTheirs]: { name: 'licensingVersion', value: response.name } } }); }); } }, parseDate(data, {fieldName}) { let date = data[fieldName]; return date && moment(date, DATE_FORMAT).format(DATE_FORMAT); } }; export default MergeEditorActionHelper;