* Fix ExtensionManager bug and add test to bandaid * Add tools configuration to extension manager preinit * Fix reducing of configs * Merge internal with external configs * Merge internal with external configs * Remove dialog from init in measurementstable * Testing injected configuration * New way to set config * Add new prop to dialog provider to allow disabling last position * Remove code from preinit in cornerstone * Add new prop to dialog provider to allow disabling last position * Add centralize to dialogs * Reorder dialogs when adding them * Fix draggable styles (cursor) * Remove repositioning methods from labelling flow and remove overlay from labelling manager * Fix empty array being set in bringToFront * Add new command to update table and pass commands manager to modules/preinit hook * Ad UIContextMenu service / factory * Use new contextmenu service in measurementspanel extension * Use dialogs for arrow annotate in default * Remove positioning funcionality from tool context menu * Add context menu service * Pass commandsModule to extension * Update edit description dialog and simple dialog to position relative * Remove style code from labelling flow and manager * Remove eventdata from labelling * Remove labelling code from measurement init * Add commandsmanager to provider * Update contextmenu provider and service * Add touchstart and mouseclick to hide contextmenu * Hide labelling if click/touch * Remove labelling and context menu dead code * Fix undefined bug if ViewerMain grid has no children * Fix broken prop on context menu * Update commandsmodule based on master * Fix broken configuration * Update script tag config * Remove cornerstone from toolcontextmenu * Remove cornerstone from toolcontextmenu * Split labelling and context menu providers * Split labelling and context menu providers * Update test * Destructure extensions into new array * CR Update: Move default arrow config to cornerstone instead of default * CR Update: Fix app configuration props structure * CR Update: Fix app configuration prop in script tag and extract commands manager from providers * CR Update: Create custom providers to use commandsManager * CR Update: Use services directly in measurementspanel * CR Update: Pass components to providers * CR Update: Remove position from dialog * CR Update: fix dialog prop check * CR Update: Fix comments * CR Update: Update documentation * CR Update: Add test default configuration * CR Update: Add default empy array to extensions * CR Update: Update i18n configuration all ot match current function configuration * CR Update: Add defaults to injected dependencies in configuration and extension configuration * CR Update: Add defaults to configuration with no args * Update documentation * CR Update: Add default for tools * CR Update: Update config object to i18n * CR Update: spread defaults * CR Update: Add tool configuration example to cornerstone extension * CR Update: Add tool configuration to netlify (testing) * CR Update: Remove netlify config for tools * CR Update: Rollback changes to i18n to be fixed later * CR Update: Update documentation and pass whole cornerstone config object instead of tools key SEE: https://www.conventionalcommits.org/en/v1.0.0/#commit-message-with-both-and-breaking-change-footer BREAKING CHANGE: modifies the exposed react <App /> components props. The contract for providing configuration for the app has changed. Please reference updated documentation for guidance.
185 lines
4.9 KiB
JavaScript
185 lines
4.9 KiB
JavaScript
import MODULE_TYPES from './MODULE_TYPES.js';
|
|
import log from './../log.js';
|
|
|
|
export default class ExtensionManager {
|
|
constructor({ commandsManager, servicesManager }) {
|
|
this.modules = {};
|
|
this.registeredExtensionIds = [];
|
|
this.moduleTypeNames = Object.values(MODULE_TYPES);
|
|
//
|
|
this._commandsManager = commandsManager;
|
|
this._servicesManager = servicesManager;
|
|
|
|
this.moduleTypeNames.forEach(moduleType => {
|
|
this.modules[moduleType] = [];
|
|
});
|
|
}
|
|
|
|
/**
|
|
* An array of extensions, or an array of arrays that contains extension
|
|
* configuration pairs.
|
|
*
|
|
* @param {Object[]} extensions - Array of extensions
|
|
*/
|
|
registerExtensions(extensions) {
|
|
extensions.forEach(extension => {
|
|
const hasConfiguration = Array.isArray(extension);
|
|
|
|
if (hasConfiguration) {
|
|
const [ohifExtension, configuration] = extension;
|
|
this.registerExtension(ohifExtension, configuration);
|
|
} else {
|
|
this.registerExtension(extension);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
*
|
|
* TODO: Id Management: SopClassHandlers currently refer to viewport module by id; setting the extension id as viewport module id is a workaround for now
|
|
* @param {Object} extension
|
|
* @param {Object} configuration
|
|
*/
|
|
registerExtension(extension, configuration = {}) {
|
|
if (!extension) {
|
|
log.warn(
|
|
'Attempting to register a null/undefined extension. Exiting early.'
|
|
);
|
|
return;
|
|
}
|
|
|
|
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}`);
|
|
}
|
|
|
|
if (this.registeredExtensionIds.includes(extensionId)) {
|
|
log.warn(
|
|
`Extension ID ${extensionId} has already been registered. Exiting before duplicating modules.`
|
|
);
|
|
return;
|
|
}
|
|
|
|
// preRegistrationHook
|
|
if (extension.preRegistration) {
|
|
extension.preRegistration({
|
|
servicesManager: this._servicesManager,
|
|
commandsManager: this._commandsManager,
|
|
configuration,
|
|
});
|
|
}
|
|
|
|
// Register Modules
|
|
this.moduleTypeNames.forEach(moduleType => {
|
|
const extensionModule = this._getExtensionModule(
|
|
moduleType,
|
|
extension,
|
|
extensionId
|
|
);
|
|
|
|
if (extensionModule) {
|
|
this._initSpecialModuleTypes(moduleType, extensionModule);
|
|
|
|
this.modules[moduleType].push({
|
|
extensionId,
|
|
module: extensionModule,
|
|
});
|
|
}
|
|
});
|
|
|
|
// Track extension registration
|
|
this.registeredExtensionIds.push(extensionId);
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
* @param {string} moduleType
|
|
* @param {Object} extension
|
|
* @param {string} extensionId - Used for logging warnings
|
|
*/
|
|
_getExtensionModule(moduleType, extension, extensionId) {
|
|
const getModuleFnName = 'get' + _capitalizeFirstCharacter(moduleType);
|
|
const getModuleFn = extension[getModuleFnName];
|
|
|
|
if (!getModuleFn) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const extensionModule = getModuleFn({
|
|
servicesManager: this._servicesManager,
|
|
commandsManager: this._commandsManager,
|
|
});
|
|
|
|
if (!extensionModule) {
|
|
log.warn(
|
|
`Null or undefined returned when registering the ${getModuleFnName} module for the ${extensionId} extension`
|
|
);
|
|
}
|
|
|
|
return extensionModule;
|
|
} catch (ex) {
|
|
log.error(
|
|
`Exception thrown while trying to call ${getModuleFnName} for the ${extensionId} extension`
|
|
);
|
|
}
|
|
}
|
|
|
|
_initSpecialModuleTypes(moduleType, extensionModule) {
|
|
switch (moduleType) {
|
|
case 'commandsModule': {
|
|
const { definitions, defaultContext } = extensionModule;
|
|
if (!definitions || Object.keys(definitions).length === 0) {
|
|
log.warn('Commands Module contains no command definitions');
|
|
return;
|
|
}
|
|
this._initCommandsModule(definitions, defaultContext);
|
|
break;
|
|
}
|
|
default:
|
|
// code block
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @private
|
|
* @param {Object[]} commandDefinitions
|
|
*/
|
|
_initCommandsModule(commandDefinitions, defaultContext = 'VIEWER') {
|
|
if (!this._commandsManager.getContext(defaultContext)) {
|
|
this._commandsManager.createContext(defaultContext);
|
|
}
|
|
|
|
Object.keys(commandDefinitions).forEach(commandName => {
|
|
const commandDefinition = commandDefinitions[commandName];
|
|
const commandHasContextThatDoesNotExist =
|
|
commandDefinition.context &&
|
|
!this._commandsManager.getContext(commandDefinition.context);
|
|
|
|
if (commandHasContextThatDoesNotExist) {
|
|
this._commandsManager.createContext(commandDefinition.context);
|
|
}
|
|
|
|
this._commandsManager.registerCommand(
|
|
commandDefinition.context || defaultContext,
|
|
commandName,
|
|
commandDefinition
|
|
);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
* @param {string} lower
|
|
*/
|
|
function _capitalizeFirstCharacter(lower) {
|
|
return lower.charAt(0).toUpperCase() + lower.substr(1);
|
|
}
|