feat: Add customization support for more UI components (#4634)

Co-authored-by: ashikcn <ashik@L1140.trenser.com>
Co-authored-by: Devu Jayalekshmi <devu.jayalekshmi@trenser.com>
Co-authored-by: Arul Mozhi <arul.mozhi@trenser.com>
This commit is contained in:
Abhijith Sb 2025-02-03 19:48:00 +05:30 committed by GitHub
parent 8f79ebafd9
commit f15eb44b4c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 288 additions and 33 deletions

View File

@ -1,6 +1,5 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import { LoadingIndicatorTotalPercent } from '@ohif/ui';
import { useViewportGrid } from '@ohif/ui-next'; import { useViewportGrid } from '@ohif/ui-next';
function OHIFCornerstonePMAPViewport(props: withAppTypes) { function OHIFCornerstonePMAPViewport(props: withAppTypes) {
@ -13,7 +12,7 @@ function OHIFCornerstonePMAPViewport(props: withAppTypes) {
extensionManager, extensionManager,
} = props; } = props;
const viewportId = viewportOptions.viewportId; const viewportId = viewportOptions.viewportId;
const { displaySetService, segmentationService, uiNotificationService } = const { displaySetService, segmentationService, uiNotificationService, customizationService } =
servicesManager.services; servicesManager.services;
// PMAP viewport will always have a single display set // PMAP viewport will always have a single display set
@ -21,6 +20,10 @@ function OHIFCornerstonePMAPViewport(props: withAppTypes) {
throw new Error('PMAP viewport must have a single display set'); throw new Error('PMAP viewport must have a single display set');
} }
const LoadingIndicatorTotalPercent = customizationService.getCustomization(
'ui.loadingIndicatorTotalPercent'
);
const pmapDisplaySet = displaySets[0]; const pmapDisplaySet = displaySets[0];
const [viewportGrid, viewportGridService] = useViewportGrid(); const [viewportGrid, viewportGridService] = useViewportGrid();
const referencedDisplaySetRef = useRef(null); const referencedDisplaySetRef = useRef(null);

View File

@ -1,6 +1,6 @@
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { LoadingIndicatorTotalPercent, ViewportActionArrows } from '@ohif/ui'; import { ViewportActionArrows } from '@ohif/ui';
import { useViewportGrid } from '@ohif/ui-next'; import { useViewportGrid } from '@ohif/ui-next';
import promptHydrateRT from '../utils/promptHydrateRT'; import promptHydrateRT from '../utils/promptHydrateRT';
@ -39,6 +39,10 @@ function OHIFCornerstoneRTViewport(props: withAppTypes) {
throw new Error('RT viewport should only have a single display set'); throw new Error('RT viewport should only have a single display set');
} }
const LoadingIndicatorTotalPercent = customizationService.getCustomization(
'ui.loadingIndicatorTotalPercent'
);
const rtDisplaySet = displaySets[0]; const rtDisplaySet = displaySets[0];
const [viewportGrid, viewportGridService] = useViewportGrid(); const [viewportGrid, viewportGridService] = useViewportGrid();

View File

@ -1,6 +1,6 @@
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { LoadingIndicatorTotalPercent, ViewportActionArrows } from '@ohif/ui'; import { ViewportActionArrows } from '@ohif/ui';
import { useViewportGrid } from '@ohif/ui-next'; import { useViewportGrid } from '@ohif/ui-next';
import createSEGToolGroupAndAddTools from '../utils/initSEGToolGroup'; import createSEGToolGroupAndAddTools from '../utils/initSEGToolGroup';
import promptHydrateSEG from '../utils/promptHydrateSEG'; import promptHydrateSEG from '../utils/promptHydrateSEG';
@ -31,6 +31,10 @@ function OHIFCornerstoneSEGViewport(props: withAppTypes) {
viewportActionCornersService, viewportActionCornersService,
} = servicesManager.services; } = servicesManager.services;
const LoadingIndicatorTotalPercent = customizationService.getCustomization(
'ui.loadingIndicatorTotalPercent'
);
const toolGroupId = `${SEG_TOOLGROUP_BASE_NAME}-${viewportId}`; const toolGroupId = `${SEG_TOOLGROUP_BASE_NAME}-${viewportId}`;
// SEG viewport will always have a single display set // SEG viewport will always have a single display set

View File

@ -208,8 +208,9 @@ function commandsModule({
*/ */
setMeasurementLabel: ({ uid }) => { setMeasurementLabel: ({ uid }) => {
const labelConfig = customizationService.getCustomization('measurementLabels'); const labelConfig = customizationService.getCustomization('measurementLabels');
const renderContent = customizationService.getCustomization('ui.labellingComponent');
const measurement = measurementService.getMeasurement(uid); const measurement = measurementService.getMeasurement(uid);
showLabelAnnotationPopup(measurement, uiDialogService, labelConfig).then( showLabelAnnotationPopup(measurement, uiDialogService, labelConfig, renderContent).then(
(val: Map<any, any>) => { (val: Map<any, any>) => {
measurementService.update( measurementService.update(
uid, uid,
@ -325,8 +326,10 @@ function commandsModule({
renameMeasurement: ({ uid }) => { renameMeasurement: ({ uid }) => {
const labelConfig = customizationService.getCustomization('measurementLabels'); const labelConfig = customizationService.getCustomization('measurementLabels');
const renderContent = customizationService.getCustomization('ui.labellingComponent');
const measurement = measurementService.getMeasurement(uid); const measurement = measurementService.getMeasurement(uid);
showLabelAnnotationPopup(measurement, uiDialogService, labelConfig).then(val => { showLabelAnnotationPopup(measurement, uiDialogService, labelConfig, renderContent).then(
val => {
measurementService.update( measurementService.update(
uid, uid,
{ {
@ -334,7 +337,8 @@ function commandsModule({
}, },
true true
); );
}); }
);
}, },
toggleLockMeasurement: ({ uid }) => { toggleLockMeasurement: ({ uid }) => {
@ -376,7 +380,8 @@ function commandsModule({
}, },
arrowTextCallback: ({ callback, data, uid }) => { arrowTextCallback: ({ callback, data, uid }) => {
const labelConfig = customizationService.getCustomization('measurementLabels'); const labelConfig = customizationService.getCustomization('measurementLabels');
callLabelAutocompleteDialog(uiDialogService, callback, {}, labelConfig); const renderContent = customizationService.getCustomization('ui.labellingComponent');
callLabelAutocompleteDialog(uiDialogService, callback, {}, labelConfig, renderContent);
}, },
toggleCine: () => { toggleCine: () => {
const { viewports } = viewportGridService.getState(); const { viewports } = viewportGridService.getState();

View File

@ -1,6 +1,7 @@
import React, { useCallback, useEffect, useRef, useState, ReactElement } from 'react'; import React, { useCallback, useEffect, useRef, useState, ReactElement } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Button, ProgressLoadingBar } from '@ohif/ui'; import { useSystem } from '@ohif/core';
import { Button } from '@ohif/ui';
import { Icons } from '@ohif/ui-next'; import { Icons } from '@ohif/ui-next';
import DicomFileUploader, { import DicomFileUploader, {
EVENTS, EVENTS,
@ -40,6 +41,11 @@ function DicomUploadProgress({
dicomFileUploaderArr, dicomFileUploaderArr,
onComplete, onComplete,
}: DicomUploadProgressProps): ReactElement { }: DicomUploadProgressProps): ReactElement {
const { servicesManager } = useSystem();
const ProgressLoadingBar =
servicesManager.services.customizationService.getCustomization('ui.progressLoadingBar');
const [totalUploadSize] = useState( const [totalUploadSize] = useState(
dicomFileUploaderArr.reduce((acc, fileUploader) => acc + fileUploader.getFileSize(), 0) dicomFileUploaderArr.reduce((acc, fileUploader) => acc + fileUploader.getFileSize(), 0)
); );

View File

@ -1,14 +1,16 @@
import React from 'react'; import React from 'react';
import { useViewportActionCornersContext } from '../contextProviders/ViewportActionCornersProvider'; import { useViewportActionCornersContext } from '../contextProviders/ViewportActionCornersProvider';
import { ViewportActionCorners } from '@ohif/ui'; import { useSystem } from '@ohif/core';
export type OHIFViewportActionCornersProps = { export type OHIFViewportActionCornersProps = {
viewportId: string; viewportId: string;
}; };
function OHIFViewportActionCorners({ viewportId }: OHIFViewportActionCornersProps) { function OHIFViewportActionCorners({ viewportId }: OHIFViewportActionCornersProps) {
const { servicesManager } = useSystem();
const [viewportActionCornersState] = useViewportActionCornersContext(); const [viewportActionCornersState] = useViewportActionCornersContext();
const ViewportActionCorners =
servicesManager.services.customizationService.getCustomization('ui.viewportActionCorner');
if (!viewportActionCornersState[viewportId]) { if (!viewportActionCornersState[viewportId]) {
return null; return null;
} }

View File

@ -1,7 +1,8 @@
import classNames from 'classnames'; import classNames from 'classnames';
import React, { ReactElement, useEffect, useState } from 'react'; import React, { ReactElement, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Button, InputFilterText, LoadingIndicatorProgress } from '@ohif/ui'; import { useSystem } from '@ohif/core';
import { Button, InputFilterText } from '@ohif/ui';
import { Icons } from '@ohif/ui-next'; import { Icons } from '@ohif/ui-next';
import { Types } from '@ohif/core'; import { Types } from '@ohif/core';
@ -16,6 +17,7 @@ function ItemListComponent({
itemList, itemList,
onItemClicked, onItemClicked,
}: ItemListComponentProps): ReactElement { }: ItemListComponentProps): ReactElement {
const { servicesManager } = useSystem();
const { t } = useTranslation('DataSourceConfiguration'); const { t } = useTranslation('DataSourceConfiguration');
const [filterValue, setFilterValue] = useState(''); const [filterValue, setFilterValue] = useState('');
@ -23,6 +25,10 @@ function ItemListComponent({
setFilterValue(''); setFilterValue('');
}, [itemList]); }, [itemList]);
const LoadingIndicatorProgress = servicesManager.services.customizationService.getCustomization(
'ui.loadingIndicatorProgress'
);
return ( return (
<div className="flex min-h-[1px] grow flex-col gap-4"> <div className="flex min-h-[1px] grow flex-col gap-4">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">

View File

@ -1,5 +1,4 @@
import * as ContextMenuItemsBuilder from './ContextMenuItemsBuilder'; import * as ContextMenuItemsBuilder from './ContextMenuItemsBuilder';
import ContextMenu from '../../../../platform/ui/src/components/ContextMenu/ContextMenu';
import { CommandsManager } from '@ohif/core'; import { CommandsManager } from '@ohif/core';
import { annotation as CsAnnotation } from '@cornerstonejs/tools'; import { annotation as CsAnnotation } from '@cornerstonejs/tools';
import { Menu, MenuItem, Point, ContextMenuProps } from './types'; import { Menu, MenuItem, Point, ContextMenuProps } from './types';
@ -72,6 +71,8 @@ export default class ContextMenuController {
menuId menuId
); );
const ContextMenu = this.services.customizationService.getCustomization('ui.contextMenu');
this.services.uiDialogService.dismiss({ id: 'context-menu' }); this.services.uiDialogService.dismiss({ id: 'context-menu' });
this.services.uiDialogService.create({ this.services.uiDialogService.create({
id: 'context-menu', id: 'context-menu',

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState, useCallback } from 'react'; import React, { useEffect, useState, useCallback } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { LoadingIndicatorProgress, InvestigationalUseDialog } from '@ohif/ui'; import { InvestigationalUseDialog } from '@ohif/ui';
import { HangingProtocolService, CommandsManager } from '@ohif/core'; import { HangingProtocolService, CommandsManager } from '@ohif/core';
import { useAppConfig } from '@state'; import { useAppConfig } from '@state';
import ViewerHeader from './ViewerHeader'; import ViewerHeader from './ViewerHeader';
@ -27,7 +27,7 @@ function ViewerLayout({
}: withAppTypes): React.FunctionComponent { }: withAppTypes): React.FunctionComponent {
const [appConfig] = useAppConfig(); const [appConfig] = useAppConfig();
const { panelService, hangingProtocolService } = servicesManager.services; const { panelService, hangingProtocolService, customizationService } = servicesManager.services;
const [showLoadingIndicator, setShowLoadingIndicator] = useState(appConfig.showLoadingIndicator); const [showLoadingIndicator, setShowLoadingIndicator] = useState(appConfig.showLoadingIndicator);
const hasPanels = useCallback( const hasPanels = useCallback(
@ -55,6 +55,10 @@ function ViewerLayout({
setRightPanelClosed setRightPanelClosed
); );
const LoadingIndicatorProgress = customizationService.getCustomization(
'ui.loadingIndicatorProgress'
);
/** /**
* Set body classes (tailwindcss) that don't allow vertical * Set body classes (tailwindcss) that don't allow vertical
* or horizontal overflow (no scrolling). Also guarantee window * or horizontal overflow (no scrolling). Also guarantee window

View File

@ -0,0 +1,5 @@
import { ContextMenu } from '@ohif/ui';
export default {
'ui.contextMenu': ContextMenu,
};

View File

@ -0,0 +1,5 @@
import { LabellingFlow } from '@ohif/ui';
export default {
'ui.labellingComponent': LabellingFlow,
};

View File

@ -0,0 +1,5 @@
import { LoadingIndicatorProgress } from '@ohif/ui';
export default {
'ui.loadingIndicatorProgress': LoadingIndicatorProgress,
};

View File

@ -0,0 +1,5 @@
import { LoadingIndicatorTotalPercent } from '@ohif/ui';
export default {
'ui.loadingIndicatorTotalPercent': LoadingIndicatorTotalPercent,
};

View File

@ -0,0 +1,5 @@
import { ProgressLoadingBar } from '@ohif/ui';
export default {
'ui.progressLoadingBar': ProgressLoadingBar,
};

View File

@ -0,0 +1,5 @@
import { ViewportActionCorners } from '@ohif/ui';
export default {
'ui.viewportActionCorner': ViewportActionCorners,
};

View File

@ -6,11 +6,17 @@ import customRoutesCustomization from './customizations/customRoutesCustomizatio
import studyBrowserCustomization from './customizations/studyBrowserCustomization'; import studyBrowserCustomization from './customizations/studyBrowserCustomization';
import overlayItemCustomization from './customizations/overlayItemCustomization'; import overlayItemCustomization from './customizations/overlayItemCustomization';
import contextMenuCustomization from './customizations/contextMenuCustomization'; import contextMenuCustomization from './customizations/contextMenuCustomization';
import contextMenuUICustomization from './customizations/contextMenuUICustomization';
import menuContentCustomization from './customizations/menuContentCustomization'; import menuContentCustomization from './customizations/menuContentCustomization';
import getDataSourceConfigurationCustomization from './customizations/dataSourceConfigurationCustomization'; import getDataSourceConfigurationCustomization from './customizations/dataSourceConfigurationCustomization';
import progressDropdownCustomization from './customizations/progressDropdownCustomization'; import progressDropdownCustomization from './customizations/progressDropdownCustomization';
import sortingCriteriaCustomization from './customizations/sortingCriteriaCustomization'; import sortingCriteriaCustomization from './customizations/sortingCriteriaCustomization';
import onDropHandlerCustomization from './customizations/onDropHandlerCustomization'; import onDropHandlerCustomization from './customizations/onDropHandlerCustomization';
import loadingIndicatorProgressCustomization from './customizations/loadingIndicatorProgressCustomization';
import loadingIndicatorTotalPercentCustomization from './customizations/loadingIndicatorTotalPercentCustomization';
import progressLoadingBarCustomization from './customizations/progressLoadingBarCustomization';
import viewportActionCornersCustomization from './customizations/viewportActionCornersCustomization';
import labellingFlowCustomization from './customizations/labellingFlowCustomization';
/** /**
* *
@ -48,6 +54,12 @@ export default function getCustomizationModule({ servicesManager, extensionManag
...sortingCriteriaCustomization, ...sortingCriteriaCustomization,
...defaultContextMenuCustomization, ...defaultContextMenuCustomization,
...onDropHandlerCustomization, ...onDropHandlerCustomization,
...loadingIndicatorProgressCustomization,
...loadingIndicatorTotalPercentCustomization,
...progressLoadingBarCustomization,
...viewportActionCornersCustomization,
...labellingFlowCustomization,
...contextMenuUICustomization,
}, },
}, },
]; ];

View File

@ -89,7 +89,13 @@ export function callInputDialog(
} }
} }
export function callLabelAutocompleteDialog(uiDialogService, callback, dialogConfig, labelConfig) { export function callLabelAutocompleteDialog(
uiDialogService,
callback,
dialogConfig,
labelConfig,
renderContent = LabellingFlow
) {
const exclusive = labelConfig ? labelConfig.exclusive : false; const exclusive = labelConfig ? labelConfig.exclusive : false;
const dropDownItems = labelConfig ? labelConfig.items : []; const dropDownItems = labelConfig ? labelConfig.items : [];
@ -112,7 +118,7 @@ export function callLabelAutocompleteDialog(uiDialogService, callback, dialogCon
centralize: true, centralize: true,
isDraggable: false, isDraggable: false,
showOverlay: true, showOverlay: true,
content: LabellingFlow, content: renderContent,
contentProps: { contentProps: {
labellingDoneCallback: labellingDoneCallback, labellingDoneCallback: labellingDoneCallback,
measurementData: { label: '' }, measurementData: { label: '' },
@ -123,7 +129,12 @@ export function callLabelAutocompleteDialog(uiDialogService, callback, dialogCon
}); });
} }
export function showLabelAnnotationPopup(measurement, uiDialogService, labelConfig) { export function showLabelAnnotationPopup(
measurement,
uiDialogService,
labelConfig,
renderContent = LabellingFlow
) {
const exclusive = labelConfig ? labelConfig.exclusive : false; const exclusive = labelConfig ? labelConfig.exclusive : false;
const dropDownItems = labelConfig ? labelConfig.items : []; const dropDownItems = labelConfig ? labelConfig.items : [];
return new Promise<Map<any, any>>((resolve, reject) => { return new Promise<Map<any, any>>((resolve, reject) => {
@ -139,7 +150,7 @@ export function showLabelAnnotationPopup(measurement, uiDialogService, labelConf
id: 'select-annotation', id: 'select-annotation',
isDraggable: false, isDraggable: false,
showOverlay: true, showOverlay: true,
content: LabellingFlow, content: renderContent,
defaultPosition: { defaultPosition: {
x: window.innerWidth / 2, x: window.innerWidth / 2,
y: window.innerHeight / 2, y: window.innerHeight / 2,

View File

@ -5,11 +5,13 @@ function promptLabelAnnotation({ servicesManager }, ctx, evt) {
const { viewportId, StudyInstanceUID, SeriesInstanceUID, measurementId } = evt; const { viewportId, StudyInstanceUID, SeriesInstanceUID, measurementId } = evt;
return new Promise(async function (resolve) { return new Promise(async function (resolve) {
const labelConfig = customizationService.getCustomization('measurementLabels'); const labelConfig = customizationService.getCustomization('measurementLabels');
const renderContent = customizationService.getCustomization('ui.labellingComponent');
const measurement = measurementService.getMeasurement(measurementId); const measurement = measurementService.getMeasurement(measurementId);
const value = await showLabelAnnotationPopup( const value = await showLabelAnnotationPopup(
measurement, measurement,
servicesManager.services.uiDialogService, servicesManager.services.uiDialogService,
labelConfig labelConfig,
renderContent
); );
measurementService.update( measurementService.update(

View File

@ -1,6 +1,5 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { LoadingIndicatorProgress } from '@ohif/ui';
import { cleanDenaturalizedDataset } from '@ohif/extension-default'; import { cleanDenaturalizedDataset } from '@ohif/extension-default';
import './DicomMicroscopyViewport.css'; import './DicomMicroscopyViewport.css';
@ -8,6 +7,7 @@ import ViewportOverlay from './components/ViewportOverlay';
import getDicomWebClient from './utils/dicomWebClient'; import getDicomWebClient from './utils/dicomWebClient';
import dcmjs from 'dcmjs'; import dcmjs from 'dcmjs';
import MicroscopyService from './services/MicroscopyService'; import MicroscopyService from './services/MicroscopyService';
import { CustomizationService } from '@ohif/core';
class DicomMicroscopyViewport extends Component { class DicomMicroscopyViewport extends Component {
state = { state = {
@ -16,6 +16,7 @@ class DicomMicroscopyViewport extends Component {
}; };
microscopyService: MicroscopyService; microscopyService: MicroscopyService;
customizationService: CustomizationService;
viewer: any = null; // dicom-microscopy-viewer instance viewer: any = null; // dicom-microscopy-viewer instance
managedViewer: any = null; // managed wrapper of microscopy-dicom extension managedViewer: any = null; // managed wrapper of microscopy-dicom extension
@ -25,8 +26,9 @@ class DicomMicroscopyViewport extends Component {
constructor(props: any) { constructor(props: any) {
super(props); super(props);
const { microscopyService } = this.props.servicesManager.services; const { microscopyService, customizationService } = this.props.servicesManager.services;
this.microscopyService = microscopyService; this.microscopyService = microscopyService;
this.customizationService = customizationService;
} }
static propTypes = { static propTypes = {
@ -49,7 +51,6 @@ class DicomMicroscopyViewport extends Component {
resizeRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.any })]), resizeRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.any })]),
}; };
/** /**
* Get the nearest ROI from the mouse click point * Get the nearest ROI from the mouse click point
* *
@ -272,6 +273,9 @@ class DicomMicroscopyViewport extends Component {
const style = { width: '100%', height: '100%' }; const style = { width: '100%', height: '100%' };
const displaySet = this.props.displaySets[0]; const displaySet = this.props.displaySets[0];
const firstInstance = displaySet.firstInstance || displaySet.instance; const firstInstance = displaySet.firstInstance || displaySet.instance;
const LoadingIndicatorProgress = this.customizationService.getCustomization(
'ui.loadingIndicatorProgress'
);
return ( return (
<div <div

View File

@ -12,6 +12,7 @@ import {
CommandsManager, CommandsManager,
HotkeysManager, HotkeysManager,
ServiceProvidersManager, ServiceProvidersManager,
SystemContextProvider,
} from '@ohif/core'; } from '@ohif/core';
import { import {
DialogProvider, DialogProvider,
@ -114,6 +115,7 @@ function App({
[I18nextProvider, { i18n }], [I18nextProvider, { i18n }],
[ThemeWrapperNext], [ThemeWrapperNext],
[ThemeWrapper], [ThemeWrapper],
[SystemContextProvider, { commandsManager, extensionManager, hotkeysManager, servicesManager }],
[ToolboxProvider], [ToolboxProvider],
[ViewportGridProvider, { service: viewportGridService }], [ViewportGridProvider, { service: viewportGridService }],
[ViewportDialogProvider, { service: uiViewportDialogService }], [ViewportDialogProvider, { service: uiViewportDialogService }],

View File

@ -1,14 +1,14 @@
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef } from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { DicomMetadataStore, MODULE_TYPES } from '@ohif/core'; import { DicomMetadataStore, MODULE_TYPES, useSystem } from '@ohif/core';
import Dropzone from 'react-dropzone'; import Dropzone from 'react-dropzone';
import filesToStudies from './filesToStudies'; import filesToStudies from './filesToStudies';
import { extensionManager } from '../../App'; import { extensionManager } from '../../App';
import { Button, LoadingIndicatorProgress } from '@ohif/ui'; import { Button } from '@ohif/ui';
import { Icons } from '@ohif/ui-next'; import { Icons } from '@ohif/ui-next';
const getLoadButton = (onDrop, text, isDir) => { const getLoadButton = (onDrop, text, isDir) => {
@ -49,10 +49,16 @@ type LocalProps = {
}; };
function Local({ modePath }: LocalProps) { function Local({ modePath }: LocalProps) {
const { servicesManager } = useSystem();
const { customizationService } = servicesManager.services;
const navigate = useNavigate(); const navigate = useNavigate();
const dropzoneRef = useRef(); const dropzoneRef = useRef();
const [dropInitiated, setDropInitiated] = React.useState(false); const [dropInitiated, setDropInitiated] = React.useState(false);
const LoadingIndicatorProgress = customizationService.getCustomization(
'ui.loadingIndicatorProgress'
);
// Initializing the dicom local dataSource // Initializing the dicom local dataSource
const dataSourceModules = extensionManager.modules[MODULE_TYPES.DATA_SOURCE]; const dataSourceModules = extensionManager.modules[MODULE_TYPES.DATA_SOURCE];
const localDataSources = dataSourceModules.reduce((acc, curr) => { const localDataSources = dataSourceModules.reduce((acc, curr) => {

View File

@ -22,7 +22,6 @@ import {
useModal, useModal,
AboutModal, AboutModal,
UserPreferences, UserPreferences,
LoadingIndicatorProgress,
useSessionStorage, useSessionStorage,
InvestigationalUseDialog, InvestigationalUseDialog,
Button, Button,
@ -525,6 +524,9 @@ function WorkList({
} }
const { customizationService } = servicesManager.services; const { customizationService } = servicesManager.services;
const LoadingIndicatorProgress = customizationService.getCustomization(
'ui.loadingIndicatorProgress'
);
const DicomUploadComponent = customizationService.getCustomization('dicomUploadComponent'); const DicomUploadComponent = customizationService.getCustomization('dicomUploadComponent');
const uploadProps = const uploadProps =

View File

@ -0,0 +1,33 @@
import React, { createContext, useContext } from 'react';
import { CommandsManager, HotkeysManager } from '../classes';
import { ExtensionManager } from '../extensions';
import { ServicesManager } from '../services';
interface SystemContextProviderProps {
children: React.ReactNode | React.ReactNode[] | ((...args: any[]) => React.ReactNode);
servicesManager: ServicesManager;
commandsManager: CommandsManager;
extensionManager: ExtensionManager;
hotkeysManager: HotkeysManager;
}
const systemContext = createContext(null);
const { Provider } = systemContext;
export const useSystem = () => useContext(systemContext);
export function SystemContextProvider({
children,
servicesManager,
commandsManager,
extensionManager,
hotkeysManager,
}: SystemContextProviderProps) {
return (
<Provider value={{ servicesManager, commandsManager, extensionManager, hotkeysManager }}>
{children}
</Provider>
);
}
export default SystemContextProvider;

View File

@ -1,6 +1,7 @@
import { ExtensionManager, MODULE_TYPES } from './extensions'; import { ExtensionManager, MODULE_TYPES } from './extensions';
import { ServiceProvidersManager, ServicesManager } from './services'; import { ServiceProvidersManager, ServicesManager } from './services';
import classes, { CommandsManager, HotkeysManager } from './classes'; import classes, { CommandsManager, HotkeysManager } from './classes';
import { SystemContextProvider, useSystem } from './contextProviders/SystemProvider';
import DICOMWeb from './DICOMWeb'; import DICOMWeb from './DICOMWeb';
import errorHandler from './errorHandler.js'; import errorHandler from './errorHandler.js';
@ -99,6 +100,7 @@ export {
HotkeysManager, HotkeysManager,
ServicesManager, ServicesManager,
ServiceProvidersManager, ServiceProvidersManager,
SystemContextProvider,
// //
defaults, defaults,
utils, utils,
@ -134,6 +136,7 @@ export {
PanelService, PanelService,
WorkflowStepsService, WorkflowStepsService,
StudyPrefetcherService, StudyPrefetcherService,
useSystem,
useToolbar, useToolbar,
useActiveViewportDisplaySets, useActiveViewportDisplaySets,
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -10,6 +10,13 @@ import segmentationTableModeImage2 from '../../../assets/img/segmentationTableMo
import segmentationShowAddSegmentImage from '../../../assets/img/segmentationShowAddSegmentImage.png'; import segmentationShowAddSegmentImage from '../../../assets/img/segmentationShowAddSegmentImage.png';
import layoutSelectorCommonPresetsImage from '../../../assets/img/layoutSelectorCommonPresetsImage.png'; import layoutSelectorCommonPresetsImage from '../../../assets/img/layoutSelectorCommonPresetsImage.png';
import layoutSelectorAdvancedPresetGeneratorImage from '../../../assets/img/layoutSelectorAdvancedPresetGeneratorImage.png'; import layoutSelectorAdvancedPresetGeneratorImage from '../../../assets/img/layoutSelectorAdvancedPresetGeneratorImage.png';
import labellingFLow from '../../../assets/img/labelling-flow.png';
import progressLoading from '../../../assets/img/Loading-Indicator.png';
import loadingIndicatorProgress from '../../../assets/img/loading-indicator-icon.png';
import loadingIndicatorPercent from '../../../assets/img/loading-indicator-percent.png';
import viewportActionCorners from '../../../assets/img/viewport-action-corners.png';
import contextMenu from '../../../assets/img/context-menu.jpg';
import segDisplayEditingTrue from '../../../assets/img/segDisplayEditingTrue.png'; import segDisplayEditingTrue from '../../../assets/img/segDisplayEditingTrue.png';
import segDisplayEditingFalse from '../../../assets/img/segDisplayEditingFalse.png'; import segDisplayEditingFalse from '../../../assets/img/segDisplayEditingFalse.png';
import thumbnailMenuItemsImage from '../../../assets/img/thumbnailMenuItemsImage.png'; import thumbnailMenuItemsImage from '../../../assets/img/thumbnailMenuItemsImage.png';
@ -610,6 +617,114 @@ window.config = {
}; };
`, `,
}, },
{
id: 'ui.loadingIndicatorTotalPercent',
description: 'Customizes the LoadingIndicatorTotalPercent component.',
image: loadingIndicatorPercent,
default: null, //use platform/ui component as default
configuration: `
window.config = {
// rest of window config
customizationService: [
{
'ui.loadingIndicatorTotalPercent': {
$set: CustomizedComponent,
},
},
],
};
`,
},
{
id: 'ui.loadingIndicatorProgress',
description: 'Customizes the LoadingIndicatorProgress component.',
image: loadingIndicatorProgress,
default: null, //use platform/ui component as default
configuration: `
window.config = {
// rest of window config
customizationService: [
{
'ui.loadingIndicatorProgress': {
$set: CustomizedComponent,
},
},
],
};
`,
},
{
id: 'ui.progressLoadingBar',
description: 'Customizes the ProgressLoadingBar component.',
image: progressLoading,
default: null, //use platform/ui component as default
configuration: `
window.config = {
// rest of window config
customizationService: [
{
'ui.progressLoadingBar': {
$set: CustomizedComponent,
},
},
],
};
`,
},
{
id: 'ui.viewportActionCorner',
description: 'Customizes the viewportActionCorner component.',
iamge: viewportActionCorners,
default: null, //use platform/ui component as default
configuration: `
window.config = {
// rest of window config
customizationService: [
{
'ui.viewportActionCorner': {
$set: CustomizedComponent,
},
},
],
};
`,
},
{
id: 'ui.contextMenu',
description: 'Customizes the Context menu component.',
image: contextMenu,
default: null, //use platform/ui component as default
configuration: `
window.config = {
// rest of window config
customizationService: [
{
'ui.contextMenu': {
$set: CustomizedComponent,
},
},
],
};
`,
},
{
id: 'ui.labellingComponent',
description: 'Customizes the labelling flow component.',
image: labellingFLow,
default: null, //use platform/ui component as default
configuration: `
window.config = {
// rest of window config
customizationService: [
{
'ui.labellingComponent': {
$set: CustomizedComponent,
},
},
],
};
`,
},
]; ];
export const segmentationCustomizations = [ export const segmentationCustomizations = [