diff --git a/extensions/_example/src/index.js b/extensions/_example/src/index.js
index 6d1e82bac..c061a44af 100644
--- a/extensions/_example/src/index.js
+++ b/extensions/_example/src/index.js
@@ -11,7 +11,10 @@ export default {
* LIFECYCLE HOOKS
*/
- preRegistration({ serviceManager, configuration: extensionConfiguration }) {},
+ preRegistration({
+ servicesManager,
+ configuration: extensionConfiguration,
+ }) {},
/**
* MODULE GETTERS
diff --git a/extensions/cornerstone/CHANGELOG.md b/extensions/cornerstone/CHANGELOG.md
index 2cd27731b..a6a6f7122 100644
--- a/extensions/cornerstone/CHANGELOG.md
+++ b/extensions/cornerstone/CHANGELOG.md
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+## [1.5.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.5.0...@ohif/extension-cornerstone@1.5.1) (2019-11-15)
+
+**Note:** Version bump only for package @ohif/extension-cornerstone
+
+
+
+
+
# [1.5.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@1.4.1...@ohif/extension-cornerstone@1.5.0) (2019-11-13)
diff --git a/extensions/cornerstone/package.json b/extensions/cornerstone/package.json
index 574d23e3c..917cd9cad 100644
--- a/extensions/cornerstone/package.json
+++ b/extensions/cornerstone/package.json
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone",
- "version": "1.5.0",
+ "version": "1.5.1",
"description": "OHIF extension for Cornerstone",
"author": "OHIF",
"license": "MIT",
diff --git a/extensions/cornerstone/src/index.js b/extensions/cornerstone/src/index.js
index 5451f4041..6470382c9 100644
--- a/extensions/cornerstone/src/index.js
+++ b/extensions/cornerstone/src/index.js
@@ -24,8 +24,8 @@ export default {
* @param {object} [configuration={}]
* @param {object|array} [configuration.csToolsConfig] - Passed directly to `initCornerstoneTools`
*/
- preRegistration({ serviceManager, configuration = {} }) {
- init({ serviceManager, configuration });
+ preRegistration({ servicesManager, configuration = {} }) {
+ init({ servicesManager, configuration });
},
getViewportModule() {
return OHIFCornerstoneViewport;
diff --git a/extensions/cornerstone/src/init.js b/extensions/cornerstone/src/init.js
index 0795e2034..aee850564 100644
--- a/extensions/cornerstone/src/init.js
+++ b/extensions/cornerstone/src/init.js
@@ -28,7 +28,7 @@ cornerstone.metaData.addProvider(fallbackMetaDataProvider, -1);
* @param {object} configuration
* @param {Object|Array} configuration.csToolsConfig
*/
-export default function init({ serviceManager, configuration = {} }) {
+export default function init({ servicesManager, configuration = {} }) {
const { csToolsConfig } = configuration;
const { StackManager } = OHIF.utils;
const metadataProvider = new OHIF.cornerstone.MetadataProvider();
diff --git a/extensions/vtk/CHANGELOG.md b/extensions/vtk/CHANGELOG.md
index 9d5f63aae..9a9acf56f 100644
--- a/extensions/vtk/CHANGELOG.md
+++ b/extensions/vtk/CHANGELOG.md
@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+## [0.53.8](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.53.7...@ohif/extension-vtk@0.53.8) (2019-11-15)
+
+**Note:** Version bump only for package @ohif/extension-vtk
+
+
+
+
+
+## [0.53.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.53.6...@ohif/extension-vtk@0.53.7) (2019-11-15)
+
+**Note:** Version bump only for package @ohif/extension-vtk
+
+
+
+
+
## [0.53.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.53.5...@ohif/extension-vtk@0.53.6) (2019-11-14)
**Note:** Version bump only for package @ohif/extension-vtk
diff --git a/extensions/vtk/package.json b/extensions/vtk/package.json
index 8df509ec4..edc9f72be 100644
--- a/extensions/vtk/package.json
+++ b/extensions/vtk/package.json
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-vtk",
- "version": "0.53.6",
+ "version": "0.53.8",
"description": "OHIF extension for VTK.js",
"author": "OHIF",
"license": "MIT",
@@ -52,8 +52,8 @@
"react-vtkjs-viewport": "^0.3.9"
},
"devDependencies": {
- "@ohif/core": "^1.9.0",
- "@ohif/ui": "^0.62.1",
+ "@ohif/core": "^1.10.0",
+ "@ohif/ui": "^0.62.3",
"cornerstone-tools": "^4.0.9",
"cornerstone-wado-image-loader": "^3.0.0",
"dcmjs": "^0.6.1",
diff --git a/platform/core/CHANGELOG.md b/platform/core/CHANGELOG.md
index 4b491a779..8805dc754 100644
--- a/platform/core/CHANGELOG.md
+++ b/platform/core/CHANGELOG.md
@@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [1.10.0](https://github.com/OHIF/Viewers/compare/@ohif/core@1.9.1...@ohif/core@1.10.0) (2019-11-15)
+
+
+### Features
+
+* Inject into Extension Modules / improve tests ([f63d8a7](https://github.com/OHIF/Viewers/commit/f63d8a73d867ad9dfd8ee0cad74edce180eb34f0))
+
+
+
+
+
+## [1.9.1](https://github.com/OHIF/Viewers/compare/@ohif/core@1.9.0...@ohif/core@1.9.1) (2019-11-15)
+
+**Note:** Version bump only for package @ohif/core
+
+
+
+
+
# [1.9.0](https://github.com/OHIF/Viewers/compare/@ohif/core@1.8.0...@ohif/core@1.9.0) (2019-11-13)
diff --git a/platform/core/package.json b/platform/core/package.json
index 2723604f6..4f9720456 100644
--- a/platform/core/package.json
+++ b/platform/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@ohif/core",
- "version": "1.9.0",
+ "version": "1.10.0",
"description": "Generic business logic for web-based medical imaging applications",
"author": "OHIF Core Team",
"license": "MIT",
diff --git a/platform/core/src/extensions/ExtensionManager.js b/platform/core/src/extensions/ExtensionManager.js
index ddb702485..e5adbb85f 100644
--- a/platform/core/src/extensions/ExtensionManager.js
+++ b/platform/core/src/extensions/ExtensionManager.js
@@ -68,7 +68,7 @@ export default class ExtensionManager {
// preRegistrationHook
if (extension.preRegistration) {
extension.preRegistration({
- serviceManager: this._servicesManager,
+ servicesManager: this._servicesManager,
configuration,
});
}
@@ -110,7 +110,9 @@ export default class ExtensionManager {
}
try {
- const extensionModule = getModuleFn();
+ const extensionModule = getModuleFn({
+ servicesManager: this._servicesManager,
+ });
if (!extensionModule) {
log.warn(
diff --git a/platform/core/src/extensions/ExtensionManager.test.js b/platform/core/src/extensions/ExtensionManager.test.js
index cfe892ef0..37b396e52 100644
--- a/platform/core/src/extensions/ExtensionManager.test.js
+++ b/platform/core/src/extensions/ExtensionManager.test.js
@@ -40,6 +40,30 @@ describe('ExtensionManager.js', () => {
});
describe('registerExtension()', () => {
+ it('calls preRegistration() for extension', () => {
+ // SUT
+ const fakeExtension = { one: '1', preRegistration: jest.fn() };
+ extensionManager.registerExtension(fakeExtension);
+
+ // Assert
+ expect(fakeExtension.preRegistration.mock.calls.length).toBe(1);
+ });
+
+ it('calls preRegistration() passing configuration and servicesManager instance for extension', () => {
+ const configuration = { config: 'Some configuration' };
+ extensionManager._servicesManager = { services: { TestService: {} } };
+
+ // SUT
+ const fakeExtension = { one: '1', preRegistration: jest.fn() };
+ extensionManager.registerExtension(fakeExtension, configuration);
+
+ // Assert
+ expect(fakeExtension.preRegistration.mock.calls[0][0]).toEqual({
+ servicesManager: extensionManager._servicesManager,
+ configuration,
+ });
+ });
+
it('logs a warning if the extension is null or undefined', () => {
const undefinedExtension = undefined;
const nullExtension = null;
@@ -110,6 +134,25 @@ describe('ExtensionManager.js', () => {
);
});
+ it('successfully passes a servicesManager instance to each module', () => {
+ extensionManager._servicesManager = { services: { TestService: {} } };
+
+ const extension = {
+ id: 'hello-world',
+ getViewportModule: jest.fn(),
+ getSopClassHandlerModule: jest.fn(),
+ getPanelModule: jest.fn(),
+ getToolbarModule: jest.fn(),
+ getCommandsModule: jest.fn(),
+ };
+
+ extensionManager.registerExtension(extension);
+
+ expect(extension.getViewportModule.mock.calls[0][0]).toEqual({
+ servicesManager: extensionManager._servicesManager,
+ });
+ });
+
it('successfully registers a module for each module type', () => {
const extension = {
id: 'hello-world',
diff --git a/platform/core/src/index.js b/platform/core/src/index.js
index 6cec02db8..cb482e505 100644
--- a/platform/core/src/index.js
+++ b/platform/core/src/index.js
@@ -19,7 +19,7 @@ import ui from './ui';
import user from './user.js';
import utils from './utils/';
-import { createUiNotificationService } from './services';
+import { createUINotificationService, createUIModalService } from './services';
const OHIF = {
MODULE_TYPES,
@@ -46,7 +46,8 @@ const OHIF = {
measurements,
hangingProtocols,
//
- createUiNotificationService,
+ createUINotificationService,
+ createUIModalService,
};
export {
@@ -73,7 +74,8 @@ export {
measurements,
hangingProtocols,
//
- createUiNotificationService,
+ createUINotificationService,
+ createUIModalService,
};
export { OHIF };
diff --git a/platform/core/src/index.test.js b/platform/core/src/index.test.js
index a017a8a39..b06073e12 100644
--- a/platform/core/src/index.test.js
+++ b/platform/core/src/index.test.js
@@ -10,7 +10,8 @@ describe('Top level exports', () => {
'HotkeysManager',
'ServicesManager',
//
- 'createUiNotificationService',
+ 'createUINotificationService',
+ 'createUIModalService',
//
'utils',
'studies',
diff --git a/platform/core/src/services/ServicesManager.js b/platform/core/src/services/ServicesManager.js
index 0e38e5695..4b71a580a 100644
--- a/platform/core/src/services/ServicesManager.js
+++ b/platform/core/src/services/ServicesManager.js
@@ -1,9 +1,49 @@
+import log from './../log.js';
+
export default class ServicesManager {
constructor() {
this.services = {};
+ this.registeredServiceNames = [];
}
- register(service) {
+ /**
+ *
+ * @param {Object} service
+ */
+ registerService(service) {
+ if (!service) {
+ log.warn(
+ 'Attempting to register a null/undefined service. Exiting early.'
+ );
+ return;
+ }
+
+ let serviceName = service.name;
+
+ if (!serviceName) {
+ log.warn(`Service name not set. Exiting early.`);
+ return;
+ }
+
+ if (this.registeredServiceNames.includes(serviceName)) {
+ log.warn(
+ `Extension name ${serviceName} has already been registered. Exiting before duplicating services.`
+ );
+ return;
+ }
+
this.services[service.name] = service;
+
+ // Track service registration
+ this.registeredServiceNames.push(serviceName);
+ }
+
+ /**
+ * An array of services.
+ *
+ * @param {Object[]} services - Array of services
+ */
+ registerServices(services) {
+ services.forEach(service => this.registerService(service));
}
}
diff --git a/platform/core/src/services/ServicesManager.test.js b/platform/core/src/services/ServicesManager.test.js
new file mode 100644
index 000000000..71ec25432
--- /dev/null
+++ b/platform/core/src/services/ServicesManager.test.js
@@ -0,0 +1,70 @@
+import ServicesManager from './ServicesManager.js';
+import log from '../log.js';
+
+jest.mock('./../log.js');
+
+describe('ServicesManager.js', () => {
+ let servicesManager;
+
+ beforeEach(() => {
+ servicesManager = new ServicesManager();
+ log.warn.mockClear();
+ jest.clearAllMocks();
+ });
+
+ describe('registerServices()', () => {
+ it('calls registerService() for each service', () => {
+ servicesManager.registerService = jest.fn();
+
+ const fakeServices = [
+ { name: 'UINotificationTestService', hide: jest.fn() },
+ { name: 'UIModalTestService', hide: jest.fn() },
+ ];
+
+ servicesManager.registerServices(fakeServices);
+
+ expect(servicesManager.registerService.mock.calls.length).toBe(2);
+ });
+ });
+
+ describe('registerService()', () => {
+ it('logs a warning if the service is null or undefined', () => {
+ const undefinedService = undefined;
+ const nullService = null;
+
+ servicesManager.registerService(undefinedService);
+ servicesManager.registerService(nullService);
+
+ expect(log.warn.mock.calls.length).toBe(2);
+ });
+
+ it('logs a warning if the service does not have a name', () => {
+ const serviceWithEmptyName = { name: '', hide: jest.fn() };
+ const serviceWithoutName = { hide: jest.fn() };
+
+ servicesManager.registerService(serviceWithEmptyName);
+ servicesManager.registerService(serviceWithoutName);
+
+ expect(log.warn.mock.calls.length).toBe(2);
+ });
+
+ it('tracks which services have been registered', () => {
+ const service = {
+ name: 'UINotificationService',
+ };
+
+ servicesManager.registerService(service);
+
+ expect(servicesManager.registeredServiceNames).toContain(service.name);
+ });
+
+ it('logs a warning if the service has an name that has already been registered', () => {
+ const service = { name: 'UINotificationService' };
+
+ servicesManager.registerService(service);
+ servicesManager.registerService(service);
+
+ expect(log.warn.mock.calls.length).toBe(1);
+ });
+ });
+});
diff --git a/platform/core/src/services/UIModalService/index.js b/platform/core/src/services/UIModalService/index.js
new file mode 100644
index 000000000..b93bccdb8
--- /dev/null
+++ b/platform/core/src/services/UIModalService/index.js
@@ -0,0 +1,88 @@
+/**
+ * A UI Element
+ *
+ * @typedef {ReactElement|HTMLElement} Modal
+ */
+
+/**
+ * UI Modal
+ *
+ * @typedef {Object} ModalProps
+ * @property {string} [header=null] -
+ * @property {string} [footer=null] -
+ * @property {string} [backdrop=false] -
+ * @property {string} [keyboard=false] -
+ * @property {number} [show=true] -
+ * @property {string} [closeButton=true] -
+ * @property {string} [title=null] - 'Modal Title'
+ * @property {boolean} [customClassName=null] - '.ModalClass'
+ */
+
+const uiModalServicePublicAPI = {
+ name: 'UIModalService',
+ hide,
+ show,
+ setServiceImplementation,
+};
+
+const uiModalServiceImplementation = {
+ _hide: () => console.warn('hide() NOT IMPLEMENTED'),
+ _show: () => console.warn('show() NOT IMPLEMENTED'),
+};
+
+function createUIModalService() {
+ return uiModalServicePublicAPI;
+}
+
+/**
+ * Show a new UI modal;
+ *
+ * @param {Modal} component React component
+ * @param {ModalProps} props { header, footer, backdrop, keyboard, show, closeButton, title, customClassName }
+ */
+function show(
+ component,
+ props = {
+ header: null,
+ footer: null,
+ backdrop: false,
+ keyboard: false,
+ show: true,
+ closeButton: true,
+ title: null,
+ customClassName: null,
+ }
+) {
+ return uiModalServiceImplementation._show(component, props);
+}
+
+/**
+ * Hides/dismisses the modal, if currently shown
+ *
+ * @returns void
+ */
+function hide() {
+ return uiModalServiceImplementation._hide();
+}
+
+/**
+ *
+ *
+ * @param {*} {
+ * hide: hideImplementation,
+ * show: showImplementation,
+ * }
+ */
+function setServiceImplementation({
+ hide: hideImplementation,
+ show: showImplementation,
+}) {
+ if (hideImplementation) {
+ uiModalServiceImplementation._hide = hideImplementation;
+ }
+ if (showImplementation) {
+ uiModalServiceImplementation._show = showImplementation;
+ }
+}
+
+export default createUIModalService;
diff --git a/platform/core/src/services/UINotificationService/index.js b/platform/core/src/services/UINotificationService/index.js
index 97db61040..7538a6280 100644
--- a/platform/core/src/services/UINotificationService/index.js
+++ b/platform/core/src/services/UINotificationService/index.js
@@ -10,7 +10,7 @@
* @property {boolean} [autoClose=true]
*/
-const uiNotificationServicePublicApi = {
+const uiNotificationServicePublicAPI = {
name: 'UINotificationService',
hide,
show,
@@ -22,8 +22,8 @@ const uiNotificationServiceImplementation = {
_show: () => console.warn('show() NOT IMPLEMENTED'),
};
-function createUiNotificationService() {
- return uiNotificationServicePublicApi;
+function createUINotificationService() {
+ return uiNotificationServicePublicAPI;
}
/**
@@ -81,4 +81,4 @@ function setServiceImplementation({
}
}
-export default createUiNotificationService;
+export default createUINotificationService;
diff --git a/platform/core/src/services/index.js b/platform/core/src/services/index.js
index ded69e822..033dee202 100644
--- a/platform/core/src/services/index.js
+++ b/platform/core/src/services/index.js
@@ -1,4 +1,5 @@
import ServicesManager from './ServicesManager.js';
-import createUiNotificationService from './UINotificationService';
+import createUINotificationService from './UINotificationService';
+import createUIModalService from './UIModalService';
-export { createUiNotificationService, ServicesManager };
+export { createUINotificationService, createUIModalService, ServicesManager };
diff --git a/platform/ui/CHANGELOG.md b/platform/ui/CHANGELOG.md
index 88e3da997..e9b03b77e 100644
--- a/platform/ui/CHANGELOG.md
+++ b/platform/ui/CHANGELOG.md
@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+## [0.62.3](https://github.com/OHIF/Viewers/compare/@ohif/ui@0.62.2...@ohif/ui@0.62.3) (2019-11-15)
+
+**Note:** Version bump only for package @ohif/ui
+
+
+
+
+
+## [0.62.2](https://github.com/OHIF/Viewers/compare/@ohif/ui@0.62.1...@ohif/ui@0.62.2) (2019-11-15)
+
+**Note:** Version bump only for package @ohif/ui
+
+
+
+
+
## [0.62.1](https://github.com/OHIF/Viewers/compare/@ohif/ui@0.62.0...@ohif/ui@0.62.1) (2019-11-14)
**Note:** Version bump only for package @ohif/ui
diff --git a/platform/ui/package.json b/platform/ui/package.json
index 9b900bf70..9126bfc4a 100644
--- a/platform/ui/package.json
+++ b/platform/ui/package.json
@@ -1,6 +1,6 @@
{
"name": "@ohif/ui",
- "version": "0.62.1",
+ "version": "0.62.3",
"description": "A set of React components for Medical Imaging Viewers",
"author": "OHIF Contributors",
"license": "MIT",
diff --git a/platform/ui/src/components/ohifModal/OHIFModal.js b/platform/ui/src/components/ohifModal/OHIFModal.js
index f69c9376e..483c650f9 100644
--- a/platform/ui/src/components/ohifModal/OHIFModal.js
+++ b/platform/ui/src/components/ohifModal/OHIFModal.js
@@ -13,7 +13,7 @@ const OHIFModal = ({
onHide,
footer: Footer,
header: Header,
- children: Component,
+ children,
}) => (