From 55dcfa1f6994a7036e7e594efb23673382a41915 Mon Sep 17 00:00:00 2001 From: Bill Wallace Date: Wed, 12 Jun 2024 11:20:27 -0400 Subject: [PATCH] feat: Add customization merge, append or replace functionality (#3871) --- extensions/cornerstone/package.json | 2 +- .../default/src/getCustomizationModule.tsx | 2 + extensions/measurement-tracking/package.json | 2 +- platform/app/public/config/e2e.js | 7 ++ platform/core/package.json | 3 +- .../CustomizationService.ts | 67 +++++++++++++++---- yarn.lock | 7 +- 7 files changed, 73 insertions(+), 17 deletions(-) diff --git a/extensions/cornerstone/package.json b/extensions/cornerstone/package.json index 02905db27..37c89085f 100644 --- a/extensions/cornerstone/package.json +++ b/extensions/cornerstone/package.json @@ -62,7 +62,7 @@ "@icr/polyseg-wasm": "^0.4.0", "@kitware/vtk.js": "30.4.1", "html2canvas": "^1.4.1", - "lodash.debounce": "4.0.8", + "lodash.debounce": "^4.0.8", "lodash.merge": "^4.6.2", "shader-loader": "^1.3.1", "worker-loader": "^3.0.8" diff --git a/extensions/default/src/getCustomizationModule.tsx b/extensions/default/src/getCustomizationModule.tsx index caf8d6335..d004d88f1 100644 --- a/extensions/default/src/getCustomizationModule.tsx +++ b/extensions/default/src/getCustomizationModule.tsx @@ -18,6 +18,7 @@ export default function getCustomizationModule({ servicesManager, extensionManag return [ { name: 'helloPage', + merge: 'Append', value: { id: 'customRoutes', routes: [ @@ -32,6 +33,7 @@ export default function getCustomizationModule({ servicesManager, extensionManag // Example customization to list a set of datasources { name: 'datasources', + merge: 'Append', value: { id: 'customRoutes', routes: [ diff --git a/extensions/measurement-tracking/package.json b/extensions/measurement-tracking/package.json index 51c4103a0..66fd04945 100644 --- a/extensions/measurement-tracking/package.json +++ b/extensions/measurement-tracking/package.json @@ -39,7 +39,7 @@ "@ohif/ui": "3.9.0-beta.40", "classnames": "^2.3.2", "dcmjs": "^0.29.12", - "lodash.debounce": "^4.17.21", + "lodash.debounce": "^4.0.8", "prop-types": "^15.6.2", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/platform/app/public/config/e2e.js b/platform/app/public/config/e2e.js index 2eb52cbb5..018c61044 100644 --- a/platform/app/public/config/e2e.js +++ b/platform/app/public/config/e2e.js @@ -10,6 +10,13 @@ window.config = { showCPUFallbackMessage: false, strictZSpacingForVolumeViewport: true, // filterQueryParam: false, + + // Add some customizations to the default e2e datasource + customizationService: [ + '@ohif/extension-default.customizationModule.datasources', + '@ohif/extension-default.customizationModule.helloPage', + ], + defaultDataSourceName: 'e2e', investigationalUseDialog: { option: 'never', diff --git a/platform/core/package.json b/platform/core/package.json index de98a129f..0ed5d21e3 100644 --- a/platform/core/package.json +++ b/platform/core/package.json @@ -49,7 +49,8 @@ "gl-matrix": "^3.4.3", "isomorphic-base64": "^1.0.2", "lodash.clonedeep": "^4.5.0", - "lodash.merge": "^4.6.1", + "lodash.merge": "^4.6.2", + "lodash.mergewith": "^4.6.2", "moment": "^2.24.0", "object-hash": "2.1.1", "query-string": "^6.14.0", diff --git a/platform/core/src/services/CustomizationService/CustomizationService.ts b/platform/core/src/services/CustomizationService/CustomizationService.ts index 0d97a3307..cd1085233 100644 --- a/platform/core/src/services/CustomizationService/CustomizationService.ts +++ b/platform/core/src/services/CustomizationService/CustomizationService.ts @@ -1,6 +1,6 @@ -import merge from 'lodash.merge'; +import mergeWith from 'lodash.mergewith'; import { PubSubService } from '../_shared/pubSubServiceInterface'; -import { Customization, NestedStrings, Obj } from './types'; +import { Customization, NestedStrings } from './types'; import { CommandsManager } from '../../classes'; const EVENTS = { @@ -28,6 +28,21 @@ const flattenNestedStrings = ( return ret; }; +export enum MergeEnum { + /** + * Append values in the nested arrays + */ + Append = 'Append', + /** + * Merge values, replacing arrays + */ + Merge = 'Merge', + /** + * Replace the given value - this is the default + */ + Replace = 'Replace', +} + /** * The CustomizationService allows for retrieving of custom components * and configuration for mode and global values. @@ -93,7 +108,7 @@ export default class CustomizationService extends PubSubService { }); } - findExtensionValue(value: string): Obj | void { + findExtensionValue(value: string) { const entry = this.extensionManager.getModuleEntry(value); return entry; } @@ -107,10 +122,15 @@ export default class CustomizationService extends PubSubService { return this.modeCustomizations; } - public setModeCustomization(customizationId: string, customization: Customization): void { - this.modeCustomizations[customizationId] = merge( - this.modeCustomizations[customizationId] || {}, - customization + public setModeCustomization( + customizationId: string, + customization: Customization, + merge = MergeEnum.Merge + ): void { + this.modeCustomizations[customizationId] = this.mergeValue( + this.modeCustomizations[customizationId], + customization, + merge ); this._broadcastEvent(this.EVENTS.CUSTOMIZATION_MODIFIED, { buttons: this.modeCustomizations, @@ -209,8 +229,16 @@ export default class CustomizationService extends PubSubService { return this.transform(this.globalCustomizations[id] ?? defaultValue); } - setGlobalCustomization(id: string, value: Customization): void { - this.globalCustomizations[id] = value; + private mergeValue(oldValue, newValue, mergeType = MergeEnum.Replace) { + if (mergeType === MergeEnum.Replace) { + return newValue; + } + + return mergeWith(oldValue || {}, newValue, mergeCustomizer.bind(null, mergeType)); + } + + public setGlobalCustomization(id: string, value: Customization, merge = MergeEnum.Replace): void { + this.globalCustomizations[id] = this.mergeValue(this.globalCustomizations[id], value, merge); this._broadcastGlobalCustomizationModified(); } @@ -235,7 +263,7 @@ export default class CustomizationService extends PubSubService { * A single reference is either an string to be loaded from a module, * or a customization itself. */ - addReference(value?: Obj | string, isGlobal = true, id?: string): void { + addReference(value?, isGlobal = true, id?: string, merge?: MergeEnum): void { if (!value) { return; } @@ -243,12 +271,16 @@ export default class CustomizationService extends PubSubService { const extensionValue = this.findExtensionValue(value); // The child of a reference is only a set of references when an array, // so call the addReference direct. It could be a secondary reference perhaps - this.addReference(extensionValue.value, isGlobal, extensionValue.name); + this.addReference(extensionValue.value, isGlobal, extensionValue.name, extensionValue.merge); } else if (Array.isArray(value)) { this.addReferences(value, isGlobal); } else { const useId = value.id || id; - this[isGlobal ? 'setGlobalCustomization' : 'setModeCustomization'](useId as string, value); + this[isGlobal ? 'setGlobalCustomization' : 'setModeCustomization']( + useId as string, + value, + merge + ); } } @@ -257,7 +289,7 @@ export default class CustomizationService extends PubSubService { * or as an object whose key is the reference id, and the value is the string * or customization. */ - addReferences(references?: Obj | Obj[], isGlobal = true): void { + addReferences(references?, isGlobal = true): void { if (!references) { return; } @@ -273,3 +305,12 @@ export default class CustomizationService extends PubSubService { } } } + +/** + * Custom merging function, to handle merging arrays + */ +function mergeCustomizer(merge: MergeEnum, obj, src) { + if (merge === MergeEnum.Append && Array.isArray(obj)) { + return obj.concat(src); + } +} diff --git a/yarn.lock b/yarn.lock index 6ccde6ec8..96d325894 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15122,11 +15122,16 @@ lodash.memoize@^4.1.2: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== -lodash.merge@^4.6.1, lodash.merge@^4.6.2: +lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.mergewith@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" + integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== + lodash.once@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"