feat(DataSource): Allow for dynamic data source configuration and creation (#3543)
This commit is contained in:
1 parent
6d88978710
commit
7bbc213f58
36 files changed
+640
-298
No files matched your search
@@ -22,6 +22,7 @@ function create({
|
||||
getImageIdsForDisplaySet,
|
||||
getImageIdsForInstance,
|
||||
getConfig,
|
||||
getStudyInstanceUIDs,
|
||||
}) {
|
||||
const defaultQuery = {
|
||||
studies: {
|
||||
@@ -73,6 +74,7 @@ function create({
|
||||
getImageIdsForDisplaySet,
|
||||
getImageIdsForInstance,
|
||||
getConfig: getConfig || defaultGetConfig,
|
||||
getStudyInstanceUIDs: getStudyInstanceUIDs,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import MODULE_TYPES from './MODULE_TYPES';
|
||||
import log from '../log';
|
||||
import { AppConfig } from '../types/AppConfig';
|
||||
import { ServicesManager } from '../services';
|
||||
import { PubSubService, ServicesManager } from '../services';
|
||||
import { HotkeysManager, CommandsManager } from '../classes';
|
||||
import { DataSourceDefinition } from '../types';
|
||||
|
||||
/**
|
||||
* This is the arguments given to create the extension.
|
||||
@@ -57,7 +58,11 @@ export type CommandsModule = {
|
||||
defaultContext?: string;
|
||||
};
|
||||
|
||||
export default class ExtensionManager {
|
||||
export default class ExtensionManager extends PubSubService {
|
||||
public static readonly EVENTS = {
|
||||
ACTIVE_DATA_SOURCE_CHANGED: 'event::activedatasourcechanged',
|
||||
};
|
||||
|
||||
private _commandsManager: CommandsManager;
|
||||
private _servicesManager: ServicesManager;
|
||||
private _hotkeysManager: HotkeysManager;
|
||||
@@ -68,6 +73,7 @@ export default class ExtensionManager {
|
||||
hotkeysManager,
|
||||
appConfig = {},
|
||||
}: ExtensionConstructor) {
|
||||
super(ExtensionManager.EVENTS);
|
||||
this.modules = {};
|
||||
this.registeredExtensionIds = [];
|
||||
this.moduleTypeNames = Object.values(MODULE_TYPES);
|
||||
@@ -85,11 +91,20 @@ export default class ExtensionManager {
|
||||
this.dataSourceMap = {};
|
||||
this.dataSourceDefs = {};
|
||||
this.defaultDataSourceName = appConfig.defaultDataSourceName;
|
||||
this.activeDataSource = undefined;
|
||||
this.activeDataSource = appConfig.defaultDataSourceName;
|
||||
}
|
||||
|
||||
public setActiveDataSource(dataSourceName: string): void {
|
||||
this.activeDataSource = dataSourceName;
|
||||
public setActiveDataSource(dataSource: string): void {
|
||||
if (this.activeDataSource === dataSource) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.activeDataSource = dataSource;
|
||||
|
||||
this._broadcastEvent(
|
||||
ExtensionManager.EVENTS.ACTIVE_DATA_SOURCE_CHANGED,
|
||||
this.dataSourceDefs[this.activeDataSource]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -330,8 +345,20 @@ export default class ExtensionManager {
|
||||
return this.dataSourceMap[this.activeDataSource];
|
||||
};
|
||||
|
||||
getDataSource = () => {
|
||||
return this.dataSourceMap[this.activeDataSource];
|
||||
/**
|
||||
* Gets the data source definition for the given data source name.
|
||||
* If no data source name is provided, the active data source definition is
|
||||
* returned.
|
||||
* @param dataSourceName the data source name
|
||||
* @returns the data source definition
|
||||
*/
|
||||
getDataSourceDef = dataSourceName => {
|
||||
if (dataSourceName === undefined) {
|
||||
// Default to the activeDataSource
|
||||
dataSourceName = this.activeDataSource;
|
||||
}
|
||||
|
||||
return this.dataSourceDefs[dataSourceName];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -383,10 +410,92 @@ export default class ExtensionManager {
|
||||
});
|
||||
};
|
||||
|
||||
_initDataSourcesModule(extensionModule, extensionId, dataSources = []) {
|
||||
/**
|
||||
* Adds the given data source and optionally sets it as the active data source.
|
||||
* The method does this by first creating the data source.
|
||||
* @param dataSourceDef the data source definition to be added
|
||||
* @param activate flag to indicate if the added data source should be set to the active data source
|
||||
*/
|
||||
addDataSource(
|
||||
dataSourceDef: DataSourceDefinition,
|
||||
options = { activate: false }
|
||||
) {
|
||||
const existingDataSource = this.getDataSources(dataSourceDef.sourceName);
|
||||
if (existingDataSource?.[0]) {
|
||||
// The data source already exists and cannot be added.
|
||||
return;
|
||||
}
|
||||
|
||||
this._createDataSourceInstance(dataSourceDef);
|
||||
|
||||
if (options.activate) {
|
||||
this.setActiveDataSource(dataSourceDef.sourceName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the configuration of the given data source name. It first creates a new data source with
|
||||
* the existing definition and the new configuration passed in.
|
||||
* @param dataSourceName the name of the data source to update
|
||||
* @param dataSourceConfiguration the new configuration to update the data source with
|
||||
*/
|
||||
updateDataSourceConfiguration(
|
||||
dataSourceName: string,
|
||||
dataSourceConfiguration: any
|
||||
) {
|
||||
const existingDataSource = this.getDataSources(dataSourceName);
|
||||
if (!existingDataSource?.[0]) {
|
||||
// Cannot update a non existent data source.
|
||||
return;
|
||||
}
|
||||
|
||||
const dataSourceDef = this.dataSourceDefs[dataSourceName];
|
||||
// Update the configuration.
|
||||
dataSourceDef.configuration = dataSourceConfiguration;
|
||||
this._createDataSourceInstance(dataSourceDef);
|
||||
|
||||
if (this.activeDataSource === dataSourceName) {
|
||||
// When the active data source is changed/set, fire an event to indicate that its configuration has changed.
|
||||
this._broadcastEvent(
|
||||
ExtensionManager.EVENTS.ACTIVE_DATA_SOURCE_CHANGED,
|
||||
dataSourceDef
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a data source instance from the given definition. The definition is
|
||||
* added to dataSourceDefs and the created instance is added to dataSourceMap.
|
||||
* @param dataSourceDef
|
||||
* @returns
|
||||
*/
|
||||
_createDataSourceInstance(dataSourceDef: DataSourceDefinition) {
|
||||
const module = this.getModuleEntry(dataSourceDef.namespace);
|
||||
|
||||
if (!module) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dataSourceDefs[dataSourceDef.sourceName] = dataSourceDef;
|
||||
|
||||
const { userAuthenticationService } = this._servicesManager.services;
|
||||
dataSources.forEach(dataSource => {
|
||||
this.dataSourceDefs[dataSource.sourceName] = dataSource;
|
||||
const dataSourceInstance = module.createDataSource(
|
||||
dataSourceDef.configuration,
|
||||
userAuthenticationService
|
||||
);
|
||||
|
||||
this.dataSourceMap[dataSourceDef.sourceName] = [dataSourceInstance];
|
||||
}
|
||||
|
||||
_initDataSourcesModule(
|
||||
extensionModule,
|
||||
extensionId,
|
||||
dataSources: Array<DataSourceDefinition> = []
|
||||
): void {
|
||||
extensionModule.forEach(element => {
|
||||
this.modulesMap[
|
||||
`${extensionId}.${MODULE_TYPES.DATA_SOURCE}.${element.name}`
|
||||
] = element;
|
||||
});
|
||||
|
||||
extensionModule.forEach(element => {
|
||||
@@ -394,25 +503,10 @@ export default class ExtensionManager {
|
||||
|
||||
dataSources.forEach(dataSource => {
|
||||
if (dataSource.namespace === namespace) {
|
||||
const dataSourceInstance = element.createDataSource(
|
||||
dataSource.configuration,
|
||||
userAuthenticationService
|
||||
);
|
||||
|
||||
if (this.dataSourceMap[dataSource.sourceName]) {
|
||||
this.dataSourceMap[dataSource.sourceName].push(dataSourceInstance);
|
||||
} else {
|
||||
this.dataSourceMap[dataSource.sourceName] = [dataSourceInstance];
|
||||
}
|
||||
this.addDataSource(dataSource);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
extensionModule.forEach(element => {
|
||||
this.modulesMap[
|
||||
`${extensionId}.${MODULE_TYPES.DATA_SOURCE}.${element.name}`
|
||||
] = element;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
export type DataSourceDefinition = {
|
||||
// TODO friendlyName to move to configuration; here now for legacy purposes
|
||||
friendlyName: string;
|
||||
namespace: string;
|
||||
sourceName: string;
|
||||
configuration: any;
|
||||
};
|
||||
@@ -3,6 +3,7 @@ import * as HangingProtocol from './HangingProtocol';
|
||||
import Services from './Services';
|
||||
import Hotkey from '../classes/Hotkey';
|
||||
import { DisplaySet } from '../services/DisplaySetService/DisplaySetService';
|
||||
import { DataSourceDefinition } from './DataSource';
|
||||
|
||||
export * from '../services/CustomizationService/types';
|
||||
// Separate out some generic types
|
||||
@@ -18,4 +19,11 @@ export * from './Color';
|
||||
* Export the types used within the various services and managers, but
|
||||
* not the services/managers themselves, which are exported at the top level.
|
||||
*/
|
||||
export { Extensions, HangingProtocol, Services, Hotkey, DisplaySet };
|
||||
export {
|
||||
Extensions,
|
||||
HangingProtocol,
|
||||
Services,
|
||||
Hotkey,
|
||||
DisplaySet,
|
||||
DataSourceDefinition,
|
||||
};
|
||||
Reference in new issue
Block a user