diff --git a/src/libs/settings/__tests__/settings-update.test.ts b/src/libs/settings/__tests__/settings-update.test.ts new file mode 100644 index 00000000..ceaae775 --- /dev/null +++ b/src/libs/settings/__tests__/settings-update.test.ts @@ -0,0 +1,89 @@ +import {ChartKitPlugin} from 'src/types'; + +import {settings} from '../settings'; + +const resetSettings = () => settings.set({lang: 'en'}); + +const getMockedPlugin = (type: string, renderer: string) => + ({ + type, + renderer, + } as unknown as ChartKitPlugin); + +// Order test is important because settings module is singleton and we can't delete plugins +describe('libs/settings update plugins', () => { + it('Update plugins when it is empty', () => { + settings.set({ + plugins: [getMockedPlugin('highcharts', 'initial'), getMockedPlugin('d3', 'initial')], + }); + + expect(settings.get('plugins')).toEqual([ + { + type: 'highcharts', + renderer: 'initial', + }, + { + type: 'd3', + renderer: 'initial', + }, + ]); + }); + + it('Update existing plugin d3', () => { + const initial = settings.get('plugins'); + + expect(initial).toEqual([ + { + type: 'highcharts', + renderer: 'initial', + }, + { + type: 'd3', + renderer: 'initial', + }, + ]); + + settings.set({ + plugins: [getMockedPlugin('d3', 'update')], + }); + + const result = settings.get('plugins'); + + expect(result).toEqual([ + { + type: 'highcharts', + renderer: 'initial', + }, + { + type: 'd3', + renderer: 'update', + }, + ]); + }); + + it('Add new plugin', () => { + settings.set({ + plugins: [getMockedPlugin('yagr', 'update')], + }); + + const result = settings.get('plugins'); + + expect(result).toEqual([ + { + type: 'highcharts', + renderer: 'initial', + }, + { + type: 'd3', + renderer: 'update', + }, + { + type: 'yagr', + renderer: 'update', + }, + ]); + }); + + beforeAll(resetSettings); + afterEach(resetSettings); +}); diff --git a/src/libs/settings/mergeSettingStrategy.ts b/src/libs/settings/mergeSettingStrategy.ts new file mode 100644 index 00000000..7a6637ff --- /dev/null +++ b/src/libs/settings/mergeSettingStrategy.ts @@ -0,0 +1,41 @@ +import isObject from 'lodash/isObject'; +import mergeWith from 'lodash/mergeWith'; + +import {ChartKitPlugin} from 'src/types'; + +// @ts-ignore +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 a8f90ca3..6db83459 100644 --- a/src/libs/settings/settings.ts +++ b/src/libs/settings/settings.ts @@ -1,9 +1,10 @@ import get from 'lodash/get'; -import merge from 'lodash/merge'; +import mergeWith from 'lodash/mergeWith'; import {configure} from '@gravity-ui/uikit'; import {i18nFactory} from '../../i18n'; import type {ChartKitPlugin, ChartKitLang, ChartKitHolidays} from '../../types'; import {EventEmitter} from './eventEmitter'; +import {mergeSettingStrategy} from './mergeSettingStrategy'; interface Settings { plugins: ChartKitPlugin[]; @@ -52,7 +53,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');