Skip to content

Commit

Permalink
feat: Add customization support for more UI components (#4634)
Browse files Browse the repository at this point in the history
Co-authored-by: ashikcn <[email protected]>
Co-authored-by: Devu Jayalekshmi <[email protected]>
Co-authored-by: Arul Mozhi <[email protected]>
  • Loading branch information
4 people authored Feb 3, 2025
1 parent 8f79eba commit f15eb44
Show file tree
Hide file tree
Showing 31 changed files with 288 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -13,14 +12,18 @@ 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
if (displaySets.length !== 1) {
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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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
Expand Down
27 changes: 16 additions & 11 deletions extensions/cornerstone/src/commandsModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,9 @@ function commandsModule({
*/
setMeasurementLabel: ({ uid }) => {
const labelConfig = customizationService.getCustomization('measurementLabels');
const renderContent = customizationService.getCustomization('ui.labellingComponent');
const measurement = measurementService.getMeasurement(uid);
showLabelAnnotationPopup(measurement, uiDialogService, labelConfig).then(
showLabelAnnotationPopup(measurement, uiDialogService, labelConfig, renderContent).then(
(val: Map<any, any>) => {
measurementService.update(
uid,
Expand Down Expand Up @@ -325,16 +326,19 @@ function commandsModule({

renameMeasurement: ({ uid }) => {
const labelConfig = customizationService.getCustomization('measurementLabels');
const renderContent = customizationService.getCustomization('ui.labellingComponent');
const measurement = measurementService.getMeasurement(uid);
showLabelAnnotationPopup(measurement, uiDialogService, labelConfig).then(val => {
measurementService.update(
uid,
{
...val,
},
true
);
});
showLabelAnnotationPopup(measurement, uiDialogService, labelConfig, renderContent).then(
val => {
measurementService.update(
uid,
{
...val,
},
true
);
}
);
},

toggleLockMeasurement: ({ uid }) => {
Expand Down Expand Up @@ -376,7 +380,8 @@ function commandsModule({
},
arrowTextCallback: ({ callback, data, uid }) => {
const labelConfig = customizationService.getCustomization('measurementLabels');
callLabelAutocompleteDialog(uiDialogService, callback, {}, labelConfig);
const renderContent = customizationService.getCustomization('ui.labellingComponent');
callLabelAutocompleteDialog(uiDialogService, callback, {}, labelConfig, renderContent);
},
toggleCine: () => {
const { viewports } = viewportGridService.getState();
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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)
);
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
Expand Down
8 changes: 7 additions & 1 deletion extensions/default/src/Components/ItemListComponent.tsx
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -16,13 +17,18 @@ function ItemListComponent({
itemList,
onItemClicked,
}: ItemListComponentProps): ReactElement {
const { servicesManager } = useSystem();
const { t } = useTranslation('DataSourceConfiguration');
const [filterValue, setFilterValue] = useState('');

useEffect(() => {
setFilterValue('');
}, [itemList]);

const LoadingIndicatorProgress = servicesManager.services.customizationService.getCustomization(
'ui.loadingIndicatorProgress'
);

return (
<div className="flex min-h-[1px] grow flex-col gap-4">
<div className="flex items-center justify-between">
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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',
Expand Down
8 changes: 6 additions & 2 deletions extensions/default/src/ViewerLayout/index.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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(
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ContextMenu } from '@ohif/ui';

export default {
'ui.contextMenu': ContextMenu,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { LabellingFlow } from '@ohif/ui';

export default {
'ui.labellingComponent': LabellingFlow,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { LoadingIndicatorProgress } from '@ohif/ui';

export default {
'ui.loadingIndicatorProgress': LoadingIndicatorProgress,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { LoadingIndicatorTotalPercent } from '@ohif/ui';

export default {
'ui.loadingIndicatorTotalPercent': LoadingIndicatorTotalPercent,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ProgressLoadingBar } from '@ohif/ui';

export default {
'ui.progressLoadingBar': ProgressLoadingBar,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ViewportActionCorners } from '@ohif/ui';

export default {
'ui.viewportActionCorner': ViewportActionCorners,
};
12 changes: 12 additions & 0 deletions extensions/default/src/getCustomizationModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@ import customRoutesCustomization from './customizations/customRoutesCustomizatio
import studyBrowserCustomization from './customizations/studyBrowserCustomization';
import overlayItemCustomization from './customizations/overlayItemCustomization';
import contextMenuCustomization from './customizations/contextMenuCustomization';
import contextMenuUICustomization from './customizations/contextMenuUICustomization';
import menuContentCustomization from './customizations/menuContentCustomization';
import getDataSourceConfigurationCustomization from './customizations/dataSourceConfigurationCustomization';
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';

/**
*
Expand Down Expand Up @@ -48,6 +54,12 @@ export default function getCustomizationModule({ servicesManager, extensionManag
...sortingCriteriaCustomization,
...defaultContextMenuCustomization,
...onDropHandlerCustomization,
...loadingIndicatorProgressCustomization,
...loadingIndicatorTotalPercentCustomization,
...progressLoadingBarCustomization,
...viewportActionCornersCustomization,
...labellingFlowCustomization,
...contextMenuUICustomization,
},
},
];
Expand Down
19 changes: 15 additions & 4 deletions extensions/default/src/utils/callInputDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 dropDownItems = labelConfig ? labelConfig.items : [];

Expand All @@ -112,7 +118,7 @@ export function callLabelAutocompleteDialog(uiDialogService, callback, dialogCon
centralize: true,
isDraggable: false,
showOverlay: true,
content: LabellingFlow,
content: renderContent,
contentProps: {
labellingDoneCallback: labellingDoneCallback,
measurementData: { label: '' },
Expand All @@ -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 dropDownItems = labelConfig ? labelConfig.items : [];
return new Promise<Map<any, any>>((resolve, reject) => {
Expand All @@ -139,7 +150,7 @@ export function showLabelAnnotationPopup(measurement, uiDialogService, labelConf
id: 'select-annotation',
isDraggable: false,
showOverlay: true,
content: LabellingFlow,
content: renderContent,
defaultPosition: {
x: window.innerWidth / 2,
y: window.innerHeight / 2,
Expand Down
4 changes: 3 additions & 1 deletion extensions/default/src/utils/promptLabelAnnotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 renderContent = customizationService.getCustomization('ui.labellingComponent');
const measurement = measurementService.getMeasurement(measurementId);
const value = await showLabelAnnotationPopup(
measurement,
servicesManager.services.uiDialogService,
labelConfig
labelConfig,
renderContent
);

measurementService.update(
Expand Down
Loading

0 comments on commit f15eb44

Please sign in to comment.