diff --git a/extensions/default/src/Components/DataSourceConfigurationComponent.tsx b/extensions/default/src/Components/DataSourceConfigurationComponent.tsx index dd61dc5517a..fdcfba4fbd4 100644 --- a/extensions/default/src/Components/DataSourceConfigurationComponent.tsx +++ b/extensions/default/src/Components/DataSourceConfigurationComponent.tsx @@ -3,11 +3,16 @@ import { useTranslation } from 'react-i18next'; import { Icon, useModal } from '@ohif/ui'; import { Types } from '@ohif/core'; import DataSourceConfigurationModalComponent from './DataSourceConfigurationModalComponent'; +import { + DataSourceConfigurationAPI, + GoogleCloudDataSourceConfigurationAPI, +} from '../DataSourceConfigurationAPI'; function DataSourceConfigurationComponent({ servicesManager, extensionManager, -}: withAppTypes): ReactElement { + type, +}: withAppTypes<{ type: string }>): ReactElement { const { t } = useTranslation('DataSourceConfiguration'); const { show, hide } = useModal(); @@ -23,14 +28,22 @@ function DataSourceConfigurationComponent({ const dataSourceChangedCallback = async () => { const activeDataSourceDef = extensionManager.getActiveDataSourceDefinition(); + const { dataSourceSelectionApi } = extensionManager.appConfig; - if (!activeDataSourceDef.configuration.configurationAPI) { + if (!activeDataSourceDef.configuration.configurationAPI && !dataSourceSelectionApi) { return; } - const { factory: configurationAPIFactory } = - customizationService.get(activeDataSourceDef.configuration.configurationAPI) ?? {}; - + let configurationAPIFactory: ( + sourceName: string + ) => DataSourceConfigurationAPI | GoogleCloudDataSourceConfigurationAPI; + if (type === 'sourceSelector') { + configurationAPIFactory = customizationService.get(dataSourceSelectionApi)?.factory; + } else { + configurationAPIFactory = customizationService.get( + activeDataSourceDef.configuration.configurationAPI + )?.factory; + } if (!configurationAPIFactory) { return; } diff --git a/extensions/default/src/DataSourceConfigurationAPI/DataSourceConfigurationAPI.ts b/extensions/default/src/DataSourceConfigurationAPI/DataSourceConfigurationAPI.ts new file mode 100644 index 00000000000..966baff6e24 --- /dev/null +++ b/extensions/default/src/DataSourceConfigurationAPI/DataSourceConfigurationAPI.ts @@ -0,0 +1,50 @@ +// PVR-447 show option to change data source from ui +import { ExtensionManager, Types } from '@ohif/core'; +class DataSourceConfigurationAPIItem implements Types.BaseDataSourceConfigurationAPIItem { + id: string; + name: string; +} + +class DataSourceConfigurationAPI implements Types.BaseDataSourceConfigurationAPI { + private _extensionManager: ExtensionManager; + + constructor(extensionManager) { + this._extensionManager = extensionManager; + } + + getItemLabels = () => ['Data Sources']; + + async initialize(): Promise { + const datasources = this._extensionManager.appConfig.dataSources.map(ds => { + return { + id: ds.sourceName, + name: ds.sourceName, + }; + }); + + return new Promise(resolve => resolve(datasources)); + } + + async setCurrentItem( + anItem: Types.BaseDataSourceConfigurationAPIItem + ): Promise { + return new Promise(resolve => { + if (anItem) { + this._extensionManager.setActiveDataSource(anItem.name); + } + this.initialize().then(items => resolve(items)); + }); + } + + async getConfiguredItems(): Promise> { + const activeDatasource = this._extensionManager.getActiveDataSourceDefinition(); + return [ + { + id: activeDatasource.sourceName, + name: activeDatasource.sourceName, + }, + ]; + } +} + +export { DataSourceConfigurationAPI }; diff --git a/extensions/default/src/DataSourceConfigurationAPI/index.ts b/extensions/default/src/DataSourceConfigurationAPI/index.ts new file mode 100644 index 00000000000..268c2a84f50 --- /dev/null +++ b/extensions/default/src/DataSourceConfigurationAPI/index.ts @@ -0,0 +1,4 @@ +import { DataSourceConfigurationAPI } from './DataSourceConfigurationAPI'; +import { GoogleCloudDataSourceConfigurationAPI } from './GoogleCloudDataSourceConfigurationAPI'; + +export { DataSourceConfigurationAPI, GoogleCloudDataSourceConfigurationAPI }; diff --git a/extensions/default/src/getCustomizationModule.tsx b/extensions/default/src/getCustomizationModule.tsx index bceeefdaf7c..dcb1c97a365 100644 --- a/extensions/default/src/getCustomizationModule.tsx +++ b/extensions/default/src/getCustomizationModule.tsx @@ -5,6 +5,7 @@ import { ProgressDropdownWithService } from './Components/ProgressDropdownWithSe import DataSourceConfigurationComponent from './Components/DataSourceConfigurationComponent'; import { GoogleCloudDataSourceConfigurationAPI } from './DataSourceConfigurationAPI/GoogleCloudDataSourceConfigurationAPI'; import { utils } from '@ohif/core'; +import { DataSourceConfigurationAPI } from './DataSourceConfigurationAPI'; const formatDate = utils.formatDate; @@ -147,6 +148,17 @@ export default function getCustomizationModule({ servicesManager, extensionManag component: DataSourceConfigurationComponent.bind(null, { servicesManager, extensionManager, + type: 'sourceConfigurationSelector', + }), + }, + + { + // the generic GUI component to change a data source using an instance of a BaseDataSourceConfigurationAPI + id: 'ohif.dataSourceSelectorComponent', + component: DataSourceConfigurationComponent.bind(null, { + servicesManager, + extensionManager, + type: 'sourceSelector', }), }, @@ -160,6 +172,11 @@ export default function getCustomizationModule({ servicesManager, extensionManag extensionManager ), }, + { + // The factory for creating an instance of a BaseDataSourceConfigurationAPI for selecting data source + id: 'ohif.dataSourceSelectionAPI', + factory: () => new DataSourceConfigurationAPI(extensionManager), + }, { id: 'progressDropdownWithServiceComponent', diff --git a/platform/app/public/config/default.js b/platform/app/public/config/default.js index 0e5443099fa..90d8a9d9a27 100644 --- a/platform/app/public/config/default.js +++ b/platform/app/public/config/default.js @@ -35,6 +35,7 @@ window.config = { // // regex: /(https:\/\/hospital.com(\/[0-9A-Za-z.]+)*)|(https:\/\/othersite.com(\/[0-9A-Za-z.]+)*)/ // regex: /.*/, // }, + dataSourceSelectionApi: 'ohif.dataSourceSelectionAPI', dataSources: [ { namespace: '@ohif/extension-default.dataSourcesModule.dicomweb', diff --git a/platform/app/src/routes/WorkList/WorkList.tsx b/platform/app/src/routes/WorkList/WorkList.tsx index 85864a03865..8075cad53cd 100644 --- a/platform/app/src/routes/WorkList/WorkList.tsx +++ b/platform/app/src/routes/WorkList/WorkList.tsx @@ -529,6 +529,8 @@ function WorkList({ const { component: dataSourceConfigurationComponent } = customizationService.get('ohif.dataSourceConfigurationComponent') ?? {}; + const { component: dataSourceSelectorComponent } = + customizationService.get('ohif.dataSourceSelectorComponent') ?? {}; return (
@@ -541,7 +543,7 @@ function WorkList({ /> -
+
dataSourceConfigurationComponent() : undefined } + getDataSourceSelectorComponent={ + dataSourceSelectorComponent ? () => dataSourceSelectorComponent() : undefined + } />
{hasStudies ? ( diff --git a/platform/docs/docs/configuration/dataSources/datasource-selector.md b/platform/docs/docs/configuration/dataSources/datasource-selector.md new file mode 100644 index 00000000000..d7d4ce0906b --- /dev/null +++ b/platform/docs/docs/configuration/dataSources/datasource-selector.md @@ -0,0 +1,32 @@ +## Data Source Selection + +The worklist page displays the selected datasource at the top. Users can easily switch between available data sources configured in the configuration file by clicking the icon next to the data source name. + +### UI Configuration + +You can customize the datasource selection UI through two configuration options: + +#### Datasource Selection API +- **Customization Module Key**: `ohif.dataSourceSelectionAPI` +- **Purpose**: Defines the API used for datasource selection. This is an implementation of the interface `BaseDataSourceConfigurationAPI` +- **Usage**: Provide a custom implementation to control what datasources are retrieved and managed + +#### Datasource Selector Component +- **Customization Module Key**: `ohif.dataSourceSelectorComponent` +- **Purpose**: Specifies the component used for displaying and interacting with datasource selection +- **Usage**: UI component that shows the selected data source and the list of selectable data sources + +Example configuration: +```javascript +{ + id: 'ohif.dataSourceSelectionAPI', + factory: () => new DataSourceConfigurationAPI(extensionManager), +}, +{ + id: 'ohif.dataSourceSelectorComponent', + component: DataSourceConfigurationComponent.bind(null, { + servicesManager, + extensionManager, + type: 'sourceSelector', + }), +} diff --git a/platform/ui/src/components/StudyListFilter/StudyListFilter.tsx b/platform/ui/src/components/StudyListFilter/StudyListFilter.tsx index ed2ae4a4f60..8a01bb355ee 100644 --- a/platform/ui/src/components/StudyListFilter/StudyListFilter.tsx +++ b/platform/ui/src/components/StudyListFilter/StudyListFilter.tsx @@ -16,6 +16,7 @@ const StudyListFilter = ({ numOfStudies, onUploadClick, getDataSourceConfigurationComponent, + getDataSourceSelectorComponent, }) => { const { t } = useTranslation('StudyList'); const { sortBy, sortDirection } = filterValues; @@ -41,6 +42,7 @@ const StudyListFilter = ({ > {t('StudyList')} + {getDataSourceSelectorComponent && getDataSourceSelectorComponent()} {getDataSourceConfigurationComponent && getDataSourceConfigurationComponent()} {onUploadClick && (