blob: fb58151bc84fb035fe219db84836791b7859a7b8 [file] [log] [blame]
Einav Weiss Keidar1801b242018-08-13 16:19:46 +03001/*
2 * Copyright © 2016-2018 European Support Limited
talig8e9c0652017-12-20 14:30:43 +02003 *
Einav Weiss Keidar1801b242018-08-13 16:19:46 +03004 * Licensed under the Apache License, Version 2.0 (the "License");
talig8e9c0652017-12-20 14:30:43 +02005 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
Einav Weiss Keidar1801b242018-08-13 16:19:46 +03008 * http://www.apache.org/licenses/LICENSE-2.0
talig8e9c0652017-12-20 14:30:43 +02009 *
10 * Unless required by applicable law or agreed to in writing, software
Einav Weiss Keidar1801b242018-08-13 16:19:46 +030011 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
talig8e9c0652017-12-20 14:30:43 +020015 */
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020016import {
17 actionTypes,
18 rules,
19 dataRules,
20 SyncStates
21} from './MergeEditorConstants.js';
talig8e9c0652017-12-20 14:30:43 +020022import cloneDeep from 'lodash/cloneDeep.js';
23import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js';
24import Configuration from 'sdc-app/config/Configuration.js';
25import ItemsHelper from '../../common/helpers/ItemsHelper.js';
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020026import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js';
Einav Weiss Keidar1801b242018-08-13 16:19:46 +030027import {
28 actionTypes as modalActionTypes,
29 modalSizes
30} from 'nfvo-components/modal/GlobalModalConstants.js';
talig8e9c0652017-12-20 14:30:43 +020031import i18n from 'nfvo-utils/i18n/i18n.js';
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020032import { optionsInputValues as laOptionsValues } from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js';
33import { optionsInputValues as processOptionValues } from 'sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesConstants.js';
34import { selectValues as limitSelectValues } from 'sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js';
talig8e9c0652017-12-20 14:30:43 +020035import FeatureGroupsActionHelper from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js';
36import LicenseAgreementActionHelper from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js';
37import moment from 'moment';
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020038import { DATE_FORMAT } from 'sdc-app/onboarding/OnboardingConstants.js';
talig8e9c0652017-12-20 14:30:43 +020039import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js';
40
41function softwareProductCategoriesUrl() {
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020042 const restCatalogPrefix = Configuration.get('restCatalogPrefix');
43 return `${restCatalogPrefix}/v1/categories/resources/`;
talig8e9c0652017-12-20 14:30:43 +020044}
45
46function versionUrl(itemId, versionId) {
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020047 const restPrefix = Configuration.get('restPrefix');
48 return `${restPrefix}/v1.0/items/${itemId}/versions/${versionId}`;
talig8e9c0652017-12-20 14:30:43 +020049}
50
51function baseUrl(itemId, version, conflictId) {
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020052 const versionId = version.id;
53 const restPrefix = Configuration.get('restPrefix');
54 let baseUrl = `${restPrefix}/v1.0/items/${itemId}/versions/${versionId}/conflicts`;
55 return conflictId ? `${baseUrl}/${conflictId}` : baseUrl;
talig8e9c0652017-12-20 14:30:43 +020056}
57
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020058function fetchConflicts({ itemId, version }) {
59 return RestAPIUtil.fetch(`${baseUrl(itemId, version)}`);
talig8e9c0652017-12-20 14:30:43 +020060}
61
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020062function fetchConflictById({ itemId, version, cid }) {
63 return RestAPIUtil.fetch(`${baseUrl(itemId, version, cid)}`);
talig8e9c0652017-12-20 14:30:43 +020064}
65
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020066function resolveConflict({ itemId, version, conflictId, resolution }) {
67 return RestAPIUtil.put(`${baseUrl(itemId, version, conflictId)}`, {
68 resolution
69 });
talig8e9c0652017-12-20 14:30:43 +020070}
71
72function fetchCategories() {
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020073 return RestAPIUtil.fetch(softwareProductCategoriesUrl());
talig8e9c0652017-12-20 14:30:43 +020074}
75
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020076function fetchVersion({ vendorId, licensingVersion }) {
77 return RestAPIUtil.fetch(versionUrl(vendorId, licensingVersion));
talig8e9c0652017-12-20 14:30:43 +020078}
79
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020080function createCategoryStr(data, { categories }) {
81 let { category, subCategory } = data;
82 let foundCat = categories.find(element => element.uniqueId === category);
83 if (!foundCat) {
84 return '';
85 }
talig8e9c0652017-12-20 14:30:43 +020086
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020087 let catName = foundCat.name;
88 let foundSub = foundCat.subcategories.find(
89 element => element.uniqueId === subCategory
90 );
91 if (!foundSub) {
92 return `${catName}`;
93 }
talig8e9c0652017-12-20 14:30:43 +020094
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020095 let subcatName = foundSub.name;
96 return `${catName} - ${subcatName}`;
talig8e9c0652017-12-20 14:30:43 +020097}
98
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +020099function getEnumValues({ enums, list }) {
100 if (!list) {
101 return '';
102 }
103 return list.map(item => enums.find(el => el.enum === item).title);
talig8e9c0652017-12-20 14:30:43 +0200104}
105
106const MergeEditorActionHelper = {
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200107 analyzeSyncResult(dispatch, { itemId, version }) {
108 return ItemsHelper.checkItemStatus(dispatch, {
109 itemId,
110 versionId: version.id
111 }).then(response => {
112 let inMerge =
113 response &&
114 response.state &&
115 response.state.synchronizationState === SyncStates.MERGE;
116 if (inMerge) {
117 MergeEditorActionHelper.fetchConflicts(dispatch, {
118 itemId,
119 version
120 }).then(() =>
121 dispatch({
122 type: modalActionTypes.GLOBAL_MODAL_SHOW,
123 data: {
124 modalComponentName: modalContentMapper.MERGE_EDITOR,
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200125 title: `${i18n('Merge Required')} - ${
126 version.description
127 }`,
128 onDeclined: () => {
129 dispatch({
130 type: modalActionTypes.GLOBAL_MODAL_CLOSE
131 });
132 },
133 modalComponentProps: {
Einav Weiss Keidar1801b242018-08-13 16:19:46 +0300134 size: modalSizes.XLARGE
135 },
136 bodyClassName: 'merge-editor-modal'
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200137 }
138 })
139 );
140 }
141 return Promise.resolve({
142 updatedVersion: response,
143 inMerge,
144 isDirty: response.state.dirty
145 });
146 });
147 },
talig8e9c0652017-12-20 14:30:43 +0200148
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200149 fetchConflicts(dispatch, { itemId, version }) {
150 return fetchConflicts({ itemId, version }).then(data => {
151 dispatch({
152 type: actionTypes.LOAD_CONFLICTS,
153 data
154 });
155 return data;
156 });
157 },
talig8e9c0652017-12-20 14:30:43 +0200158
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200159 fetchConflict(dispatch, { itemId, version, cid }) {
160 fetchConflictById({ itemId, version, cid }).then(data => {
161 let newData = {};
162 newData = MergeEditorActionHelper.processConflict(dispatch, {
163 conflict: data,
164 itemId,
165 cid,
166 version
167 });
168 dispatch({
169 type: actionTypes.LOAD_CONFLICT,
170 data: newData
171 });
172 });
173 },
talig8e9c0652017-12-20 14:30:43 +0200174
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200175 resolveConflict(
176 dispatch,
177 { itemId, version, conflictId, resolution, currentScreen }
178 ) {
179 resolveConflict({ itemId, version, conflictId, resolution }).then(
180 () => {
181 MergeEditorActionHelper.fetchConflicts(dispatch, {
182 itemId,
183 version
184 }).then(conflicts => {
185 if (
186 conflicts.conflictInfoList &&
187 conflicts.conflictInfoList.length === 0
188 ) {
189 dispatch({
190 type: modalActionTypes.GLOBAL_MODAL_CLOSE
191 });
192 ScreensHelper.loadLandingScreen(dispatch, {
193 previousScreenName: currentScreen.screen,
194 props: currentScreen.props
195 });
196 ItemsHelper.checkItemStatus(dispatch, {
197 itemId,
198 versionId: version.id
199 });
200 }
201 });
202 }
203 );
204 },
talig8e9c0652017-12-20 14:30:43 +0200205
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200206 createConflictObject(
207 data,
208 { cid, conflict, dispatch, itemId, version, isYours }
209 ) {
210 let newData = {};
talig8e9c0652017-12-20 14:30:43 +0200211
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200212 for (let key in data) {
213 if (data.hasOwnProperty(key)) {
214 let value = data[key];
215 let fieldRule =
216 (dataRules[conflict.type] &&
217 dataRules[conflict.type][key]) ||
218 dataRules.general[key];
talig8e9c0652017-12-20 14:30:43 +0200219
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200220 if (fieldRule) {
221 switch (fieldRule.rule) {
222 case rules.SKIP:
223 break;
talig8e9c0652017-12-20 14:30:43 +0200224
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200225 case rules.BOOLEAN:
226 let { trueValue, falseValue } = fieldRule;
227 newData[key] =
228 value === trueValue
229 ? true
230 : value === falseValue ? false : undefined;
231 break;
talig8e9c0652017-12-20 14:30:43 +0200232
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200233 case rules.PARSE:
234 let { moveFields, subFields } = fieldRule;
235 if (moveFields) {
236 let fields = subFields || Object.keys(value);
237 fields.forEach(field => {
238 newData[
239 field
240 ] = MergeEditorActionHelper.createConflictObject(
241 value[field],
242 {
243 cid,
244 conflict,
245 dispatch,
246 itemId,
247 version,
248 isYours
249 }
250 );
251 });
252 } else {
253 newData[
254 key
255 ] = MergeEditorActionHelper.createConflictObject(
256 value,
257 {
258 cid,
259 conflict,
260 dispatch,
261 itemId,
262 version,
263 isYours
264 }
265 );
266 }
267 break;
talig8e9c0652017-12-20 14:30:43 +0200268
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200269 case rules.FUNCTION:
270 let { args, functionName } = fieldRule;
271 newData[key] = MergeEditorActionHelper[
272 functionName
273 ](data, {
274 cid,
275 conflict,
276 dispatch,
277 version,
278 fieldName: key,
279 isYours,
280 itemId,
281 args
282 });
283 break;
talig8e9c0652017-12-20 14:30:43 +0200284
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200285 default:
286 newData[key] = value;
287 break;
288 }
289 } else {
290 newData[key] = value;
291 }
292 }
293 }
talig8e9c0652017-12-20 14:30:43 +0200294
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200295 return newData;
296 },
talig8e9c0652017-12-20 14:30:43 +0200297
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200298 getNamesFromIDs(
299 data,
300 { version, cid, dispatch, itemId, fieldName, isYours, args }
301 ) {
302 let idList = data[fieldName] || [];
303 let { fetchFunction, fetchField } = args;
talig8e9c0652017-12-20 14:30:43 +0200304
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200305 let promises = idList.map(
306 id =>
307 new Promise(resolve =>
308 MergeEditorActionHelper[fetchFunction](dispatch, {
309 licenseModelId: itemId,
310 [fetchField]: id,
311 version
312 }).then(item => resolve(item.name))
313 )
314 );
talig8e9c0652017-12-20 14:30:43 +0200315
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200316 Promise.all(promises).then(fetchedItems => {
317 let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField';
318 dispatch({
319 type: actionTypes.DATA_PROCESSED,
320 data: {
321 cid,
322 [yoursOrTheirs]: { name: fieldName, value: fetchedItems }
323 }
324 });
325 });
talig8e9c0652017-12-20 14:30:43 +0200326
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200327 return idList;
328 },
talig8e9c0652017-12-20 14:30:43 +0200329
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200330 getFeatureGroups(
331 data,
332 { version, cid, dispatch, itemId, fieldName, isYours }
333 ) {
334 let featureGroups = data[fieldName] || [];
335 if (!(featureGroups instanceof Array)) {
336 featureGroups = [featureGroups];
337 }
talig8e9c0652017-12-20 14:30:43 +0200338
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200339 let promises = featureGroups.map(
340 featureGroupId =>
341 new Promise(resolve =>
342 FeatureGroupsActionHelper.fetchFeatureGroup(dispatch, {
343 licenseModelId: itemId,
344 featureGroupId,
345 version
346 })
347 .then(featureGroup => resolve(featureGroup.name))
348 .catch(reason =>
349 console.log(
350 `getFeatureGroups Promise rejected ('${reason}')`
351 )
352 )
353 )
354 );
talig8e9c0652017-12-20 14:30:43 +0200355
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200356 Promise.all(promises).then(fetchedGroups => {
357 let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField';
358 dispatch({
359 type: actionTypes.DATA_PROCESSED,
360 data: {
361 cid,
362 [yoursOrTheirs]: { name: fieldName, value: fetchedGroups }
363 }
364 });
365 });
talig8e9c0652017-12-20 14:30:43 +0200366
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200367 return featureGroups;
368 },
talig8e9c0652017-12-20 14:30:43 +0200369
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200370 getLicenseAgreements(
371 data,
372 { version, cid, dispatch, itemId, fieldName, isYours }
373 ) {
374 let licenseAgreements = data[fieldName] || [];
375 if (!(licenseAgreements instanceof Array)) {
376 licenseAgreements = [licenseAgreements];
377 }
talig8e9c0652017-12-20 14:30:43 +0200378
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200379 let promises = licenseAgreements.map(
380 licenseAgreementId =>
381 new Promise(resolve =>
382 LicenseAgreementActionHelper.fetchLicenseAgreement(
383 dispatch,
384 {
385 licenseModelId: itemId,
386 licenseAgreementId,
387 version
388 }
389 )
390 .then(licenseAgreement =>
391 resolve(licenseAgreement.name)
392 )
393 .catch(reason =>
394 console.log(
395 `getLicenseAgreements Promise rejected ('${reason}')`
396 )
397 )
398 )
399 );
talig8e9c0652017-12-20 14:30:43 +0200400
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200401 Promise.all(promises).then(fetchedAgreements => {
402 let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField';
403 dispatch({
404 type: actionTypes.DATA_PROCESSED,
405 data: {
406 cid,
407 [yoursOrTheirs]: {
408 name: fieldName,
409 value: fetchedAgreements
410 }
411 }
412 });
413 });
talig8e9c0652017-12-20 14:30:43 +0200414
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200415 return licenseAgreements;
416 },
talig8e9c0652017-12-20 14:30:43 +0200417
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200418 processConflict(dispatch, { conflict, cid, version, itemId }) {
419 let { id, type, yours, theirs } = conflict;
talig8e9c0652017-12-20 14:30:43 +0200420
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200421 let newYours = MergeEditorActionHelper.createConflictObject(
422 cloneDeep(yours),
423 { cid, conflict, dispatch, itemId, version, isYours: true }
424 );
425 let newTheirs = MergeEditorActionHelper.createConflictObject(
426 cloneDeep(theirs),
427 { cid, conflict, dispatch, itemId, version, isYours: false }
428 );
talig8e9c0652017-12-20 14:30:43 +0200429
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200430 return {
431 id,
432 type,
433 yours: newYours,
434 theirs: newTheirs
435 };
436 },
talig8e9c0652017-12-20 14:30:43 +0200437
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200438 reduceList(data, { fieldName, args }) {
439 let { subField } = args;
440 return data[fieldName].map(el => el[subField]);
441 },
talig8e9c0652017-12-20 14:30:43 +0200442
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200443 getEnumList({ fieldName }) {
444 const enumLists = {
445 licenseTerm: laOptionsValues.LICENSE_MODEL_TYPE,
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200446 processType: processOptionValues.PROCESS_TYPE,
447 limitType: [
448 { title: 'Service Provider', enum: 'ServiceProvider' },
449 { title: 'Vendor', enum: 'Vendor' }
450 ],
451 limitUnit: limitSelectValues.UNIT
452 };
talig8e9c0652017-12-20 14:30:43 +0200453
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200454 return enumLists[fieldName];
455 },
talig8e9c0652017-12-20 14:30:43 +0200456
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200457 getEnumValue(data, { fieldName, args = {} }) {
458 let value = data[fieldName];
459 let enumValues = MergeEditorActionHelper.getEnumList({
460 fieldName: args.listName || fieldName
461 });
462 let enumValue = enumValues.find(el => el.enum === value);
talig8e9c0652017-12-20 14:30:43 +0200463
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200464 return (enumValue && enumValue.title) || value;
465 },
talig8e9c0652017-12-20 14:30:43 +0200466
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200467 processChoice(data, { fieldName, args = {} }) {
468 let value = data[fieldName];
469 let enumValues = MergeEditorActionHelper.getEnumList({
470 fieldName: args.listName || fieldName
471 });
472 let newValue =
473 value.other ||
474 (enumValues &&
475 enumValues.find(el => el.enum === value.choice).title) ||
476 value.choice;
talig8e9c0652017-12-20 14:30:43 +0200477
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200478 return newValue;
479 },
talig8e9c0652017-12-20 14:30:43 +0200480
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200481 processChoices(data, { fieldName, args = {} }) {
482 let value = data[fieldName];
483 let enumValues = MergeEditorActionHelper.getEnumList({
484 fieldName: args.listName || fieldName
485 });
486 let newValue =
487 value.other ||
488 getEnumValues({ enums: enumValues, list: value.choices }) ||
489 value.choices;
talig8e9c0652017-12-20 14:30:43 +0200490
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200491 return newValue;
492 },
talig8e9c0652017-12-20 14:30:43 +0200493
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200494 convertArrayToObject(data, { fieldName }) {
495 let value = data[fieldName];
496 let newValue = {};
497 value.forEach((el, index) => {
498 newValue[index] = el;
499 });
500 return newValue;
501 },
talig8e9c0652017-12-20 14:30:43 +0200502
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200503 fetchCategory(data, { cid, isYours, fieldName, dispatch }) {
504 fetchCategories().then(categories => {
505 let value = createCategoryStr(data, { categories });
506 let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField';
talig8e9c0652017-12-20 14:30:43 +0200507
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200508 dispatch({
509 type: actionTypes.DATA_PROCESSED,
510 data: {
511 cid,
512 [yoursOrTheirs]: { name: fieldName, value }
513 }
514 });
515 });
516 },
talig8e9c0652017-12-20 14:30:43 +0200517
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200518 fetchLMVersion(data, { cid, dispatch, isYours }) {
519 let { licensingVersion, vendorId } = data;
520 let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField';
talig8e9c0652017-12-20 14:30:43 +0200521
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200522 if (licensingVersion) {
523 fetchVersion({ licensingVersion, vendorId }).then(response => {
524 dispatch({
525 type: actionTypes.DATA_PROCESSED,
526 data: {
527 cid,
528 [yoursOrTheirs]: {
529 name: 'licensingVersion',
530 value: response.name
531 }
532 }
533 });
534 });
535 }
536 },
talig8e9c0652017-12-20 14:30:43 +0200537
Einav Weiss Keidar7fdf7332018-03-20 14:45:40 +0200538 parseDate(data, { fieldName }) {
539 let date = data[fieldName];
540 return date && moment(date, DATE_FORMAT).format(DATE_FORMAT);
541 }
talig8e9c0652017-12-20 14:30:43 +0200542};
543
544export default MergeEditorActionHelper;