diff --git a/extensions/cornerstone-dicom-pmap/src/viewports/OHIFCornerstonePMAPViewport.tsx b/extensions/cornerstone-dicom-pmap/src/viewports/OHIFCornerstonePMAPViewport.tsx index 59a3609a4d4..2d33fe3ed3a 100644 --- a/extensions/cornerstone-dicom-pmap/src/viewports/OHIFCornerstonePMAPViewport.tsx +++ b/extensions/cornerstone-dicom-pmap/src/viewports/OHIFCornerstonePMAPViewport.tsx @@ -1,6 +1,5 @@ import PropTypes from 'prop-types'; import React, { useCallback, useEffect, useRef, useState } from 'react'; -import { LoadingIndicatorTotalPercent } from '@ohif/ui'; import { useViewportGrid } from '@ohif/ui-next'; function OHIFCornerstonePMAPViewport(props: withAppTypes) { @@ -13,7 +12,7 @@ function OHIFCornerstonePMAPViewport(props: withAppTypes) { extensionManager, } = props; const viewportId = viewportOptions.viewportId; - const { displaySetService, segmentationService, uiNotificationService } = + const { displaySetService, segmentationService, uiNotificationService, customizationService } = servicesManager.services; // 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'); } + const LoadingIndicatorTotalPercent = customizationService.getCustomization( + 'ui.loadingIndicatorTotalPercent' + ); + const pmapDisplaySet = displaySets[0]; const [viewportGrid, viewportGridService] = useViewportGrid(); const referencedDisplaySetRef = useRef(null); diff --git a/extensions/cornerstone-dicom-rt/src/viewports/OHIFCornerstoneRTViewport.tsx b/extensions/cornerstone-dicom-rt/src/viewports/OHIFCornerstoneRTViewport.tsx index 64b233252ba..e6b8d1ee88b 100644 --- a/extensions/cornerstone-dicom-rt/src/viewports/OHIFCornerstoneRTViewport.tsx +++ b/extensions/cornerstone-dicom-rt/src/viewports/OHIFCornerstoneRTViewport.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import PropTypes from 'prop-types'; -import { LoadingIndicatorTotalPercent, ViewportActionArrows } from '@ohif/ui'; +import { ViewportActionArrows } from '@ohif/ui'; import { useViewportGrid } from '@ohif/ui-next'; 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'); } + const LoadingIndicatorTotalPercent = customizationService.getCustomization( + 'ui.loadingIndicatorTotalPercent' + ); + const rtDisplaySet = displaySets[0]; const [viewportGrid, viewportGridService] = useViewportGrid(); diff --git a/extensions/cornerstone-dicom-seg/src/viewports/OHIFCornerstoneSEGViewport.tsx b/extensions/cornerstone-dicom-seg/src/viewports/OHIFCornerstoneSEGViewport.tsx index 69c0d4f6f7d..311ada43800 100644 --- a/extensions/cornerstone-dicom-seg/src/viewports/OHIFCornerstoneSEGViewport.tsx +++ b/extensions/cornerstone-dicom-seg/src/viewports/OHIFCornerstoneSEGViewport.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { LoadingIndicatorTotalPercent, ViewportActionArrows } from '@ohif/ui'; +import { ViewportActionArrows } from '@ohif/ui'; import { useViewportGrid } from '@ohif/ui-next'; import createSEGToolGroupAndAddTools from '../utils/initSEGToolGroup'; import promptHydrateSEG from '../utils/promptHydrateSEG'; @@ -31,6 +31,10 @@ function OHIFCornerstoneSEGViewport(props: withAppTypes) { viewportActionCornersService, } = servicesManager.services; + const LoadingIndicatorTotalPercent = customizationService.getCustomization( + 'ui.loadingIndicatorTotalPercent' + ); + const toolGroupId = `${SEG_TOOLGROUP_BASE_NAME}-${viewportId}`; // SEG viewport will always have a single display set diff --git a/extensions/cornerstone/src/commandsModule.ts b/extensions/cornerstone/src/commandsModule.ts index a9d659cd193..ff0cc2894ad 100644 --- a/extensions/cornerstone/src/commandsModule.ts +++ b/extensions/cornerstone/src/commandsModule.ts @@ -208,8 +208,9 @@ function commandsModule({ */ setMeasurementLabel: ({ uid }) => { const labelConfig = customizationService.getCustomization('measurementLabels'); + const labelSelector = customizationService.getCustomization('ui.labellingComponent'); const measurement = measurementService.getMeasurement(uid); - showLabelAnnotationPopup(measurement, uiDialogService, labelConfig).then( + showLabelAnnotationPopup(measurement, uiDialogService, labelConfig, labelSelector).then( (val: Map) => { measurementService.update( uid, @@ -325,16 +326,19 @@ function commandsModule({ renameMeasurement: ({ uid }) => { const labelConfig = customizationService.getCustomization('measurementLabels'); + const labelSelector = customizationService.getCustomization('ui.labellingComponent'); const measurement = measurementService.getMeasurement(uid); - showLabelAnnotationPopup(measurement, uiDialogService, labelConfig).then(val => { - measurementService.update( - uid, - { - ...val, - }, - true - ); - }); + showLabelAnnotationPopup(measurement, uiDialogService, labelConfig, labelSelector).then( + val => { + measurementService.update( + uid, + { + ...val, + }, + true + ); + } + ); }, toggleLockMeasurement: ({ uid }) => { @@ -376,7 +380,8 @@ function commandsModule({ }, arrowTextCallback: ({ callback, data, uid }) => { const labelConfig = customizationService.getCustomization('measurementLabels'); - callLabelAutocompleteDialog(uiDialogService, callback, {}, labelConfig); + const labelSelector = customizationService.getCustomization('ui.labellingComponent'); + callLabelAutocompleteDialog(uiDialogService, callback, {}, labelConfig, labelSelector); }, toggleCine: () => { const { viewports } = viewportGridService.getState(); diff --git a/extensions/cornerstone/src/components/DicomUpload/DicomUploadProgress.tsx b/extensions/cornerstone/src/components/DicomUpload/DicomUploadProgress.tsx index 2ab8b23024a..7f58172f99a 100644 --- a/extensions/cornerstone/src/components/DicomUpload/DicomUploadProgress.tsx +++ b/extensions/cornerstone/src/components/DicomUpload/DicomUploadProgress.tsx @@ -1,6 +1,7 @@ import React, { useCallback, useEffect, useRef, useState, ReactElement } from 'react'; 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 DicomFileUploader, { EVENTS, @@ -40,6 +41,11 @@ function DicomUploadProgress({ dicomFileUploaderArr, onComplete, }: DicomUploadProgressProps): ReactElement { + const { servicesManager } = useSystem(); + + const ProgressLoadingBar = + servicesManager.services.customizationService.getCustomization('ui.progressLoadingBar'); + const [totalUploadSize] = useState( dicomFileUploaderArr.reduce((acc, fileUploader) => acc + fileUploader.getFileSize(), 0) ); diff --git a/extensions/cornerstone/src/components/OHIFViewportActionCorners.tsx b/extensions/cornerstone/src/components/OHIFViewportActionCorners.tsx index 3e7380972da..041dfa5912d 100644 --- a/extensions/cornerstone/src/components/OHIFViewportActionCorners.tsx +++ b/extensions/cornerstone/src/components/OHIFViewportActionCorners.tsx @@ -1,14 +1,16 @@ import React from 'react'; import { useViewportActionCornersContext } from '../contextProviders/ViewportActionCornersProvider'; -import { ViewportActionCorners } from '@ohif/ui'; +import { useSystem } from '@ohif/core'; export type OHIFViewportActionCornersProps = { viewportId: string; }; function OHIFViewportActionCorners({ viewportId }: OHIFViewportActionCornersProps) { + const { servicesManager } = useSystem(); const [viewportActionCornersState] = useViewportActionCornersContext(); - + const ViewportActionCorners = + servicesManager.services.customizationService.getCustomization('ui.viewportActionCorner'); if (!viewportActionCornersState[viewportId]) { return null; } diff --git a/extensions/default/src/Components/ItemListComponent.tsx b/extensions/default/src/Components/ItemListComponent.tsx index c3533684549..796ad7659e7 100644 --- a/extensions/default/src/Components/ItemListComponent.tsx +++ b/extensions/default/src/Components/ItemListComponent.tsx @@ -1,7 +1,8 @@ import classNames from 'classnames'; import React, { ReactElement, useEffect, useState } from 'react'; 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 { Types } from '@ohif/core'; @@ -16,6 +17,7 @@ function ItemListComponent({ itemList, onItemClicked, }: ItemListComponentProps): ReactElement { + const { servicesManager } = useSystem(); const { t } = useTranslation('DataSourceConfiguration'); const [filterValue, setFilterValue] = useState(''); @@ -23,6 +25,10 @@ function ItemListComponent({ setFilterValue(''); }, [itemList]); + const LoadingIndicatorProgress = servicesManager.services.customizationService.getCustomization( + 'ui.loadingIndicatorProgress' + ); + return (
diff --git a/extensions/default/src/CustomizableContextMenu/ContextMenuController.tsx b/extensions/default/src/CustomizableContextMenu/ContextMenuController.tsx index 9b7c1078b09..50303a4ba39 100644 --- a/extensions/default/src/CustomizableContextMenu/ContextMenuController.tsx +++ b/extensions/default/src/CustomizableContextMenu/ContextMenuController.tsx @@ -1,5 +1,4 @@ import * as ContextMenuItemsBuilder from './ContextMenuItemsBuilder'; -import ContextMenu from '../../../../platform/ui/src/components/ContextMenu/ContextMenu'; import { CommandsManager } from '@ohif/core'; import { annotation as CsAnnotation } from '@cornerstonejs/tools'; import { Menu, MenuItem, Point, ContextMenuProps } from './types'; @@ -72,6 +71,8 @@ export default class ContextMenuController { menuId ); + const ContextMenu = this.services.customizationService.getCustomization('ui.contextMenu'); + this.services.uiDialogService.dismiss({ id: 'context-menu' }); this.services.uiDialogService.create({ id: 'context-menu', diff --git a/extensions/default/src/ViewerLayout/index.tsx b/extensions/default/src/ViewerLayout/index.tsx index 64ecca5615c..a2ed2ba39cf 100644 --- a/extensions/default/src/ViewerLayout/index.tsx +++ b/extensions/default/src/ViewerLayout/index.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState, useCallback } from 'react'; import PropTypes from 'prop-types'; -import { LoadingIndicatorProgress, InvestigationalUseDialog } from '@ohif/ui'; +import { InvestigationalUseDialog } from '@ohif/ui'; import { HangingProtocolService, CommandsManager } from '@ohif/core'; import { useAppConfig } from '@state'; import ViewerHeader from './ViewerHeader'; @@ -27,7 +27,7 @@ function ViewerLayout({ }: withAppTypes): React.FunctionComponent { const [appConfig] = useAppConfig(); - const { panelService, hangingProtocolService } = servicesManager.services; + const { panelService, hangingProtocolService, customizationService } = servicesManager.services; const [showLoadingIndicator, setShowLoadingIndicator] = useState(appConfig.showLoadingIndicator); const hasPanels = useCallback( @@ -55,6 +55,10 @@ function ViewerLayout({ setRightPanelClosed ); + const LoadingIndicatorProgress = customizationService.getCustomization( + 'ui.loadingIndicatorProgress' + ); + /** * Set body classes (tailwindcss) that don't allow vertical * or horizontal overflow (no scrolling). Also guarantee window diff --git a/extensions/default/src/customizations/contextMenuCustomization.ts b/extensions/default/src/customizations/contextMenuCustomization.ts index b19232b228b..4366df89c6e 100644 --- a/extensions/default/src/customizations/contextMenuCustomization.ts +++ b/extensions/default/src/customizations/contextMenuCustomization.ts @@ -1,25 +1,5 @@ -import { CustomizationService } from '@ohif/core'; +import { ContextMenu } from '@ohif/ui'; export default { - 'ohif.contextMenu': { - $transform: function (customizationService: CustomizationService) { - /** - * Applies the inheritsFrom to all the menu items. - * This function clones the object and child objects to prevent - * changes to the original customization object. - */ - // Don't modify the children, as those are copied by reference - const clonedObject = { ...this }; - clonedObject.menus = this.menus.map(menu => ({ ...menu })); - - for (const menu of clonedObject.menus) { - const { items: originalItems } = menu; - menu.items = []; - for (const item of originalItems) { - menu.items.push(customizationService.transform(item)); - } - } - return clonedObject; - }, - }, + 'ui.contextMenu': ContextMenu, }; diff --git a/extensions/default/src/customizations/labellingFlowCustomization.tsx b/extensions/default/src/customizations/labellingFlowCustomization.tsx new file mode 100644 index 00000000000..00f97f8229b --- /dev/null +++ b/extensions/default/src/customizations/labellingFlowCustomization.tsx @@ -0,0 +1,5 @@ +import { LabellingFlow } from '@ohif/ui'; + +export default { + 'ui.labellingComponent': LabellingFlow, +}; diff --git a/extensions/default/src/customizations/loadingIndicatorProgressCustomization.tsx b/extensions/default/src/customizations/loadingIndicatorProgressCustomization.tsx new file mode 100644 index 00000000000..9bba0cc758c --- /dev/null +++ b/extensions/default/src/customizations/loadingIndicatorProgressCustomization.tsx @@ -0,0 +1,5 @@ +import { LoadingIndicatorProgress } from '@ohif/ui'; + +export default { + 'ui.loadingIndicatorProgress': LoadingIndicatorProgress, +}; diff --git a/extensions/default/src/customizations/loadingIndicatorTotalPercentCustomization.tsx b/extensions/default/src/customizations/loadingIndicatorTotalPercentCustomization.tsx new file mode 100644 index 00000000000..368834f6310 --- /dev/null +++ b/extensions/default/src/customizations/loadingIndicatorTotalPercentCustomization.tsx @@ -0,0 +1,5 @@ +import { LoadingIndicatorTotalPercent } from '@ohif/ui'; + +export default { + 'ui.loadingIndicatorTotalPercent': LoadingIndicatorTotalPercent, +}; diff --git a/extensions/default/src/customizations/progressLoadingBarCustomization.tsx b/extensions/default/src/customizations/progressLoadingBarCustomization.tsx new file mode 100644 index 00000000000..d4de5097c21 --- /dev/null +++ b/extensions/default/src/customizations/progressLoadingBarCustomization.tsx @@ -0,0 +1,5 @@ +import { ProgressLoadingBar } from '@ohif/ui'; + +export default { + 'ui.progressLoadingBar': ProgressLoadingBar, +}; diff --git a/extensions/default/src/customizations/viewportActionCornersCustomization.ts b/extensions/default/src/customizations/viewportActionCornersCustomization.ts new file mode 100644 index 00000000000..49b28bb214e --- /dev/null +++ b/extensions/default/src/customizations/viewportActionCornersCustomization.ts @@ -0,0 +1,5 @@ +import { ViewportActionCorners } from '@ohif/ui'; + +export default { + 'ui.viewportActionCorner': ViewportActionCorners, +}; diff --git a/extensions/default/src/getCustomizationModule.tsx b/extensions/default/src/getCustomizationModule.tsx index 47b7852511b..d4b30618354 100644 --- a/extensions/default/src/getCustomizationModule.tsx +++ b/extensions/default/src/getCustomizationModule.tsx @@ -11,6 +11,11 @@ import getDataSourceConfigurationCustomization from './customizations/dataSource import progressDropdownCustomization from './customizations/progressDropdownCustomization'; import sortingCriteriaCustomization from './customizations/sortingCriteriaCustomization'; 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 +53,11 @@ export default function getCustomizationModule({ servicesManager, extensionManag ...sortingCriteriaCustomization, ...defaultContextMenuCustomization, ...onDropHandlerCustomization, + ...loadingIndicatorProgressCustomization, + ...loadingIndicatorTotalPercentCustomization, + ...progressLoadingBarCustomization, + ...viewportActionCornersCustomization, + ...labellingFlowCustomization, }, }, ]; diff --git a/extensions/default/src/utils/callInputDialog.tsx b/extensions/default/src/utils/callInputDialog.tsx index 321b308a864..15519e0745f 100644 --- a/extensions/default/src/utils/callInputDialog.tsx +++ b/extensions/default/src/utils/callInputDialog.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Input, Dialog, ButtonEnums, LabellingFlow } from '@ohif/ui'; +import { Input, Dialog, ButtonEnums } from '@ohif/ui'; /** * @@ -89,7 +89,13 @@ export function callInputDialog( } } -export function callLabelAutocompleteDialog(uiDialogService, callback, dialogConfig, labelConfig) { +export function callLabelAutocompleteDialog( + uiDialogService, + callback, + dialogConfig, + labelConfig, + labelSelector +) { const exclusive = labelConfig ? labelConfig.exclusive : false; const dropDownItems = labelConfig ? labelConfig.items : []; @@ -112,7 +118,7 @@ export function callLabelAutocompleteDialog(uiDialogService, callback, dialogCon centralize: true, isDraggable: false, showOverlay: true, - content: LabellingFlow, + content: labelSelector, contentProps: { labellingDoneCallback: labellingDoneCallback, measurementData: { label: '' }, @@ -123,7 +129,7 @@ export function callLabelAutocompleteDialog(uiDialogService, callback, dialogCon }); } -export function showLabelAnnotationPopup(measurement, uiDialogService, labelConfig) { +export function showLabelAnnotationPopup(measurement, uiDialogService, labelConfig, labelSelector) { const exclusive = labelConfig ? labelConfig.exclusive : false; const dropDownItems = labelConfig ? labelConfig.items : []; return new Promise>((resolve, reject) => { @@ -139,7 +145,7 @@ export function showLabelAnnotationPopup(measurement, uiDialogService, labelConf id: 'select-annotation', isDraggable: false, showOverlay: true, - content: LabellingFlow, + content: labelSelector, defaultPosition: { x: window.innerWidth / 2, y: window.innerHeight / 2, diff --git a/extensions/default/src/utils/promptLabelAnnotation.js b/extensions/default/src/utils/promptLabelAnnotation.js index 8139da4ebfd..fa0b195cc86 100644 --- a/extensions/default/src/utils/promptLabelAnnotation.js +++ b/extensions/default/src/utils/promptLabelAnnotation.js @@ -5,11 +5,13 @@ function promptLabelAnnotation({ servicesManager }, ctx, evt) { const { viewportId, StudyInstanceUID, SeriesInstanceUID, measurementId } = evt; return new Promise(async function (resolve) { const labelConfig = customizationService.getCustomization('measurementLabels'); + const labelSelector = customizationService.getCustomization('ui.labellingComponent'); const measurement = measurementService.getMeasurement(measurementId); const value = await showLabelAnnotationPopup( measurement, servicesManager.services.uiDialogService, - labelConfig + labelConfig, + labelSelector ); measurementService.update( diff --git a/extensions/dicom-microscopy/src/DicomMicroscopyViewport.tsx b/extensions/dicom-microscopy/src/DicomMicroscopyViewport.tsx index 2fcd0ca6643..c0c72bb1fcb 100644 --- a/extensions/dicom-microscopy/src/DicomMicroscopyViewport.tsx +++ b/extensions/dicom-microscopy/src/DicomMicroscopyViewport.tsx @@ -1,6 +1,5 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { LoadingIndicatorProgress } from '@ohif/ui'; import { cleanDenaturalizedDataset } from '@ohif/extension-default'; import './DicomMicroscopyViewport.css'; @@ -8,6 +7,7 @@ import ViewportOverlay from './components/ViewportOverlay'; import getDicomWebClient from './utils/dicomWebClient'; import dcmjs from 'dcmjs'; import MicroscopyService from './services/MicroscopyService'; +import { CustomizationService } from '@ohif/core'; class DicomMicroscopyViewport extends Component { state = { @@ -16,6 +16,7 @@ class DicomMicroscopyViewport extends Component { }; microscopyService: MicroscopyService; + customizationService: CustomizationService; viewer: any = null; // dicom-microscopy-viewer instance managedViewer: any = null; // managed wrapper of microscopy-dicom extension @@ -25,8 +26,9 @@ class DicomMicroscopyViewport extends Component { constructor(props: any) { super(props); - const { microscopyService } = this.props.servicesManager.services; + const { microscopyService, customizationService } = this.props.servicesManager.services; this.microscopyService = microscopyService; + this.customizationService = customizationService; } static propTypes = { @@ -49,7 +51,6 @@ class DicomMicroscopyViewport extends Component { resizeRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.any })]), }; - /** * Get the nearest ROI from the mouse click point * @@ -272,6 +273,9 @@ class DicomMicroscopyViewport extends Component { const style = { width: '100%', height: '100%' }; const displaySet = this.props.displaySets[0]; const firstInstance = displaySet.firstInstance || displaySet.instance; + const LoadingIndicatorProgress = this.customizationService.getCustomization( + 'ui.loadingIndicatorProgress' + ); return (
{ @@ -49,10 +49,15 @@ type LocalProps = { }; function Local({ modePath }: LocalProps) { + const { customizationService } = servicesManager.services; const navigate = useNavigate(); const dropzoneRef = useRef(); const [dropInitiated, setDropInitiated] = React.useState(false); + const LoadingIndicatorProgress = customizationService.getCustomization( + 'ui.loadingIndicatorProgress' + ); + // Initializing the dicom local dataSource const dataSourceModules = extensionManager.modules[MODULE_TYPES.DATA_SOURCE]; const localDataSources = dataSourceModules.reduce((acc, curr) => { diff --git a/platform/app/src/routes/WorkList/WorkList.tsx b/platform/app/src/routes/WorkList/WorkList.tsx index 96f0676319d..a63a96ec226 100644 --- a/platform/app/src/routes/WorkList/WorkList.tsx +++ b/platform/app/src/routes/WorkList/WorkList.tsx @@ -22,7 +22,6 @@ import { useModal, AboutModal, UserPreferences, - LoadingIndicatorProgress, useSessionStorage, InvestigationalUseDialog, Button, @@ -525,6 +524,9 @@ function WorkList({ } const { customizationService } = servicesManager.services; + const LoadingIndicatorProgress = customizationService.getCustomization( + 'ui.loadingIndicatorProgress' + ); const DicomUploadComponent = customizationService.getCustomization('dicomUploadComponent'); const uploadProps = diff --git a/platform/core/src/contextProviders/SystemProvider.tsx b/platform/core/src/contextProviders/SystemProvider.tsx new file mode 100644 index 00000000000..6f168608066 --- /dev/null +++ b/platform/core/src/contextProviders/SystemProvider.tsx @@ -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 ( + + {children} + + ); +} + +export default SystemContextProvider; diff --git a/platform/core/src/index.ts b/platform/core/src/index.ts index 5f01c13446e..b9d8719f5d0 100644 --- a/platform/core/src/index.ts +++ b/platform/core/src/index.ts @@ -1,6 +1,7 @@ import { ExtensionManager, MODULE_TYPES } from './extensions'; import { ServiceProvidersManager, ServicesManager } from './services'; import classes, { CommandsManager, HotkeysManager } from './classes'; +import { SystemContextProvider, useSystem } from './contextProviders/SystemProvider'; import DICOMWeb from './DICOMWeb'; import errorHandler from './errorHandler.js'; @@ -99,6 +100,7 @@ export { HotkeysManager, ServicesManager, ServiceProvidersManager, + SystemContextProvider, // defaults, utils, @@ -134,6 +136,7 @@ export { PanelService, WorkflowStepsService, StudyPrefetcherService, + useSystem, useToolbar, useActiveViewportDisplaySets, }; diff --git a/platform/docs/docs/assets/img/Loading-Indicator.png b/platform/docs/docs/assets/img/Loading-Indicator.png new file mode 100644 index 00000000000..d559db4021a Binary files /dev/null and b/platform/docs/docs/assets/img/Loading-Indicator.png differ diff --git a/platform/docs/docs/assets/img/context-menu.jpg b/platform/docs/docs/assets/img/context-menu.jpg new file mode 100644 index 00000000000..4fef53fa964 Binary files /dev/null and b/platform/docs/docs/assets/img/context-menu.jpg differ diff --git a/platform/docs/docs/assets/img/labelling-flow.png b/platform/docs/docs/assets/img/labelling-flow.png new file mode 100644 index 00000000000..d16f46149e4 Binary files /dev/null and b/platform/docs/docs/assets/img/labelling-flow.png differ diff --git a/platform/docs/docs/assets/img/loading-indicator-icon.png b/platform/docs/docs/assets/img/loading-indicator-icon.png new file mode 100644 index 00000000000..934d03aed0f Binary files /dev/null and b/platform/docs/docs/assets/img/loading-indicator-icon.png differ diff --git a/platform/docs/docs/assets/img/loading-indicator-percent.png b/platform/docs/docs/assets/img/loading-indicator-percent.png new file mode 100644 index 00000000000..b4f466b2113 Binary files /dev/null and b/platform/docs/docs/assets/img/loading-indicator-percent.png differ diff --git a/platform/docs/docs/assets/img/viewport-action-corners.png b/platform/docs/docs/assets/img/viewport-action-corners.png new file mode 100644 index 00000000000..887bfe0290f Binary files /dev/null and b/platform/docs/docs/assets/img/viewport-action-corners.png differ diff --git a/platform/docs/docs/platform/services/customization-service/sampleCustomizations.tsx b/platform/docs/docs/platform/services/customization-service/sampleCustomizations.tsx index 81214fb5f96..0a46a4b4a57 100644 --- a/platform/docs/docs/platform/services/customization-service/sampleCustomizations.tsx +++ b/platform/docs/docs/platform/services/customization-service/sampleCustomizations.tsx @@ -10,6 +10,13 @@ import segmentationTableModeImage2 from '../../../assets/img/segmentationTableMo import segmentationShowAddSegmentImage from '../../../assets/img/segmentationShowAddSegmentImage.png'; import layoutSelectorCommonPresetsImage from '../../../assets/img/layoutSelectorCommonPresetsImage.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 segDisplayEditingFalse from '../../../assets/img/segDisplayEditingFalse.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, + configuration: ` + window.config = { + // rest of window config + customizationService: [ + { + 'ui.labellingComponent': { + $set: CustomizedComponent, + }, + }, + ], + }; + `, + }, ]; export const segmentationCustomizations = [