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.
|
||||
*/
|
||||
id: 'cornerstone',
|
||||
id: 'org.ohif.cornerstone',
|
||||
|
||||
/**
|
||||
*
|
||||
@ -39,10 +39,14 @@ export default {
|
||||
const onNewImageHandler = jumpData => {
|
||||
commandsManager.runCommand('jumpToImage', jumpData);
|
||||
};
|
||||
return <OHIFCornerstoneViewport {...props} onNewImage={onNewImageHandler} />;
|
||||
return (
|
||||
<OHIFCornerstoneViewport {...props} onNewImage={onNewImageHandler} />
|
||||
);
|
||||
};
|
||||
|
||||
return ExtendedOHIFCornerstoneViewport;
|
||||
return [
|
||||
{ name: 'cornerstone', component: ExtendedOHIFCornerstoneViewport },
|
||||
];
|
||||
},
|
||||
getToolbarModule() {
|
||||
return toolbarModule;
|
||||
|
||||
@ -15,8 +15,6 @@ import measurementServiceMappingsFactory from './utils/measurementServiceMapping
|
||||
export default function init({ servicesManager, configuration }) {
|
||||
const { UIDialogService, MeasurementService } = servicesManager.services;
|
||||
|
||||
debugger;
|
||||
|
||||
const callInputDialog = (data, event, callback) => {
|
||||
if (UIDialogService) {
|
||||
let dialogId = UIDialogService.create({
|
||||
|
||||
@ -165,8 +165,6 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
}
|
||||
});
|
||||
|
||||
debugger;
|
||||
|
||||
return imageIds;
|
||||
},
|
||||
});
|
||||
|
||||
@ -12,12 +12,25 @@ export default function mode({ modeConfiguration }) {
|
||||
routes: [
|
||||
{
|
||||
path: 'viewer',
|
||||
preInit: ({ toolbarManager }) => {
|
||||
toolbarManager &&
|
||||
toolbarManager.setDefaultLoadOut([
|
||||
[], // Primary
|
||||
[], // Secondary
|
||||
]);
|
||||
init: ({ toolbarManager }) => {
|
||||
toolbarManager.addButtons([
|
||||
{
|
||||
id: 'StackScroll', // If id not given will use default in button definition.
|
||||
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 }) => {
|
||||
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.dataSourceMap = {};
|
||||
|
||||
console.log('modules map');
|
||||
console.log(this.modulesMap);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,11 +58,9 @@ export default class ExtensionManager {
|
||||
let extensionId = extension.id;
|
||||
|
||||
if (!extensionId) {
|
||||
extensionId = Math.random()
|
||||
.toString(36)
|
||||
.substr(2, 5);
|
||||
|
||||
log.warn(`Extension ID not set. Using random string ID: ${extensionId}`);
|
||||
// Note: Mode framework cannot function without IDs.
|
||||
log.warn(extension);
|
||||
throw new Error(`Extension ID not set`);
|
||||
}
|
||||
|
||||
if (this.registeredExtensionIds.includes(extensionId)) {
|
||||
@ -89,25 +90,43 @@ export default class ExtensionManager {
|
||||
);
|
||||
|
||||
if (extensionModule) {
|
||||
this._initSpecialModuleTypes(
|
||||
extensionId,
|
||||
moduleType,
|
||||
extensionModule,
|
||||
dataSources
|
||||
);
|
||||
switch (moduleType) {
|
||||
case MODULE_TYPES.COMMANDS:
|
||||
this._initCommandsModule(extensionModule);
|
||||
break;
|
||||
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({
|
||||
extensionId,
|
||||
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];
|
||||
};
|
||||
|
||||
_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
|
||||
* @param {string} moduleType
|
||||
@ -162,64 +202,52 @@ export default class ExtensionManager {
|
||||
}
|
||||
};
|
||||
|
||||
_initSpecialModuleTypes = (
|
||||
extensionId,
|
||||
moduleType,
|
||||
extensionModule,
|
||||
dataSources
|
||||
) => {
|
||||
switch (moduleType) {
|
||||
case 'commandsModule': {
|
||||
const { definitions, defaultContext } = extensionModule;
|
||||
if (!definitions || Object.keys(definitions).length === 0) {
|
||||
log.warn('Commands Module contains no command definitions');
|
||||
return;
|
||||
_initDataSourcesModule(extensionModule, extensionId, dataSources) {
|
||||
extensionModule.forEach(element => {
|
||||
const namespace = `${extensionId}.${MODULE_TYPES.DATA_SOURCE}.${element.name}`;
|
||||
|
||||
dataSources.forEach(dataSource => {
|
||||
if (dataSource.namespace === namespace) {
|
||||
const dataSourceInstance = element.createDataSource(
|
||||
dataSource.configuration
|
||||
);
|
||||
|
||||
if (this.dataSourceMap[dataSource.sourceName]) {
|
||||
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 => {
|
||||
if (dataSource.namespace === namespace) {
|
||||
const dataSourceInstance = element.createDataSource(
|
||||
dataSource.configuration
|
||||
);
|
||||
|
||||
if (this.dataSourceMap[dataSource.sourceName]) {
|
||||
this.dataSourceMap[dataSource.sourceName].push(
|
||||
dataSourceInstance
|
||||
);
|
||||
} else {
|
||||
this.dataSourceMap[dataSource.sourceName] = [
|
||||
dataSourceInstance,
|
||||
];
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// code block
|
||||
}
|
||||
};
|
||||
extensionModule.forEach(element => {
|
||||
this.modulesMap[
|
||||
`${extensionId}.${MODULE_TYPES.DATA_SOURCE}.${element.name}`
|
||||
] = element;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @private
|
||||
* @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)) {
|
||||
this._commandsManager.createContext(defaultContext);
|
||||
}
|
||||
|
||||
Object.keys(commandDefinitions).forEach(commandName => {
|
||||
const commandDefinition = commandDefinitions[commandName];
|
||||
Object.keys(definitions).forEach(commandName => {
|
||||
const commandDefinition = definitions[commandName];
|
||||
const commandHasContextThatDoesNotExist =
|
||||
commandDefinition.context &&
|
||||
!this._commandsManager.getContext(commandDefinition.context);
|
||||
|
||||
@ -20,6 +20,7 @@ import ui from './ui';
|
||||
import user from './user.js';
|
||||
import dicomMetadataStore from './dicomMetadataStore';
|
||||
import displaySetManager from './displaySetManager';
|
||||
import ToolBarManager from './ToolBarManager';
|
||||
import utils, { hotkeys } from './utils/';
|
||||
|
||||
import {
|
||||
@ -68,6 +69,7 @@ const OHIF = {
|
||||
IWebApiDataSource,
|
||||
dicomMetadataStore,
|
||||
displaySetManager,
|
||||
ToolBarManager,
|
||||
};
|
||||
|
||||
export {
|
||||
@ -105,6 +107,7 @@ export {
|
||||
IWebApiDataSource,
|
||||
dicomMetadataStore,
|
||||
displaySetManager,
|
||||
ToolBarManager,
|
||||
};
|
||||
|
||||
export { OHIF };
|
||||
|
||||
@ -47,8 +47,6 @@ function appInit(appConfigOrFunc, defaultExtensions) {
|
||||
MeasurementService,
|
||||
]);
|
||||
|
||||
debugger;
|
||||
|
||||
/**
|
||||
* Example: [ext1, ext2, ext3]
|
||||
* Example2: [[ext1, config], ext2, [ext3, config]]
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React, { useContext, useEffect, useCallback } from 'react';
|
||||
import { displaySetManager } from '@ohif/core';
|
||||
import { displaySetManager, ToolBarManager } from '@ohif/core';
|
||||
import ViewModelContext from './ViewModelContext';
|
||||
import Compose from './Compose';
|
||||
|
||||
@ -9,15 +9,21 @@ export default function ModeRoute({
|
||||
dataSourceName,
|
||||
extensionManager,
|
||||
}) {
|
||||
const { routes, sopClassHandlers, extensions } = mode;
|
||||
const { routes, sopClassHandlers, extensions, init } = mode;
|
||||
const dataSources = extensionManager.getDataSources(dataSourceName);
|
||||
|
||||
const toolbarManager = new ToolBarManager(extensionManager);
|
||||
|
||||
// TODO: For now assume one unique datasource.
|
||||
|
||||
const dataSource = dataSources[0];
|
||||
const route = routes[0];
|
||||
|
||||
route.init({ toolbarManager });
|
||||
|
||||
console.log(dataSource);
|
||||
|
||||
// Add toolbar state to the view model context?
|
||||
const { displaySetInstanceUids, setDisplaySetInstanceUids } = useContext(
|
||||
ViewModelContext
|
||||
);
|
||||
@ -42,11 +48,9 @@ export default function ModeRoute({
|
||||
createDisplaySets();
|
||||
}, [mode, dataSourceName, location]);
|
||||
|
||||
// Deal with toolbar.
|
||||
|
||||
// Only handling one route per mode for now
|
||||
// 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(
|
||||
layoutTemplateData.id
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user