diff --git a/docs/latest/extensions/index.md b/docs/latest/extensions/index.md index 2a03023ae..d5052873f 100644 --- a/docs/latest/extensions/index.md +++ b/docs/latest/extensions/index.md @@ -193,7 +193,8 @@ today, create a GitHub issue! The `ExtensionManager` is a class made available to us via the `@ohif/core` project (platform/core). Our application instantiates a single instance of it, -and provides a `ServicesManager` and `CommandsManager`. +and provides a `ServicesManager` and `CommandsManager` along with the application's +configuration through the appConfig key (optional). ```js const commandsManager = new CommandsManager(); @@ -201,6 +202,7 @@ const servicesManager = new ServicesManager(); const extensionManager = new ExtensionManager({ commandsManager, servicesManager, + appConfig }); ``` @@ -210,8 +212,8 @@ The `ExtensionManager` only has a few public members: - `registerExtensions` - Registers an array of extensions - `modules` - An object containing registered extensions by `MODULE_TYPE` -During registration, lifecycle hooks and modules have access to -`ExtensionManager`'s `ServicesManager` and `CommandsManager`. +During registration, lifecycle hooks and modules have access to the extension's config, +the application's config and `ExtensionManager`'s `ServicesManager` and `CommandsManager` instances. Our `@ohif/viewer` uses the `modules` member to access registered extensions at appropriate places in our application. diff --git a/extensions/_example/src/index.js b/extensions/_example/src/index.js index 4827f8f94..bafd2ae32 100644 --- a/extensions/_example/src/index.js +++ b/extensions/_example/src/index.js @@ -14,6 +14,7 @@ export default { preRegistration({ servicesManager = {}, commandsManager = {}, + appConfig = {}, configuration = {}, }) {}, diff --git a/platform/core/src/extensions/ExtensionManager.js b/platform/core/src/extensions/ExtensionManager.js index 7b9cba74a..7bb5a30b2 100644 --- a/platform/core/src/extensions/ExtensionManager.js +++ b/platform/core/src/extensions/ExtensionManager.js @@ -2,13 +2,14 @@ import MODULE_TYPES from './MODULE_TYPES.js'; import log from './../log.js'; export default class ExtensionManager { - constructor({ commandsManager, servicesManager }) { + constructor({ commandsManager, servicesManager, appConfig = {} }) { this.modules = {}; this.registeredExtensionIds = []; this.moduleTypeNames = Object.values(MODULE_TYPES); // this._commandsManager = commandsManager; this._servicesManager = servicesManager; + this._appConfig = appConfig; this.moduleTypeNames.forEach(moduleType => { this.modules[moduleType] = []; @@ -70,6 +71,7 @@ export default class ExtensionManager { extension.preRegistration({ servicesManager: this._servicesManager, commandsManager: this._commandsManager, + appConfig: this._appConfig, configuration, }); } @@ -79,7 +81,8 @@ export default class ExtensionManager { const extensionModule = this._getExtensionModule( moduleType, extension, - extensionId + extensionId, + configuration ); if (extensionModule) { @@ -102,7 +105,7 @@ export default class ExtensionManager { * @param {Object} extension * @param {string} extensionId - Used for logging warnings */ - _getExtensionModule(moduleType, extension, extensionId) { + _getExtensionModule(moduleType, extension, extensionId, configuration) { const getModuleFnName = 'get' + _capitalizeFirstCharacter(moduleType); const getModuleFn = extension[getModuleFnName]; @@ -114,6 +117,8 @@ export default class ExtensionManager { const extensionModule = getModuleFn({ servicesManager: this._servicesManager, commandsManager: this._commandsManager, + appConfig: this._appConfig, + configuration, }); if (!extensionModule) { diff --git a/platform/core/src/extensions/ExtensionManager.test.js b/platform/core/src/extensions/ExtensionManager.test.js index 1a506b0c0..5ed3fad8d 100644 --- a/platform/core/src/extensions/ExtensionManager.test.js +++ b/platform/core/src/extensions/ExtensionManager.test.js @@ -6,7 +6,7 @@ import log from './../log.js'; jest.mock('./../log.js'); describe('ExtensionManager.js', () => { - let extensionManager, commandsManager; + let extensionManager, commandsManager, servicesManager, appConfig; beforeEach(() => { commandsManager = { @@ -14,7 +14,17 @@ describe('ExtensionManager.js', () => { getContext: jest.fn(), registerCommand: jest.fn(), }; - extensionManager = new ExtensionManager({ commandsManager }); + servicesManager = { + registerService: jest.fn(), + }; + appConfig = { + testing: true, + }; + extensionManager = new ExtensionManager({ + servicesManager, + commandsManager, + appConfig, + }); log.warn.mockClear(); jest.clearAllMocks(); }); @@ -51,7 +61,7 @@ describe('ExtensionManager.js', () => { extensionManager.registerExtensions(fakeExtensions); // Assert - expect(extensionManager.registerExtension.mock.calls[1]).toContain( + expect(extensionManager.registerExtension.mock.calls[1][1]).toEqual( fakeConfiguration ); }); @@ -67,19 +77,19 @@ describe('ExtensionManager.js', () => { expect(fakeExtension.preRegistration.mock.calls.length).toBe(1); }); - it('calls preRegistration() passing configuration along with servicesManager and commandsManager instances for extension', () => { - const configuration = { config: 'Some configuration' }; - extensionManager._servicesManager = { services: { TestService: {} } }; + it('calls preRegistration() passing dependencies and extension configuration to extension', () => { + const extensionConfiguration = { config: 'Some configuration' }; // SUT - const fakeExtension = { one: '1', preRegistration: jest.fn() }; - extensionManager.registerExtension(fakeExtension, configuration); + const extension = { one: '1', preRegistration: jest.fn() }; + extensionManager.registerExtension(extension, extensionConfiguration); // Assert - expect(fakeExtension.preRegistration.mock.calls[0][0]).toEqual({ - servicesManager: extensionManager._servicesManager, - commandsManager: extensionManager._commandsManager, - configuration, + expect(extension.preRegistration.mock.calls[0][0]).toEqual({ + servicesManager, + commandsManager, + appConfig, + configuration: extensionConfiguration, }); }); @@ -153,8 +163,8 @@ describe('ExtensionManager.js', () => { ); }); - it('successfully passes a servicesManager and commandsManager instances to each module', () => { - extensionManager._servicesManager = { services: { TestService: {} } }; + it('successfully passes dependencies to each module along with extension configuration', () => { + const extensionConfiguration = { testing: true }; const extension = { id: 'hello-world', @@ -165,11 +175,17 @@ describe('ExtensionManager.js', () => { getCommandsModule: jest.fn(), }; - extensionManager.registerExtension(extension); + extensionManager.registerExtension(extension, extensionConfiguration); - expect(extension.getViewportModule.mock.calls[0][0]).toEqual({ - servicesManager: extensionManager._servicesManager, - commandsManager: extensionManager._commandsManager, + Object.keys(extension).forEach(module => { + if (typeof extension[module] === 'function') { + expect(extension[module].mock.calls[0][0]).toEqual({ + servicesManager, + commandsManager, + appConfig, + configuration: extensionConfiguration, + }); + } }); }); diff --git a/platform/core/src/services/ServicesManager.js b/platform/core/src/services/ServicesManager.js index c64b74c8f..db5dec800 100644 --- a/platform/core/src/services/ServicesManager.js +++ b/platform/core/src/services/ServicesManager.js @@ -33,7 +33,9 @@ export default class ServicesManager { } if (service.create) { - this.services[service.name] = service.create({ configuration }); + this.services[service.name] = service.create({ + configuration, + }); } else { log.warn(`Service create factory function not defined. Exiting early.`); return; diff --git a/platform/core/src/services/ServicesManager.test.js b/platform/core/src/services/ServicesManager.test.js index c8b5a3f0d..e1c35d120 100644 --- a/platform/core/src/services/ServicesManager.test.js +++ b/platform/core/src/services/ServicesManager.test.js @@ -33,7 +33,7 @@ describe('ServicesManager.js', () => { [{ name: 'UIModalTestService', create: jest.fn() }, fakeConfiguration], ]); - expect(servicesManager.registerService.mock.calls[1]).toContain( + expect(servicesManager.registerService.mock.calls[1][1]).toEqual( fakeConfiguration ); }); @@ -85,7 +85,7 @@ describe('ServicesManager.js', () => { expect(log.warn.mock.calls.length).toBe(1); }); - it('pass configuration to service create factory function', () => { + it('pass dependencies and configuration to service create factory function', () => { const configuration = { config: 'Some configuration' }; servicesManager.registerService(fakeService, configuration); diff --git a/platform/viewer/src/App.js b/platform/viewer/src/App.js index 801e6df21..fc07a8566 100644 --- a/platform/viewer/src/App.js +++ b/platform/viewer/src/App.js @@ -64,10 +64,7 @@ const commandsManagerConfig = { const commandsManager = new CommandsManager(commandsManagerConfig); const hotkeysManager = new HotkeysManager(commandsManager); const servicesManager = new ServicesManager(); -const extensionManager = new ExtensionManager({ - commandsManager, - servicesManager, -}); +let extensionManager; /** ~~~~~~~~~~~~~ End Application Setup */ // TODO[react] Use a provider when the whole tree is React @@ -128,7 +125,8 @@ class App extends Component { _initServices([UINotificationService, UIModalService, UIDialogService]); _initExtensions( [...defaultExtensions, ...extensions], - cornerstoneExtensionConfig + cornerstoneExtensionConfig, + this._appConfig ); /* @@ -241,7 +239,13 @@ function _initServices(services) { /** * @param */ -function _initExtensions(extensions, cornerstoneExtensionConfig) { +function _initExtensions(extensions, cornerstoneExtensionConfig, appConfig) { + extensionManager = new ExtensionManager({ + commandsManager, + servicesManager, + appConfig, + }); + const requiredExtensions = [ GenericViewerCommands, [OHIFCornerstoneExtension, cornerstoneExtensionConfig],