2023-02-10 20:30:56 +01:00
|
|
|
import MODULE_TYPES from './MODULE_TYPES';
|
|
|
|
|
import log from '../log';
|
|
|
|
|
import { AppConfig } from '../types/AppConfig';
|
|
|
|
|
import { ServicesManager } from '../services';
|
|
|
|
|
import { HotkeysManager, CommandsManager } from '../classes';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This is the arguments given to create the extension.
|
|
|
|
|
*/
|
|
|
|
|
export interface ExtensionConstructor {
|
|
|
|
|
servicesManager: ServicesManager;
|
|
|
|
|
commandsManager: CommandsManager;
|
|
|
|
|
hotkeysManager: HotkeysManager;
|
|
|
|
|
appConfig: AppConfig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The configuration of an extension.
|
|
|
|
|
* This uses type as the extension manager only knows that the configuration
|
|
|
|
|
* is an object of some sort, and doesn't know anything else about it.
|
|
|
|
|
*/
|
|
|
|
|
export type ExtensionConfiguration = Record<string, unknown>;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The parameters passed to the extension.
|
|
|
|
|
*/
|
|
|
|
|
export interface ExtensionParams extends ExtensionConstructor {
|
|
|
|
|
extensionManager: ExtensionManager;
|
|
|
|
|
configuration?: ExtensionConfiguration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The type of an actual extension instance.
|
|
|
|
|
* This is an interface as it declares possible calls, but extensions can
|
|
|
|
|
* have more values than this.
|
|
|
|
|
*/
|
|
|
|
|
export interface Extension {
|
2023-02-17 21:04:07 +01:00
|
|
|
id: string;
|
2023-03-22 22:45:28 +01:00
|
|
|
preRegistration?: (p: ExtensionParams) => Promise<void> | void;
|
|
|
|
|
getHangingProtocolModule?: (p: ExtensionParams) => unknown;
|
|
|
|
|
getCommandsModule?: (p: ExtensionParams) => CommandsModule;
|
2023-04-18 17:17:50 +02:00
|
|
|
getViewportModule?: (p: ExtensionParams) => unknown;
|
|
|
|
|
getUtilityModule?: (p: ExtensionParams) => unknown;
|
feat(RT): add dicom RT support via volume viewports (#3310)
* feat: initial RT support
* make the segmentation service work with representation data
* feat: make segmentation service work with representations
* fix rtss vis
* fix: rt hydration
* fix the rendering of rt names
* fix imports
* refactor: Modify status and click handling for hydration of RTStructures
Modify status and click handling for hydration of RTStructures by renaming `onPillClick` to `onStatusClick` in `OHIFCornerstoneRTViewport.tsx` and `_getStatusComponent.tsx` files. Also, update initial segmentation configurations in `PanelSegmentation.tsx` and simplify configuration changes and values for segmentation service in `SegmentationService.ts`. Finally, remove console debug in `CornerstoneViewportService.ts`.
* wip for highlighting contours
* refactor rt displayset code
* review code update
* update cornerstone dependencies
* refactor: Update license year, version number, and minor code cleanup
This commit updates the license year in several files, updates the version number in package.json, and contains minor code cleanup in two files.
* add bulkdataURI retrieve for RT
* fix package version
* apply review comments
* apply review comments
* apply review comments
* feat(panels): refactor and streamline segmentation configuration and inputs
Rewrote state hooks and streamlined the configuration input for `PanelSegmentation` to be more verbose and reusable. Included several new input types, including the `InputRange` component which now shows a fixed floating value based on the step provided. The `SegmentationConfig` component now works with dynamic values controlled by `initialConfig`. These changes should improve function usability and make the code more maintainable going forward.
* fix various bugs
* fix contour delete by upgrade cs3d version
* feat(viewport, inputNumber, segmentationConfig, orthanc): Implement minimum and maximum values for input number components, and useBulkDataURI for Orthanc configuration. Compare measurement view planes with absolute viewport view planes in Cornerstone viewport.
* update yarn lock
2023-04-26 18:21:08 +02:00
|
|
|
getCustomizationModule?: (p: ExtensionParams) => unknown;
|
2023-04-18 17:17:50 +02:00
|
|
|
onModeEnter?: () => void;
|
|
|
|
|
onModeExit?: () => void;
|
2023-02-10 20:30:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type ExtensionRegister = {
|
|
|
|
|
id: string;
|
|
|
|
|
create: (p: ExtensionParams) => Extension;
|
|
|
|
|
};
|
2019-08-13 21:36:46 +02:00
|
|
|
|
2023-03-22 22:45:28 +01:00
|
|
|
export type CommandsModule = {
|
|
|
|
|
actions: Record<string, unknown>;
|
|
|
|
|
definitions: Record<string, unknown>;
|
|
|
|
|
defaultContext?: string;
|
|
|
|
|
};
|
|
|
|
|
|
2019-08-13 21:36:46 +02:00
|
|
|
export default class ExtensionManager {
|
2023-02-10 20:30:56 +01:00
|
|
|
private _commandsManager: CommandsManager;
|
|
|
|
|
private _servicesManager: ServicesManager;
|
|
|
|
|
private _hotkeysManager: HotkeysManager;
|
|
|
|
|
|
2021-05-28 20:32:48 +02:00
|
|
|
constructor({
|
|
|
|
|
commandsManager,
|
|
|
|
|
servicesManager,
|
|
|
|
|
hotkeysManager,
|
|
|
|
|
appConfig = {},
|
2023-02-10 20:30:56 +01:00
|
|
|
}: ExtensionConstructor) {
|
2019-08-13 21:36:46 +02:00
|
|
|
this.modules = {};
|
|
|
|
|
this.registeredExtensionIds = [];
|
|
|
|
|
this.moduleTypeNames = Object.values(MODULE_TYPES);
|
|
|
|
|
//
|
|
|
|
|
this._commandsManager = commandsManager;
|
2019-11-13 21:02:14 +01:00
|
|
|
this._servicesManager = servicesManager;
|
2020-08-19 21:02:59 +02:00
|
|
|
this._hotkeysManager = hotkeysManager;
|
2019-12-16 20:07:53 +01:00
|
|
|
this._appConfig = appConfig;
|
2019-08-13 21:36:46 +02:00
|
|
|
|
2020-05-07 20:04:33 +02:00
|
|
|
this.modulesMap = {};
|
2019-08-13 21:36:46 +02:00
|
|
|
this.moduleTypeNames.forEach(moduleType => {
|
|
|
|
|
this.modules[moduleType] = [];
|
|
|
|
|
});
|
2020-08-04 11:11:23 +02:00
|
|
|
this._extensionLifeCycleHooks = { onModeEnter: {}, onModeExit: {} };
|
2020-05-07 20:04:33 +02:00
|
|
|
this.dataSourceMap = {};
|
2022-12-29 16:13:06 +01:00
|
|
|
this.dataSourceDefs = {};
|
2020-06-05 17:36:11 +02:00
|
|
|
this.defaultDataSourceName = appConfig.defaultDataSourceName;
|
|
|
|
|
this.activeDataSource = undefined;
|
|
|
|
|
}
|
2020-05-13 12:06:13 +02:00
|
|
|
|
2023-02-10 20:30:56 +01:00
|
|
|
public setActiveDataSource(dataSourceName: string): void {
|
2020-06-05 17:36:11 +02:00
|
|
|
this.activeDataSource = dataSourceName;
|
2019-08-13 21:36:46 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-10 20:30:56 +01:00
|
|
|
/**
|
|
|
|
|
* Calls all the services and extension on mode enters.
|
|
|
|
|
* The service onModeEnter is called first
|
|
|
|
|
* Then registered extensions onModeEnter is called
|
|
|
|
|
* This is supposed to setup the extension for a standard entry.
|
|
|
|
|
*/
|
|
|
|
|
public onModeEnter(): void {
|
2020-07-03 19:18:59 +02:00
|
|
|
const {
|
|
|
|
|
registeredExtensionIds,
|
|
|
|
|
_servicesManager,
|
|
|
|
|
_commandsManager,
|
2020-08-19 21:02:59 +02:00
|
|
|
_hotkeysManager,
|
2020-07-03 19:18:59 +02:00
|
|
|
_extensionLifeCycleHooks,
|
|
|
|
|
} = this;
|
|
|
|
|
|
2022-12-09 16:58:01 +01:00
|
|
|
// The onModeEnter of the service must occur BEFORE the extension
|
|
|
|
|
// onModeEnter in order to reset the state to a standard state
|
|
|
|
|
// before the extension restores and cached data.
|
2022-11-24 22:28:10 +01:00
|
|
|
for (const service of Object.values(_servicesManager.services)) {
|
|
|
|
|
service?.onModeEnter?.();
|
|
|
|
|
}
|
2020-08-04 11:11:23 +02:00
|
|
|
|
2020-07-03 19:18:59 +02:00
|
|
|
registeredExtensionIds.forEach(extensionId => {
|
|
|
|
|
const onModeEnter = _extensionLifeCycleHooks.onModeEnter[extensionId];
|
|
|
|
|
|
|
|
|
|
if (typeof onModeEnter === 'function') {
|
|
|
|
|
onModeEnter({
|
|
|
|
|
servicesManager: _servicesManager,
|
|
|
|
|
commandsManager: _commandsManager,
|
2021-05-28 20:32:48 +02:00
|
|
|
hotkeysManager: _hotkeysManager,
|
2020-07-03 19:18:59 +02:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-10 20:30:56 +01:00
|
|
|
public onModeExit(): void {
|
2020-08-04 11:11:23 +02:00
|
|
|
const {
|
|
|
|
|
registeredExtensionIds,
|
|
|
|
|
_servicesManager,
|
|
|
|
|
_commandsManager,
|
|
|
|
|
_extensionLifeCycleHooks,
|
|
|
|
|
} = this;
|
|
|
|
|
|
|
|
|
|
registeredExtensionIds.forEach(extensionId => {
|
|
|
|
|
const onModeExit = _extensionLifeCycleHooks.onModeExit[extensionId];
|
|
|
|
|
|
|
|
|
|
if (typeof onModeExit === 'function') {
|
|
|
|
|
onModeExit({
|
|
|
|
|
servicesManager: _servicesManager,
|
|
|
|
|
commandsManager: _commandsManager,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2022-12-09 16:58:01 +01:00
|
|
|
|
|
|
|
|
// The service onModeExit calls must occur after the extension ones
|
|
|
|
|
// so that extension ones can store/restore data.
|
|
|
|
|
for (const service of Object.values(_servicesManager.services)) {
|
|
|
|
|
try {
|
|
|
|
|
service?.onModeExit?.();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.warn('onModeExit caught', e);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-04 11:11:23 +02:00
|
|
|
}
|
|
|
|
|
|
2019-08-13 21:36:46 +02:00
|
|
|
/**
|
|
|
|
|
* An array of extensions, or an array of arrays that contains extension
|
|
|
|
|
* configuration pairs.
|
|
|
|
|
*
|
|
|
|
|
* @param {Object[]} extensions - Array of extensions
|
|
|
|
|
*/
|
2023-02-10 20:30:56 +01:00
|
|
|
public registerExtensions = async (
|
|
|
|
|
extensions: (
|
|
|
|
|
| ExtensionRegister
|
|
|
|
|
| [ExtensionRegister, ExtensionConfiguration]
|
|
|
|
|
)[],
|
|
|
|
|
dataSources: unknown[] = []
|
|
|
|
|
): Promise<void> => {
|
2022-07-27 18:39:04 +02:00
|
|
|
// Todo: we ideally should be able to run registrations in parallel
|
|
|
|
|
// but currently since some extensions need to be registered before
|
|
|
|
|
// others, we need to run them sequentially. We need a postInit hook
|
|
|
|
|
// to avoid this sequential async registration
|
2023-02-17 21:04:07 +01:00
|
|
|
for (let i = 0; i < extensions.length; i++) {
|
|
|
|
|
const extension = extensions[i];
|
2019-08-13 21:36:46 +02:00
|
|
|
const hasConfiguration = Array.isArray(extension);
|
2022-07-27 18:39:04 +02:00
|
|
|
try {
|
|
|
|
|
if (hasConfiguration) {
|
2023-02-17 21:04:07 +01:00
|
|
|
// Important: for some reason in the line below the type
|
|
|
|
|
// of extension is not recognized as [ExtensionRegister,
|
|
|
|
|
// ExtensionConfiguration] by babel DON"T CHANGE IT
|
|
|
|
|
// Same for the for loop above don't use
|
|
|
|
|
// for (const extension of extensions)
|
|
|
|
|
const ohifExtension = extension[0];
|
|
|
|
|
const configuration = extension[1];
|
2022-07-27 18:39:04 +02:00
|
|
|
await this.registerExtension(
|
|
|
|
|
ohifExtension,
|
|
|
|
|
configuration,
|
|
|
|
|
dataSources
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
await this.registerExtension(extension, {}, dataSources);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
2019-08-13 21:36:46 +02:00
|
|
|
}
|
2022-07-27 18:39:04 +02:00
|
|
|
}
|
2020-05-09 20:23:43 +02:00
|
|
|
};
|
2019-08-13 21:36:46 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
2023-02-10 20:30:56 +01:00
|
|
|
public registerExtension = async (
|
|
|
|
|
extension: ExtensionRegister,
|
2022-07-27 18:39:04 +02:00
|
|
|
configuration = {},
|
|
|
|
|
dataSources = []
|
2023-02-10 20:30:56 +01:00
|
|
|
): Promise<void> => {
|
2019-08-13 21:36:46 +02:00
|
|
|
if (!extension) {
|
2021-05-28 20:32:48 +02:00
|
|
|
throw new Error('Attempting to register a null/undefined extension.');
|
2019-08-13 21:36:46 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-10 20:30:56 +01:00
|
|
|
const extensionId = extension.id;
|
2019-08-13 21:36:46 +02:00
|
|
|
|
|
|
|
|
if (!extensionId) {
|
2020-05-13 12:06:13 +02:00
|
|
|
// Note: Mode framework cannot function without IDs.
|
|
|
|
|
log.warn(extension);
|
|
|
|
|
throw new Error(`Extension ID not set`);
|
2019-08-13 21:36:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.registeredExtensionIds.includes(extensionId)) {
|
|
|
|
|
log.warn(
|
|
|
|
|
`Extension ID ${extensionId} has already been registered. Exiting before duplicating modules.`
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// preRegistrationHook
|
|
|
|
|
if (extension.preRegistration) {
|
2022-07-27 18:39:04 +02:00
|
|
|
await extension.preRegistration({
|
2019-11-14 15:50:37 +01:00
|
|
|
servicesManager: this._servicesManager,
|
2019-12-02 17:29:04 +01:00
|
|
|
commandsManager: this._commandsManager,
|
2020-08-19 21:02:59 +02:00
|
|
|
hotkeysManager: this._hotkeysManager,
|
2022-07-27 18:39:04 +02:00
|
|
|
extensionManager: this,
|
2019-12-16 20:07:53 +01:00
|
|
|
appConfig: this._appConfig,
|
2019-11-13 21:02:14 +01:00
|
|
|
configuration,
|
|
|
|
|
});
|
2019-08-13 21:36:46 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-03 19:18:59 +02:00
|
|
|
if (extension.onModeEnter) {
|
|
|
|
|
this._extensionLifeCycleHooks.onModeEnter[extensionId] =
|
|
|
|
|
extension.onModeEnter;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-04 11:11:23 +02:00
|
|
|
if (extension.onModeExit) {
|
|
|
|
|
this._extensionLifeCycleHooks.onModeExit[extensionId] =
|
|
|
|
|
extension.onModeExit;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-13 21:36:46 +02:00
|
|
|
// Register Modules
|
|
|
|
|
this.moduleTypeNames.forEach(moduleType => {
|
|
|
|
|
const extensionModule = this._getExtensionModule(
|
|
|
|
|
moduleType,
|
|
|
|
|
extension,
|
2019-12-16 20:07:53 +01:00
|
|
|
extensionId,
|
|
|
|
|
configuration
|
2019-08-13 21:36:46 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (extensionModule) {
|
2020-05-13 12:06:13 +02:00
|
|
|
switch (moduleType) {
|
|
|
|
|
case MODULE_TYPES.COMMANDS:
|
|
|
|
|
this._initCommandsModule(extensionModule);
|
|
|
|
|
break;
|
|
|
|
|
case MODULE_TYPES.DATA_SOURCE:
|
|
|
|
|
this._initDataSourcesModule(
|
|
|
|
|
extensionModule,
|
|
|
|
|
extensionId,
|
|
|
|
|
dataSources
|
|
|
|
|
);
|
|
|
|
|
break;
|
2022-09-21 05:40:26 +02:00
|
|
|
case MODULE_TYPES.HANGING_PROTOCOL:
|
|
|
|
|
this._initHangingProtocolsModule(extensionModule, extensionId);
|
2020-05-13 12:06:13 +02:00
|
|
|
case MODULE_TYPES.TOOLBAR:
|
2020-05-15 19:07:21 +02:00
|
|
|
case MODULE_TYPES.VIEWPORT:
|
2020-05-13 12:06:13 +02:00
|
|
|
case MODULE_TYPES.PANEL:
|
|
|
|
|
case MODULE_TYPES.SOP_CLASS_HANDLER:
|
|
|
|
|
case MODULE_TYPES.CONTEXT:
|
|
|
|
|
case MODULE_TYPES.LAYOUT_TEMPLATE:
|
2022-11-24 22:28:10 +01:00
|
|
|
case MODULE_TYPES.CUSTOMIZATION:
|
2023-02-10 20:30:56 +01:00
|
|
|
case MODULE_TYPES.STATE_SYNC:
|
2022-07-27 18:39:04 +02:00
|
|
|
case MODULE_TYPES.UTILITY:
|
2020-05-13 12:06:13 +02:00
|
|
|
// Default for most extension points,
|
|
|
|
|
// Just adds each entry ready for consumption by mode.
|
|
|
|
|
extensionModule.forEach(element => {
|
2023-03-31 17:58:48 +02:00
|
|
|
if (!element.name) {
|
|
|
|
|
throw new Error(
|
|
|
|
|
`Extension ID ${extensionId} module ${moduleType} element has no name`
|
|
|
|
|
);
|
|
|
|
|
}
|
2023-03-10 04:30:09 +01:00
|
|
|
const id = `${extensionId}.${moduleType}.${element.name}`;
|
|
|
|
|
element.id = id;
|
|
|
|
|
this.modulesMap[id] = element;
|
2020-05-13 12:06:13 +02:00
|
|
|
});
|
2020-05-15 19:07:21 +02:00
|
|
|
break;
|
2021-03-01 16:52:54 +01:00
|
|
|
default:
|
|
|
|
|
throw new Error(`Module type invalid: ${moduleType}`);
|
2020-05-13 12:06:13 +02:00
|
|
|
}
|
2019-08-13 21:36:46 +02:00
|
|
|
|
|
|
|
|
this.modules[moduleType].push({
|
|
|
|
|
extensionId,
|
|
|
|
|
module: extensionModule,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Track extension registration
|
|
|
|
|
this.registeredExtensionIds.push(extensionId);
|
2020-05-09 20:23:43 +02:00
|
|
|
};
|
2019-08-13 21:36:46 +02:00
|
|
|
|
2020-05-09 20:23:43 +02:00
|
|
|
getModuleEntry = stringEntry => {
|
2020-05-07 20:04:33 +02:00
|
|
|
return this.modulesMap[stringEntry];
|
2020-05-09 20:23:43 +02:00
|
|
|
};
|
2020-05-07 20:04:33 +02:00
|
|
|
|
2020-05-11 18:56:46 +02:00
|
|
|
getDataSources = dataSourceName => {
|
2020-06-05 17:36:11 +02:00
|
|
|
if (dataSourceName === undefined) {
|
2020-06-26 11:01:13 +02:00
|
|
|
// Default to the activeDataSource
|
2020-06-05 17:36:11 +02:00
|
|
|
dataSourceName = this.activeDataSource;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-09 10:57:52 +02:00
|
|
|
// Note: this currently uses the data source name, which feels weird...
|
2020-05-11 18:56:46 +02:00
|
|
|
return this.dataSourceMap[dataSourceName];
|
2020-05-09 20:23:43 +02:00
|
|
|
};
|
2020-05-07 20:04:33 +02:00
|
|
|
|
2020-06-26 11:01:13 +02:00
|
|
|
getActiveDataSource = () => {
|
2020-07-03 19:18:59 +02:00
|
|
|
return this.dataSourceMap[this.activeDataSource];
|
2020-06-26 11:01:13 +02:00
|
|
|
};
|
|
|
|
|
|
2021-05-28 20:32:48 +02:00
|
|
|
getDataSource = () => {
|
|
|
|
|
return this.dataSourceMap[this.activeDataSource];
|
|
|
|
|
};
|
|
|
|
|
|
2019-08-13 21:36:46 +02:00
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
* @param {string} moduleType
|
|
|
|
|
* @param {Object} extension
|
|
|
|
|
* @param {string} extensionId - Used for logging warnings
|
|
|
|
|
*/
|
2020-05-09 20:23:43 +02:00
|
|
|
_getExtensionModule = (moduleType, extension, extensionId, configuration) => {
|
2019-08-13 21:36:46 +02:00
|
|
|
const getModuleFnName = 'get' + _capitalizeFirstCharacter(moduleType);
|
|
|
|
|
const getModuleFn = extension[getModuleFnName];
|
|
|
|
|
|
|
|
|
|
if (!getModuleFn) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2023-03-22 22:45:28 +01:00
|
|
|
const extensionModule = extension[getModuleFnName]({
|
2020-06-15 03:18:29 +02:00
|
|
|
appConfig: this._appConfig,
|
2019-12-02 17:29:04 +01:00
|
|
|
commandsManager: this._commandsManager,
|
2020-06-15 03:18:29 +02:00
|
|
|
servicesManager: this._servicesManager,
|
2020-08-19 21:02:59 +02:00
|
|
|
hotkeysManager: this._hotkeysManager,
|
|
|
|
|
extensionManager: this,
|
2019-12-16 20:07:53 +01:00
|
|
|
configuration,
|
2019-11-14 23:29:40 +01:00
|
|
|
});
|
2019-08-13 21:36:46 +02:00
|
|
|
|
|
|
|
|
if (!extensionModule) {
|
|
|
|
|
log.warn(
|
|
|
|
|
`Null or undefined returned when registering the ${getModuleFnName} module for the ${extensionId} extension`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return extensionModule;
|
|
|
|
|
} catch (ex) {
|
2023-03-22 22:45:28 +01:00
|
|
|
console.log(ex);
|
2021-03-01 16:52:54 +01:00
|
|
|
throw new Error(
|
2019-08-13 21:36:46 +02:00
|
|
|
`Exception thrown while trying to call ${getModuleFnName} for the ${extensionId} extension`
|
|
|
|
|
);
|
|
|
|
|
}
|
2020-05-09 20:23:43 +02:00
|
|
|
};
|
2019-08-13 21:36:46 +02:00
|
|
|
|
2022-09-21 05:40:26 +02:00
|
|
|
_initHangingProtocolsModule = (extensionModule, extensionId) => {
|
2023-02-10 22:46:09 +01:00
|
|
|
const { hangingProtocolService } = this._servicesManager.services;
|
2023-03-31 17:58:48 +02:00
|
|
|
extensionModule.forEach(({ name, protocol }) => {
|
2022-10-05 14:32:54 +02:00
|
|
|
if (protocol) {
|
|
|
|
|
// Only auto-register if protocol specified, otherwise let mode register
|
2023-03-31 17:58:48 +02:00
|
|
|
hangingProtocolService.addProtocol(name, protocol);
|
2022-10-05 14:32:54 +02:00
|
|
|
}
|
2022-09-21 05:40:26 +02:00
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2021-03-01 16:52:54 +01:00
|
|
|
_initDataSourcesModule(extensionModule, extensionId, dataSources = []) {
|
2023-02-13 14:55:55 +01:00
|
|
|
const { userAuthenticationService } = this._servicesManager.services;
|
2022-12-29 16:13:06 +01:00
|
|
|
dataSources.forEach(dataSource => {
|
|
|
|
|
this.dataSourceDefs[dataSource.sourceName] = dataSource;
|
|
|
|
|
});
|
2021-06-23 20:41:27 +02:00
|
|
|
|
2020-05-13 12:06:13 +02:00
|
|
|
extensionModule.forEach(element => {
|
|
|
|
|
const namespace = `${extensionId}.${MODULE_TYPES.DATA_SOURCE}.${element.name}`;
|
|
|
|
|
|
|
|
|
|
dataSources.forEach(dataSource => {
|
|
|
|
|
if (dataSource.namespace === namespace) {
|
|
|
|
|
const dataSourceInstance = element.createDataSource(
|
2021-06-23 20:41:27 +02:00
|
|
|
dataSource.configuration,
|
2023-02-13 14:55:55 +01:00
|
|
|
userAuthenticationService
|
2020-05-13 12:06:13 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (this.dataSourceMap[dataSource.sourceName]) {
|
|
|
|
|
this.dataSourceMap[dataSource.sourceName].push(dataSourceInstance);
|
|
|
|
|
} else {
|
|
|
|
|
this.dataSourceMap[dataSource.sourceName] = [dataSourceInstance];
|
|
|
|
|
}
|
2019-08-13 21:36:46 +02:00
|
|
|
}
|
2020-05-13 12:06:13 +02:00
|
|
|
});
|
|
|
|
|
});
|
2020-05-09 10:57:52 +02:00
|
|
|
|
2020-05-13 12:06:13 +02:00
|
|
|
extensionModule.forEach(element => {
|
|
|
|
|
this.modulesMap[
|
|
|
|
|
`${extensionId}.${MODULE_TYPES.DATA_SOURCE}.${element.name}`
|
|
|
|
|
] = element;
|
|
|
|
|
});
|
|
|
|
|
}
|
2019-08-13 21:36:46 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @private
|
|
|
|
|
* @param {Object[]} commandDefinitions
|
|
|
|
|
*/
|
2020-05-13 12:06:13 +02:00
|
|
|
_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';
|
|
|
|
|
|
2019-08-13 21:36:46 +02:00
|
|
|
if (!this._commandsManager.getContext(defaultContext)) {
|
|
|
|
|
this._commandsManager.createContext(defaultContext);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-13 12:06:13 +02:00
|
|
|
Object.keys(definitions).forEach(commandName => {
|
|
|
|
|
const commandDefinition = definitions[commandName];
|
2019-08-13 21:36:46 +02:00
|
|
|
const commandHasContextThatDoesNotExist =
|
|
|
|
|
commandDefinition.context &&
|
|
|
|
|
!this._commandsManager.getContext(commandDefinition.context);
|
|
|
|
|
|
|
|
|
|
if (commandHasContextThatDoesNotExist) {
|
|
|
|
|
this._commandsManager.createContext(commandDefinition.context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this._commandsManager.registerCommand(
|
|
|
|
|
commandDefinition.context || defaultContext,
|
|
|
|
|
commandName,
|
|
|
|
|
commandDefinition
|
|
|
|
|
);
|
|
|
|
|
});
|
2020-05-09 20:23:43 +02:00
|
|
|
};
|
2019-08-13 21:36:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
* @param {string} lower
|
|
|
|
|
*/
|
|
|
|
|
function _capitalizeFirstCharacter(lower) {
|
2022-11-10 19:29:55 +01:00
|
|
|
return lower.charAt(0).toUpperCase() + lower.substring(1);
|
2019-08-13 21:36:46 +02:00
|
|
|
}
|