diff --git a/package-lock.json b/package-lock.json index 2eb3569e08..44731d0327 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10472,6 +10472,16 @@ "@types/lodash": "*" } }, + "node_modules/@types/lodash.mergewith": { + "version": "4.6.9", + "resolved": "https://registry.npmjs.org/@types/lodash.mergewith/-/lodash.mergewith-4.6.9.tgz", + "integrity": "sha512-fgkoCAOF47K7sxrQ7Mlud2TH023itugZs2bUg8h/KzT+BnZNrR2jAOmaokbLunHNnobXVWOezAeNn/lZqwxkcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/lodash.throttle": { "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/lodash.throttle/-/lodash.throttle-4.1.9.tgz", @@ -23061,6 +23071,12 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "license": "MIT" + }, "node_modules/lodash.throttle": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", @@ -33853,9 +33869,13 @@ "@deephaven/log": "file:../log", "@deephaven/plugin": "file:../plugin", "fast-deep-equal": "^3.1.3", + "lodash.mergewith": "^4.6.2", "proxy-memoize": "^3.0.0", "redux-thunk": "2.4.1" }, + "devDependencies": { + "@types/lodash.mergewith": "^4.6.9" + }, "engines": { "node": ">=16" }, diff --git a/packages/redux/package.json b/packages/redux/package.json index 1a1641bcf7..b88e127249 100644 --- a/packages/redux/package.json +++ b/packages/redux/package.json @@ -27,6 +27,7 @@ "@deephaven/log": "file:../log", "@deephaven/plugin": "file:../plugin", "fast-deep-equal": "^3.1.3", + "lodash.mergewith": "^4.6.2", "proxy-memoize": "^3.0.0", "redux-thunk": "2.4.1" }, @@ -39,5 +40,8 @@ "sideEffects": false, "publishConfig": { "access": "public" + }, + "devDependencies": { + "@types/lodash.mergewith": "^4.6.9" } } diff --git a/packages/redux/src/selectors.ts b/packages/redux/src/selectors.ts index df61392fb9..b3f077fc47 100644 --- a/packages/redux/src/selectors.ts +++ b/packages/redux/src/selectors.ts @@ -1,6 +1,7 @@ import type { UndoPartial } from '@deephaven/utils'; import { memoize } from 'proxy-memoize'; -import type { RootState, WorkspaceSettings } from './store'; +import mergeWith from 'lodash.mergewith'; +import type { RootState } from './store'; const EMPTY_OBJECT = Object.freeze({}); @@ -61,17 +62,22 @@ export const getSettings = memoize( store: State ): UndoPartial => { const customizedSettings = getWorkspace(store)?.data.settings ?? {}; - - const settings = { ...getDefaultWorkspaceSettings(store) }; - const keys = Object.keys(customizedSettings) as (keyof WorkspaceSettings)[]; - for (let i = 0; i < keys.length; i += 1) { - const key = keys[i]; - if (customizedSettings[key] !== undefined) { - // @ts-expect-error assign non-undefined customized settings to settings - settings[key] = customizedSettings[key]; + const defaultSettings = getDefaultWorkspaceSettings(store); + + // Deep merge settings but replace arrays instead of merging them + const newSettings = mergeWith( + {}, + defaultSettings, + customizedSettings, + (objValue: unknown, srcValue: unknown) => { + if (Array.isArray(objValue) && Array.isArray(srcValue)) { + return srcValue; + } + return undefined; } - } - return settings as UndoPartial; + ) as UndoPartial; + + return newSettings; } );