/*! * 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;