Update extension manager to ingest each module type. Add toolbar Manager.
This commit is contained in:
parent
a8340b9b69
commit
c42aa37d7f
@ -23,7 +23,7 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* Only required property. Should be a unique value across all extensions.
|
* Only required property. Should be a unique value across all extensions.
|
||||||
*/
|
*/
|
||||||
id: 'cornerstone',
|
id: 'org.ohif.cornerstone',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -39,10 +39,14 @@ export default {
|
|||||||
const onNewImageHandler = jumpData => {
|
const onNewImageHandler = jumpData => {
|
||||||
commandsManager.runCommand('jumpToImage', jumpData);
|
commandsManager.runCommand('jumpToImage', jumpData);
|
||||||
};
|
};
|
||||||
return <OHIFCornerstoneViewport {...props} onNewImage={onNewImageHandler} />;
|
return (
|
||||||
|
<OHIFCornerstoneViewport {...props} onNewImage={onNewImageHandler} />
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return ExtendedOHIFCornerstoneViewport;
|
return [
|
||||||
|
{ name: 'cornerstone', component: ExtendedOHIFCornerstoneViewport },
|
||||||
|
];
|
||||||
},
|
},
|
||||||
getToolbarModule() {
|
getToolbarModule() {
|
||||||
return toolbarModule;
|
return toolbarModule;
|
||||||
|
|||||||
@ -15,8 +15,6 @@ import measurementServiceMappingsFactory from './utils/measurementServiceMapping
|
|||||||
export default function init({ servicesManager, configuration }) {
|
export default function init({ servicesManager, configuration }) {
|
||||||
const { UIDialogService, MeasurementService } = servicesManager.services;
|
const { UIDialogService, MeasurementService } = servicesManager.services;
|
||||||
|
|
||||||
debugger;
|
|
||||||
|
|
||||||
const callInputDialog = (data, event, callback) => {
|
const callInputDialog = (data, event, callback) => {
|
||||||
if (UIDialogService) {
|
if (UIDialogService) {
|
||||||
let dialogId = UIDialogService.create({
|
let dialogId = UIDialogService.create({
|
||||||
|
|||||||
@ -165,8 +165,6 @@ function createDicomWebApi(dicomWebConfig) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
debugger;
|
|
||||||
|
|
||||||
return imageIds;
|
return imageIds;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -12,12 +12,25 @@ export default function mode({ modeConfiguration }) {
|
|||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: 'viewer',
|
path: 'viewer',
|
||||||
preInit: ({ toolbarManager }) => {
|
init: ({ toolbarManager }) => {
|
||||||
toolbarManager &&
|
toolbarManager.addButtons([
|
||||||
toolbarManager.setDefaultLoadOut([
|
{
|
||||||
[], // Primary
|
id: 'StackScroll', // If id not given will use default in button definition.
|
||||||
[], // Secondary
|
namespace: 'org.ohif.cornerstone.toolbarModule.StackScroll',
|
||||||
]);
|
},
|
||||||
|
{
|
||||||
|
id: 'Zoom',
|
||||||
|
namespace: 'org.ohif.cornerstone.toolbarModule.Zoom',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Could import layout selector here from org.ohif.default (when it exists!)
|
||||||
|
toolbarManager.setToolBarLayout([
|
||||||
|
// Primary
|
||||||
|
['StackScroll', { label: 'More', subMenu: ['Zoom'] }],
|
||||||
|
// Secondary
|
||||||
|
['StackScroll'],
|
||||||
|
]);
|
||||||
},
|
},
|
||||||
layoutTemplate: ({ routeProps }) => {
|
layoutTemplate: ({ routeProps }) => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
55
platform/core/src/ToolBarManager.js
Normal file
55
platform/core/src/ToolBarManager.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
export default class toolBarManager {
|
||||||
|
constructor(extensionManager) {
|
||||||
|
this.toolBarLayout = [];
|
||||||
|
this.buttons = {};
|
||||||
|
this.extensionManager = extensionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
addButtons(buttons) {
|
||||||
|
buttons.forEach(button => {
|
||||||
|
const buttonDefinition = this.extensionManager.getModuleEntry(
|
||||||
|
button.namespace
|
||||||
|
);
|
||||||
|
|
||||||
|
const id = button.id || buttonDefinition.id;
|
||||||
|
|
||||||
|
this.buttons[id] = buttonDefinition;
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(this.buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
setToolBarLayout(layouts) {
|
||||||
|
const toolBarLayout = [];
|
||||||
|
|
||||||
|
layouts.forEach(layout => {
|
||||||
|
const toolBarDefinitions = [];
|
||||||
|
|
||||||
|
layout.forEach(element => {
|
||||||
|
if (typeof element === 'object') {
|
||||||
|
// process submenu.
|
||||||
|
|
||||||
|
const subMenuDefinition = { label: element.label, subMenu: [] };
|
||||||
|
|
||||||
|
element.subMenu.forEach(subMenuElement => {
|
||||||
|
const button = this.buttons[subMenuElement];
|
||||||
|
|
||||||
|
subMenuDefinition.subMenu.push(button);
|
||||||
|
});
|
||||||
|
|
||||||
|
toolBarDefinitions.push(subMenuDefinition);
|
||||||
|
} else {
|
||||||
|
const button = this.buttons[element];
|
||||||
|
|
||||||
|
toolBarDefinitions.push(button);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
toolBarLayout.push(toolBarDefinitions);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.toolBarLayout = toolBarLayout;
|
||||||
|
|
||||||
|
console.log(this.toolBarLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,6 +17,9 @@ export default class ExtensionManager {
|
|||||||
this.modules[moduleType] = [];
|
this.modules[moduleType] = [];
|
||||||
});
|
});
|
||||||
this.dataSourceMap = {};
|
this.dataSourceMap = {};
|
||||||
|
|
||||||
|
console.log('modules map');
|
||||||
|
console.log(this.modulesMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,11 +58,9 @@ export default class ExtensionManager {
|
|||||||
let extensionId = extension.id;
|
let extensionId = extension.id;
|
||||||
|
|
||||||
if (!extensionId) {
|
if (!extensionId) {
|
||||||
extensionId = Math.random()
|
// Note: Mode framework cannot function without IDs.
|
||||||
.toString(36)
|
log.warn(extension);
|
||||||
.substr(2, 5);
|
throw new Error(`Extension ID not set`);
|
||||||
|
|
||||||
log.warn(`Extension ID not set. Using random string ID: ${extensionId}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.registeredExtensionIds.includes(extensionId)) {
|
if (this.registeredExtensionIds.includes(extensionId)) {
|
||||||
@ -89,25 +90,43 @@ export default class ExtensionManager {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (extensionModule) {
|
if (extensionModule) {
|
||||||
this._initSpecialModuleTypes(
|
switch (moduleType) {
|
||||||
extensionId,
|
case MODULE_TYPES.COMMANDS:
|
||||||
moduleType,
|
this._initCommandsModule(extensionModule);
|
||||||
extensionModule,
|
break;
|
||||||
dataSources
|
case MODULE_TYPES.DATA_SOURCE:
|
||||||
);
|
this._initDataSourcesModule(
|
||||||
|
extensionModule,
|
||||||
|
extensionId,
|
||||||
|
dataSources
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case MODULE_TYPES.TOOLBAR:
|
||||||
|
this._initToolBarModule(extensionModule, extensionId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODULE_TYPES.PANEL:
|
||||||
|
case MODULE_TYPES.SOP_CLASS_HANDLER:
|
||||||
|
case MODULE_TYPES.VIEWPORT:
|
||||||
|
case MODULE_TYPES.CONTEXT:
|
||||||
|
case MODULE_TYPES.LAYOUT_TEMPLATE:
|
||||||
|
// Default for most extension points,
|
||||||
|
// Just adds each entry ready for consumption by mode.
|
||||||
|
if (!extensionModule.forEach) {
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
|
|
||||||
|
extensionModule.forEach(element => {
|
||||||
|
this.modulesMap[
|
||||||
|
`${extensionId}.${moduleType}.${element.name}`
|
||||||
|
] = element;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.modules[moduleType].push({
|
this.modules[moduleType].push({
|
||||||
extensionId,
|
extensionId,
|
||||||
module: extensionModule,
|
module: extensionModule,
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO -> deal with command modules.
|
|
||||||
|
|
||||||
extensionModule.forEach(element => {
|
|
||||||
this.modulesMap[
|
|
||||||
`${extensionId}.${moduleType}.${element.name}`
|
|
||||||
] = element;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -124,6 +143,27 @@ export default class ExtensionManager {
|
|||||||
return this.dataSourceMap[dataSourceName];
|
return this.dataSourceMap[dataSourceName];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_initToolBarModule = (extensionModule, extensionId) => {
|
||||||
|
let { definitions, defaultContext } = extensionModule;
|
||||||
|
if (!definitions || Object.keys(definitions).length === 0) {
|
||||||
|
log.warn('Commands Module contains no command definitions');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultContext = defaultContext || 'VIEWER';
|
||||||
|
|
||||||
|
definitions.forEach(definition => {
|
||||||
|
console.log(`${extensionId}.${MODULE_TYPES.TOOLBAR}.${definition.id}`);
|
||||||
|
|
||||||
|
// TODO -> Deep copy instead of mutation? We only do this once, but would be better.
|
||||||
|
definition.context = definition.context || defaultContext;
|
||||||
|
|
||||||
|
this.modulesMap[
|
||||||
|
`${extensionId}.${MODULE_TYPES.TOOLBAR}.${definition.id}`
|
||||||
|
] = definition;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {string} moduleType
|
* @param {string} moduleType
|
||||||
@ -162,64 +202,52 @@ export default class ExtensionManager {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_initSpecialModuleTypes = (
|
_initDataSourcesModule(extensionModule, extensionId, dataSources) {
|
||||||
extensionId,
|
extensionModule.forEach(element => {
|
||||||
moduleType,
|
const namespace = `${extensionId}.${MODULE_TYPES.DATA_SOURCE}.${element.name}`;
|
||||||
extensionModule,
|
|
||||||
dataSources
|
dataSources.forEach(dataSource => {
|
||||||
) => {
|
if (dataSource.namespace === namespace) {
|
||||||
switch (moduleType) {
|
const dataSourceInstance = element.createDataSource(
|
||||||
case 'commandsModule': {
|
dataSource.configuration
|
||||||
const { definitions, defaultContext } = extensionModule;
|
);
|
||||||
if (!definitions || Object.keys(definitions).length === 0) {
|
|
||||||
log.warn('Commands Module contains no command definitions');
|
if (this.dataSourceMap[dataSource.sourceName]) {
|
||||||
return;
|
this.dataSourceMap[dataSource.sourceName].push(dataSourceInstance);
|
||||||
|
} else {
|
||||||
|
this.dataSourceMap[dataSource.sourceName] = [dataSourceInstance];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this._initCommandsModule(definitions, defaultContext);
|
});
|
||||||
break;
|
});
|
||||||
}
|
|
||||||
case 'dataSourcesModule': {
|
|
||||||
extensionModule.forEach(element => {
|
|
||||||
const namespace = `${extensionId}.${moduleType}.${element.name}`;
|
|
||||||
|
|
||||||
dataSources.forEach(dataSource => {
|
extensionModule.forEach(element => {
|
||||||
if (dataSource.namespace === namespace) {
|
this.modulesMap[
|
||||||
const dataSourceInstance = element.createDataSource(
|
`${extensionId}.${MODULE_TYPES.DATA_SOURCE}.${element.name}`
|
||||||
dataSource.configuration
|
] = element;
|
||||||
);
|
});
|
||||||
|
}
|
||||||
if (this.dataSourceMap[dataSource.sourceName]) {
|
|
||||||
this.dataSourceMap[dataSource.sourceName].push(
|
|
||||||
dataSourceInstance
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.dataSourceMap[dataSource.sourceName] = [
|
|
||||||
dataSourceInstance,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// code block
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {Object[]} commandDefinitions
|
* @param {Object[]} commandDefinitions
|
||||||
*/
|
*/
|
||||||
_initCommandsModule = (commandDefinitions, defaultContext = 'VIEWER') => {
|
_initCommandsModule = extensionModule => {
|
||||||
|
let { definitions, defaultContext } = extensionModule;
|
||||||
|
if (!definitions || Object.keys(definitions).length === 0) {
|
||||||
|
log.warn('Commands Module contains no command definitions');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultContext = defaultContext || 'VIEWER';
|
||||||
|
|
||||||
if (!this._commandsManager.getContext(defaultContext)) {
|
if (!this._commandsManager.getContext(defaultContext)) {
|
||||||
this._commandsManager.createContext(defaultContext);
|
this._commandsManager.createContext(defaultContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(commandDefinitions).forEach(commandName => {
|
Object.keys(definitions).forEach(commandName => {
|
||||||
const commandDefinition = commandDefinitions[commandName];
|
const commandDefinition = definitions[commandName];
|
||||||
const commandHasContextThatDoesNotExist =
|
const commandHasContextThatDoesNotExist =
|
||||||
commandDefinition.context &&
|
commandDefinition.context &&
|
||||||
!this._commandsManager.getContext(commandDefinition.context);
|
!this._commandsManager.getContext(commandDefinition.context);
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import ui from './ui';
|
|||||||
import user from './user.js';
|
import user from './user.js';
|
||||||
import dicomMetadataStore from './dicomMetadataStore';
|
import dicomMetadataStore from './dicomMetadataStore';
|
||||||
import displaySetManager from './displaySetManager';
|
import displaySetManager from './displaySetManager';
|
||||||
|
import ToolBarManager from './ToolBarManager';
|
||||||
import utils, { hotkeys } from './utils/';
|
import utils, { hotkeys } from './utils/';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -68,6 +69,7 @@ const OHIF = {
|
|||||||
IWebApiDataSource,
|
IWebApiDataSource,
|
||||||
dicomMetadataStore,
|
dicomMetadataStore,
|
||||||
displaySetManager,
|
displaySetManager,
|
||||||
|
ToolBarManager,
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@ -105,6 +107,7 @@ export {
|
|||||||
IWebApiDataSource,
|
IWebApiDataSource,
|
||||||
dicomMetadataStore,
|
dicomMetadataStore,
|
||||||
displaySetManager,
|
displaySetManager,
|
||||||
|
ToolBarManager,
|
||||||
};
|
};
|
||||||
|
|
||||||
export { OHIF };
|
export { OHIF };
|
||||||
|
|||||||
@ -47,8 +47,6 @@ function appInit(appConfigOrFunc, defaultExtensions) {
|
|||||||
MeasurementService,
|
MeasurementService,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
debugger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example: [ext1, ext2, ext3]
|
* Example: [ext1, ext2, ext3]
|
||||||
* Example2: [[ext1, config], ext2, [ext3, config]]
|
* Example2: [[ext1, config], ext2, [ext3, config]]
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React, { useContext, useEffect, useCallback } from 'react';
|
import React, { useContext, useEffect, useCallback } from 'react';
|
||||||
import { displaySetManager } from '@ohif/core';
|
import { displaySetManager, ToolBarManager } from '@ohif/core';
|
||||||
import ViewModelContext from './ViewModelContext';
|
import ViewModelContext from './ViewModelContext';
|
||||||
import Compose from './Compose';
|
import Compose from './Compose';
|
||||||
|
|
||||||
@ -9,15 +9,21 @@ export default function ModeRoute({
|
|||||||
dataSourceName,
|
dataSourceName,
|
||||||
extensionManager,
|
extensionManager,
|
||||||
}) {
|
}) {
|
||||||
const { routes, sopClassHandlers, extensions } = mode;
|
const { routes, sopClassHandlers, extensions, init } = mode;
|
||||||
const dataSources = extensionManager.getDataSources(dataSourceName);
|
const dataSources = extensionManager.getDataSources(dataSourceName);
|
||||||
|
|
||||||
|
const toolbarManager = new ToolBarManager(extensionManager);
|
||||||
|
|
||||||
// TODO: For now assume one unique datasource.
|
// TODO: For now assume one unique datasource.
|
||||||
|
|
||||||
const dataSource = dataSources[0];
|
const dataSource = dataSources[0];
|
||||||
|
const route = routes[0];
|
||||||
|
|
||||||
|
route.init({ toolbarManager });
|
||||||
|
|
||||||
console.log(dataSource);
|
console.log(dataSource);
|
||||||
|
|
||||||
|
// Add toolbar state to the view model context?
|
||||||
const { displaySetInstanceUids, setDisplaySetInstanceUids } = useContext(
|
const { displaySetInstanceUids, setDisplaySetInstanceUids } = useContext(
|
||||||
ViewModelContext
|
ViewModelContext
|
||||||
);
|
);
|
||||||
@ -42,11 +48,9 @@ export default function ModeRoute({
|
|||||||
createDisplaySets();
|
createDisplaySets();
|
||||||
}, [mode, dataSourceName, location]);
|
}, [mode, dataSourceName, location]);
|
||||||
|
|
||||||
// Deal with toolbar.
|
|
||||||
|
|
||||||
// Only handling one route per mode for now
|
// Only handling one route per mode for now
|
||||||
// You can test via http://localhost:3000/example-mode/dicomweb
|
// You can test via http://localhost:3000/example-mode/dicomweb
|
||||||
const layoutTemplateData = routes[0].layoutTemplate({ location });
|
const layoutTemplateData = route.layoutTemplate({ location });
|
||||||
const layoutTemplateModuleEntry = extensionManager.getModuleEntry(
|
const layoutTemplateModuleEntry = extensionManager.getModuleEntry(
|
||||||
layoutTemplateData.id
|
layoutTemplateData.id
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user