From 69bc458ded8e71ed01134fe7d13ddd26bf6c44a1 Mon Sep 17 00:00:00 2001 From: Ilya Lomtev Date: Fri, 12 Apr 2024 15:26:30 +0300 Subject: [PATCH] fix(settings): fix merge logic for plugins update in settings --- src/libs/settings/__tests__/settings.test.ts | 76 +++++++++++++++++++- src/libs/settings/mergeSettingStrategy.ts | 40 +++++++++++ src/libs/settings/settings.ts | 5 +- 3 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 src/libs/settings/mergeSettingStrategy.ts diff --git a/src/libs/settings/__tests__/settings.test.ts b/src/libs/settings/__tests__/settings.test.ts index e84c05d0..1074987f 100644 --- a/src/libs/settings/__tests__/settings.test.ts +++ b/src/libs/settings/__tests__/settings.test.ts @@ -1,6 +1,8 @@ +import {ChartKitPlugin} from 'src/types'; + import {settings} from '../settings'; -const resetSettings = () => settings.set({lang: 'en'}); +const resetSettings = () => settings.set({lang: 'en', plugins: []}); describe('libs/settings', () => { it('Default lang should be equal to en', () => { @@ -18,6 +20,78 @@ describe('libs/settings', () => { expect(result).toBe('ru'); }); + // Order test is important because settings module is singleton + it('Update plugins when it is empty', () => { + const initialPlugins: ChartKitPlugin[] = [ + { + type: 'highcharts', + renderer: 'highchartsInitial' as any, + }, + { + type: 'd3', + renderer: 'd3Initial' as any, + }, + ]; + + settings.set({ + plugins: initialPlugins, + }); + + expect(settings.get('plugins')).toEqual(initialPlugins); + }); + + it('Update existing plugin d3', () => { + settings.set({ + plugins: [ + { + type: 'd3', + renderer: 'd3Update' as any, + }, + ], + }); + + const result = settings.get('plugins'); + + expect(result).toEqual([ + { + type: 'highcharts', + renderer: 'highchartsInitial' as any, + }, + { + type: 'd3', + renderer: 'd3Update' as any, + }, + ]); + }); + + it('Add new plugin', () => { + settings.set({ + plugins: [ + { + type: 'yagr', + renderer: 'yagrUpdate' as any, + }, + ], + }); + + const result = settings.get('plugins'); + + expect(result).toEqual([ + { + type: 'highcharts', + renderer: 'highchartsInitial' as any, + }, + { + type: 'd3', + renderer: 'd3Update' as any, + }, + { + type: 'yagr', + renderer: 'yagrUpdate' as any, + }, + ]); + }); + beforeAll(resetSettings); afterEach(resetSettings); }); diff --git a/src/libs/settings/mergeSettingStrategy.ts b/src/libs/settings/mergeSettingStrategy.ts new file mode 100644 index 00000000..85e93621 --- /dev/null +++ b/src/libs/settings/mergeSettingStrategy.ts @@ -0,0 +1,40 @@ +import isObject from 'lodash/isObject'; +import mergeWith from 'lodash/mergeWith'; + +import {ChartKitPlugin} from 'src/types'; + +export function mergeSettingStrategy(objValue: any, srcValue: any, key: string): any { + if (key === 'plugins') { + const currentPlugins: ChartKitPlugin[] = [...objValue]; + const newPlugins: ChartKitPlugin[] = [...srcValue]; + // modify existing plugins + let newSettingsPlugins = currentPlugins.map((currentPlugin) => { + const newPluginIndex = newPlugins.findIndex(({type}) => type === currentPlugin.type); + + if (newPluginIndex !== -1) { + const newPlugin = newPlugins[newPluginIndex]; + newPlugins.splice(newPluginIndex, 1); + + return { + type: currentPlugin.type, + renderer: newPlugin.renderer, + }; + } + + return currentPlugin; + }); + + // add new plugins if it exist after modified + if (newPlugins.length > 0) { + newSettingsPlugins = [...newSettingsPlugins, ...newPlugins]; + } + + return newSettingsPlugins; + } + + if (isObject(objValue)) { + return mergeWith(objValue, srcValue, mergeSettingStrategy); + } + + return srcValue; +} diff --git a/src/libs/settings/settings.ts b/src/libs/settings/settings.ts index 749b2a80..f05d1795 100644 --- a/src/libs/settings/settings.ts +++ b/src/libs/settings/settings.ts @@ -1,11 +1,12 @@ import {configure} from '@gravity-ui/uikit'; import get from 'lodash/get'; -import merge from 'lodash/merge'; +import mergeWith from 'lodash/mergeWith'; import {i18nFactory} from '../../i18n'; import type {ChartKitHolidays, ChartKitLang, ChartKitPlugin} from '../../types'; import {EventEmitter} from './eventEmitter'; +import {mergeSettingStrategy} from './mergeSettingStrategy'; interface Settings { plugins: ChartKitPlugin[]; @@ -54,7 +55,7 @@ class ChartKitSettings { set(updates: Partial) { const filteredUpdates = removeUndefinedValues(updates); - this.settings = merge(this.settings, filteredUpdates); + this.settings = mergeWith(this.settings, filteredUpdates, mergeSettingStrategy); if (filteredUpdates.lang) { const lang = filteredUpdates.lang || this.get('lang');