From e80fc6f47708e1d6b1a1e1de438196a4b74ec637 Mon Sep 17 00:00:00 2001 From: Ibrahim <93064150+IbrahimCSAE@users.noreply.github.com> Date: Tue, 16 Apr 2024 10:31:06 -0230 Subject: [PATCH] fix(bugs): enhancements and bug fixes (#4036) --- .../src/utils/promptHydrateRT.ts | 5 + .../src/utils/promptHydrateSEG.ts | 5 + .../src/panels/DynamicVolumeControls.tsx | 2 +- .../WindowLevelActionMenu/Colormap.tsx | 5 + .../WindowLevelActionMenu/VolumeLighting.tsx | 18 +- .../VolumeRenderingOptions.tsx | 4 +- .../VolumeRenderingPresets.tsx | 2 +- .../VolumeRenderingQuality.tsx | 6 +- .../WindowLevelActionMenu/VolumeShift.tsx | 2 + .../WindowLevelActionMenu/WindowLevel.tsx | 33 ++- .../WindowLevelActionMenu.tsx | 12 +- .../getWindowLevelActionMenu.tsx | 8 +- .../cornerstone/src/getToolbarModule.tsx | 4 +- extensions/cornerstone/src/hps/fourUp.ts | 7 +- extensions/cornerstone/src/hps/main3D.ts | 7 +- .../src/hps/mprAnd3DVolumeViewport.ts | 6 +- extensions/cornerstone/src/hps/only3D.ts | 7 +- extensions/cornerstone/src/hps/primary3D.ts | 7 +- extensions/cornerstone/src/init.tsx | 2 +- .../cornerstone/src/initMeasurementService.js | 18 ++ .../CornerstoneViewportService.ts | 8 +- extensions/cornerstone/src/utils/colormaps.js | 32 +-- .../utils/measurementServiceMappings/Probe.ts | 187 ++++++++++++++++ .../UltrasoundDirectional.ts | 206 ++++++++++++++++++ .../constants/supportedTools.js | 2 + .../measurementServiceMappingsFactory.ts | 39 ++++ .../default/src/ViewerLayout/ViewerHeader.tsx | 3 +- extensions/default/src/commandsModule.ts | 1 + .../promptHydrateStructuredReport.js | 6 + .../PanelStudyBrowserTracking.tsx | 72 +++++- extensions/tmtv/src/Panels/PanelPetSUV.tsx | 2 +- .../PanelROIThresholdExport.tsx | 4 +- platform/app/public/config/netlify.js | 1 + platform/app/src/routes/WorkList/WorkList.tsx | 3 +- .../docs/configuration/configurationFiles.md | 3 +- platform/ui/src/assets/icons/tool-layout.svg | 15 +- .../ui/src/assets/icons/tool-seg-brush.svg | 9 + .../ui/src/assets/icons/tool-seg-eraser.svg | 10 + .../ui/src/assets/icons/tool-seg-shape.svg | 9 + .../src/assets/icons/tool-seg-threshold.svg | 17 ++ .../components/ButtonGroup/ButtonGroup.tsx | 45 ++-- platform/ui/src/components/Header/Header.tsx | 3 +- .../HeaderPatientInfo/HeaderPatientInfo.tsx | 7 +- platform/ui/src/components/Icon/getIcon.js | 8 +- .../src/components/IconButton/IconButton.tsx | 3 +- .../src/components/InputRange/InputRange.tsx | 4 +- .../ui/src/components/ListMenu/ListMenu.tsx | 2 +- .../components/Notification/Notification.tsx | 2 +- .../components/PanelSection/PanelSection.tsx | 6 +- .../SegmentationGroupSegment.tsx | 6 +- .../SegmentationGroupTable.tsx | 6 +- .../SegmentationGroupTableExpanded.tsx | 6 +- .../ui/src/components/SidePanel/SidePanel.tsx | 18 +- .../components/SplitButton/SplitButton.tsx | 2 +- .../ui/src/components/StudyItem/StudyItem.tsx | 4 +- .../ToolbarButton/ToolbarButton.tsx | 2 +- .../src/contextProviders/DialogProvider.tsx | 2 +- .../ui/src/types/PatientInfoVisibility.ts | 1 + 58 files changed, 768 insertions(+), 148 deletions(-) create mode 100644 extensions/cornerstone/src/utils/measurementServiceMappings/Probe.ts create mode 100644 extensions/cornerstone/src/utils/measurementServiceMappings/UltrasoundDirectional.ts create mode 100644 platform/ui/src/assets/icons/tool-seg-brush.svg create mode 100644 platform/ui/src/assets/icons/tool-seg-eraser.svg create mode 100644 platform/ui/src/assets/icons/tool-seg-shape.svg create mode 100644 platform/ui/src/assets/icons/tool-seg-threshold.svg diff --git a/extensions/cornerstone-dicom-rt/src/utils/promptHydrateRT.ts b/extensions/cornerstone-dicom-rt/src/utils/promptHydrateRT.ts index 91492cbfbed..2baa0305b39 100644 --- a/extensions/cornerstone-dicom-rt/src/utils/promptHydrateRT.ts +++ b/extensions/cornerstone-dicom-rt/src/utils/promptHydrateRT.ts @@ -66,6 +66,11 @@ function _askHydrate(uiViewportDialogService, viewportId) { uiViewportDialogService.hide(); resolve(RESPONSE.CANCEL); }, + onKeyPress: event => { + if (event.key === 'Enter') { + onSubmit(RESPONSE.HYDRATE_SEG); + } + }, }); }); } diff --git a/extensions/cornerstone-dicom-seg/src/utils/promptHydrateSEG.ts b/extensions/cornerstone-dicom-seg/src/utils/promptHydrateSEG.ts index 9f8c1dddf78..c42b32e69f3 100644 --- a/extensions/cornerstone-dicom-seg/src/utils/promptHydrateSEG.ts +++ b/extensions/cornerstone-dicom-seg/src/utils/promptHydrateSEG.ts @@ -63,6 +63,11 @@ function _askHydrate(uiViewportDialogService, viewportId) { uiViewportDialogService.hide(); resolve(RESPONSE.CANCEL); }, + onKeyPress: event => { + if (event.key === 'Enter') { + onSubmit(RESPONSE.HYDRATE_SEG); + } + }, }); }); } diff --git a/extensions/cornerstone-dynamic-volume/src/panels/DynamicVolumeControls.tsx b/extensions/cornerstone-dynamic-volume/src/panels/DynamicVolumeControls.tsx index 337e9e0a360..b780669f91a 100644 --- a/extensions/cornerstone-dynamic-volume/src/panels/DynamicVolumeControls.tsx +++ b/extensions/cornerstone-dynamic-volume/src/panels/DynamicVolumeControls.tsx @@ -22,7 +22,7 @@ const Header = ({ title, tooltip }) => (
{tooltip}
} - position="bottom" + position="bottom-left" tight={true} tooltipBoxClassName="max-w-xs" > diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/Colormap.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/Colormap.tsx index 335e54456d5..a37eae3a9be 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/Colormap.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/Colormap.tsx @@ -68,6 +68,11 @@ export function Colormap({ key: index, style: { minWidth: `calc(100% / ${displaySets.length})`, + fontSize: '0.8rem', + textAlign: 'center', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', }, })); }, [displaySets]); diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeLighting.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeLighting.tsx index 80b6452c69d..7cd7d4f853c 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeLighting.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeLighting.tsx @@ -60,7 +60,11 @@ export function VolumeLighting({ min={0} type="range" step={0.1} - style={{ background: calculateBackground(ambient) }} + style={{ + background: calculateBackground(ambient), + '--thumb-inner-color': '#5acce6', + '--thumb-outer-color': '#090c29', + }} /> )} @@ -84,7 +88,11 @@ export function VolumeLighting({ min={0} type="range" step={0.1} - style={{ background: calculateBackground(diffuse) }} + style={{ + background: calculateBackground(diffuse), + '--thumb-inner-color': '#5acce6', + '--thumb-outer-color': '#090c29', + }} /> )} @@ -109,7 +117,11 @@ export function VolumeLighting({ min={0} type="range" step={0.1} - style={{ background: calculateBackground(specular) }} + style={{ + background: calculateBackground(specular), + '--thumb-inner-color': '#5acce6', + '--thumb-outer-color': '#090c29', + }} /> )} diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingOptions.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingOptions.tsx index a75f0bd52ee..d666e354b4a 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingOptions.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingOptions.tsx @@ -25,10 +25,10 @@ export function VolumeRenderingOptions({ commandsManager={commandsManager} serviceManager={serviceManager} /> -
+
LIGHTING
- +
onChange(parseInt(e.target.value, 10))} - style={{ background: calculateBackground((quality - min) / (max - min)) }} + style={{ + background: calculateBackground((quality - min) / (max - min)), + '--thumb-inner-color': '#5acce6', + '--thumb-outer-color': '#090c29', + }} /> )}
diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShift.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShift.tsx index 6ad9eb9d37f..274f71599e2 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShift.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeShift.tsx @@ -82,6 +82,8 @@ export function VolumeShift({ step={step} style={{ background: calculateBackground((shift - minShift) / (maxShift - minShift)), + '--thumb-inner-color': '#5acce6', + '--thumb-outer-color': '#090c29', }} /> )} diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevel.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevel.tsx index 44b75bf938c..eda52d5bbe8 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevel.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevel.tsx @@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next'; export type WindowLevelProps = { viewportId: string; - presets: Record>; + presets: Array>>; commandsManager: CommandsManager; }; @@ -23,25 +23,34 @@ export function WindowLevel({ commandName: 'setViewportWindowLevel', commandOptions: { ...props, + viewportId, }, context: 'CORNERSTONE', }); }, - [commandsManager] + [commandsManager, viewportId] ); return ( - - {t('Modality Presets', { modality: Object.keys(presets)[0] })} - - {Object.values(presets)[0].map((preset, index) => ( - onSetWindowLevel({ ...preset, viewportId })} - > + {presets.map((modalityPresets, modalityIndex) => ( + + {Object.entries(modalityPresets).map(([modality, presetsArray]) => ( + + + {t('Modality Presets', { modality })} + + {presetsArray.map((preset, index) => ( + onSetWindowLevel(preset)} + /> + ))} + + ))} + ))} ); diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevelActionMenu.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevelActionMenu.tsx index b4db9fd211b..6905c9988d0 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevelActionMenu.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevelActionMenu.tsx @@ -19,7 +19,7 @@ import { utilities } from '@cornerstonejs/core'; export type WindowLevelActionMenuProps = { viewportId: string; element: HTMLElement; - presets: Record>; + presets: Array>>; verticalDirection: AllInOneMenu.VerticalDirection; horizontalDirection: AllInOneMenu.HorizontalDirection; commandsManager: CommandsManager; @@ -128,10 +128,8 @@ export function WindowLevelActionMenu({ iconClassName={classNames( // Visible on hover and for the active viewport activeViewportId === viewportId ? 'visible' : 'invisible group-hover:visible', - 'flex shrink-0 cursor-pointer rounded active:text-white', - isLight - ? 'text-aqua-pale hover:bg-secondary-dark' - : 'text-primary-light hover:bg-secondary-light/60' + 'flex shrink-0 cursor-pointer rounded active:text-white text-primary-light', + isLight ? ' hover:bg-secondary-dark' : 'hover:bg-secondary-light/60' )} menuStyle={{ maxHeight: vpHeight - 32, minWidth: 218 }} onVisibilityChange={() => { @@ -166,10 +164,10 @@ export function WindowLevelActionMenu({ )} - {presets && !is3DVolume && ( + {presets && presets.length > 0 && !is3DVolume && ( 0; - - return hasMenu ? ( + return ( - ) : null; + ); } diff --git a/extensions/cornerstone/src/getToolbarModule.tsx b/extensions/cornerstone/src/getToolbarModule.tsx index e58643da4e1..74a1162699b 100644 --- a/extensions/cornerstone/src/getToolbarModule.tsx +++ b/extensions/cornerstone/src/getToolbarModule.tsx @@ -43,8 +43,8 @@ export default function getToolbarModule({ commandsManager, servicesManager }) { return { disabled: false, className: isPrimaryActive - ? '!text-black bg-primary-light' - : '!text-common-bright hover:!bg-primary-dark hover:!text-primary-light', + ? '!text-black bg-primary-light rounded' + : '!text-common-bright hover:!bg-primary-dark hover:!text-primary-light rounded', // Todo: isActive right now is used for nested buttons where the primary // button needs to be fully rounded (vs partial rounded) when active // otherwise it does not have any other use diff --git a/extensions/cornerstone/src/hps/fourUp.ts b/extensions/cornerstone/src/hps/fourUp.ts index 69305e6c18a..df4056854f7 100644 --- a/extensions/cornerstone/src/hps/fourUp.ts +++ b/extensions/cornerstone/src/hps/fourUp.ts @@ -77,8 +77,11 @@ export const fourUp = { { id: 'mprDisplaySet', options: { - // ToDo: choose appropriate preset - displayPreset: 'CT-Bone', + displayPreset: { + CT: 'CT-Bone', + MR: 'MR-Default', + default: 'CT-Bone', + }, }, }, ], diff --git a/extensions/cornerstone/src/hps/main3D.ts b/extensions/cornerstone/src/hps/main3D.ts index a00ccc4a73b..5976dae2c43 100644 --- a/extensions/cornerstone/src/hps/main3D.ts +++ b/extensions/cornerstone/src/hps/main3D.ts @@ -77,8 +77,11 @@ export const main3D = { { id: 'mprDisplaySet', options: { - // ToDo: choose appropriate preset - displayPreset: 'CT-Bone', + displayPreset: { + CT: 'CT-Bone', + MR: 'MR-Default', + default: 'CT-Bone', + }, }, }, ], diff --git a/extensions/cornerstone/src/hps/mprAnd3DVolumeViewport.ts b/extensions/cornerstone/src/hps/mprAnd3DVolumeViewport.ts index 759ce1849a3..53289f8293e 100644 --- a/extensions/cornerstone/src/hps/mprAnd3DVolumeViewport.ts +++ b/extensions/cornerstone/src/hps/mprAnd3DVolumeViewport.ts @@ -84,7 +84,11 @@ export const mprAnd3DVolumeViewport = { { id: 'mprDisplaySet', options: { - displayPreset: 'CT-Bone', + displayPreset: { + CT: 'CT-Bone', + MR: 'MR-Default', + default: 'CT-Bone', + }, }, }, ], diff --git a/extensions/cornerstone/src/hps/only3D.ts b/extensions/cornerstone/src/hps/only3D.ts index 53c32cf61b9..17d6ceecd45 100644 --- a/extensions/cornerstone/src/hps/only3D.ts +++ b/extensions/cornerstone/src/hps/only3D.ts @@ -51,8 +51,11 @@ export const only3D = { { id: 'mprDisplaySet', options: { - // ToDo: choose appropriate preset - displayPreset: 'CT-Bone', + displayPreset: { + CT: 'CT-Bone', + MR: 'MR-Default', + default: 'CT-Bone', + }, }, }, ], diff --git a/extensions/cornerstone/src/hps/primary3D.ts b/extensions/cornerstone/src/hps/primary3D.ts index 11054d1065e..ebb8a59d9e7 100644 --- a/extensions/cornerstone/src/hps/primary3D.ts +++ b/extensions/cornerstone/src/hps/primary3D.ts @@ -77,8 +77,11 @@ export const primary3D = { { id: 'mprDisplaySet', options: { - // ToDo: choose appropriate preset - displayPreset: 'CT-Bone', + displayPreset: { + CT: 'CT-Bone', + MR: 'MR-Default', + default: 'CT-Bone', + }, }, }, ], diff --git a/extensions/cornerstone/src/init.tsx b/extensions/cornerstone/src/init.tsx index c06bff08af6..2282abb5b06 100644 --- a/extensions/cornerstone/src/init.tsx +++ b/extensions/cornerstone/src/init.tsx @@ -160,7 +160,7 @@ export default async function init({ const labelmapRepresentation = cornerstoneTools.Enums.SegmentationRepresentations.Labelmap; cornerstoneTools.segmentation.config.setGlobalRepresentationConfig(labelmapRepresentation, { - fillAlpha: 0.3, + fillAlpha: 0.5, fillAlphaInactive: 0.2, outlineOpacity: 1, outlineOpacityInactive: 0.65, diff --git a/extensions/cornerstone/src/initMeasurementService.js b/extensions/cornerstone/src/initMeasurementService.js index 61145aa184f..79d94f78f57 100644 --- a/extensions/cornerstone/src/initMeasurementService.js +++ b/extensions/cornerstone/src/initMeasurementService.js @@ -33,6 +33,8 @@ const initMeasurementService = ( PlanarFreehandROI, SplineROI, LivewireContour, + Probe, + UltrasoundDirectional, } = measurementServiceMappingsFactory( measurementService, displaySetService, @@ -157,6 +159,22 @@ const initMeasurementService = ( LivewireContour.toMeasurement ); + measurementService.addMapping( + csTools3DVer1MeasurementSource, + 'Probe', + Probe.matchingCriteria, + Probe.toAnnotation, + Probe.toMeasurement + ); + + measurementService.addMapping( + csTools3DVer1MeasurementSource, + 'UltrasoundDirectionalTool', + UltrasoundDirectional.matchingCriteria, + UltrasoundDirectional.toAnnotation, + UltrasoundDirectional.toMeasurement + ); + return csTools3DVer1MeasurementSource; }; diff --git a/extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts b/extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts index fa33ef58b1d..319884d6230 100644 --- a/extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts +++ b/extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts @@ -721,10 +721,14 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi } public async setVolumesForViewport(viewport, volumeInputArray, presentations) { - const { displaySetService, toolGroupService } = this.servicesManager.services; + const { displaySetService, toolGroupService, viewportGridService } = + this.servicesManager.services; const viewportInfo = this.getViewportInfo(viewport.id); const displaySetOptions = viewportInfo.getDisplaySetOptions(); + const displaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewport.id); + const displaySet = displaySetService.getDisplaySetByUID(displaySetUIDs[0]); + const displaySetModality = displaySet?.Modality; // Todo: use presentations states const volumesProperties = volumeInputArray.map((volumeInput, index) => { @@ -750,7 +754,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi } if (displayPreset !== undefined) { - properties.preset = displayPreset; + properties.preset = displayPreset[displaySetModality] || displayPreset.default; } return { properties, volumeId }; diff --git a/extensions/cornerstone/src/utils/colormaps.js b/extensions/cornerstone/src/utils/colormaps.js index 85946725cc1..a21df96ac81 100644 --- a/extensions/cornerstone/src/utils/colormaps.js +++ b/extensions/cornerstone/src/utils/colormaps.js @@ -1,4 +1,20 @@ const colormaps = [ + { + ColorSpace: 'RGB', + Name: 'Grayscale', + name: 'Grayscale', + NanColor: [1, 0, 0], + RGBPoints: [0, 0, 0, 0, 1, 1, 1, 1], + description: 'Grayscale', + }, + { + ColorSpace: 'RGB', + Name: 'X Ray', + name: 'X Ray', + NanColor: [1, 0, 0], + RGBPoints: [0, 1, 1, 1, 1, 0, 0, 0], + description: 'X Ray', + }, { ColorSpace: 'RGB', Name: 'hsv', @@ -1579,22 +1595,6 @@ const colormaps = [ ], description: 'Siemens', }, - { - ColorSpace: 'RGB', - Name: 'X Ray', - name: 'X Ray', - NanColor: [1, 0, 0], - RGBPoints: [0, 1, 1, 1, 1, 0, 0, 0], - description: 'X Ray', - }, - { - ColorSpace: 'RGB', - Name: 'Grayscale', - name: 'Grayscale', - NanColor: [1, 0, 0], - RGBPoints: [0, 0, 0, 0, 1, 1, 1, 1], - description: 'Grayscale', - }, ]; export { colormaps }; diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/Probe.ts b/extensions/cornerstone/src/utils/measurementServiceMappings/Probe.ts new file mode 100644 index 00000000000..554df184216 --- /dev/null +++ b/extensions/cornerstone/src/utils/measurementServiceMappings/Probe.ts @@ -0,0 +1,187 @@ +import SUPPORTED_TOOLS from './constants/supportedTools'; +import { getDisplayUnit } from './utils'; +import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes'; +import { utils } from '@ohif/core'; + +const Probe = { + toAnnotation: measurement => {}, + + /** + * Maps cornerstone annotation event data to measurement service format. + * + * @param {Object} cornerstone Cornerstone event data + * @return {Measurement} Measurement instance + */ + toMeasurement: ( + csToolsEventDetail, + displaySetService, + CornerstoneViewportService, + getValueTypeFromToolType, + customizationService + ) => { + const { annotation, viewportId } = csToolsEventDetail; + const { metadata, data, annotationUID } = annotation; + + if (!metadata || !data) { + console.warn('Length tool: Missing metadata or data'); + return null; + } + + const { toolName, referencedImageId, FrameOfReferenceUID } = metadata; + const validToolType = SUPPORTED_TOOLS.includes(toolName); + + if (!validToolType) { + throw new Error('Tool not supported'); + } + + const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } = + getSOPInstanceAttributes(referencedImageId); + + let displaySet; + + if (SOPInstanceUID) { + displaySet = displaySetService.getDisplaySetForSOPInstanceUID( + SOPInstanceUID, + SeriesInstanceUID + ); + } else { + displaySet = displaySetService.getDisplaySetsForSeries(SeriesInstanceUID); + } + + const { points } = data.handles; + + const mappedAnnotations = getMappedAnnotations(annotation, displaySetService); + + const displayText = getDisplayText(mappedAnnotations, displaySet, customizationService); + const getReport = () => + _getReport(mappedAnnotations, points, FrameOfReferenceUID, customizationService); + + return { + uid: annotationUID, + SOPInstanceUID, + FrameOfReferenceUID, + points, + metadata, + referenceSeriesUID: SeriesInstanceUID, + referenceStudyUID: StudyInstanceUID, + frameNumber: mappedAnnotations?.[0]?.frameNumber || 1, + toolName: metadata.toolName, + displaySetInstanceUID: displaySet.displaySetInstanceUID, + label: data.label, + displayText: displayText, + data: data.cachedStats, + type: getValueTypeFromToolType(toolName), + getReport, + }; + }, +}; + +function getMappedAnnotations(annotation, DisplaySetService) { + const { metadata, data } = annotation; + const { cachedStats } = data; + const { referencedImageId } = metadata; + const targets = Object.keys(cachedStats); + + if (!targets.length) { + return; + } + + const annotations = []; + Object.keys(cachedStats).forEach(targetId => { + const targetStats = cachedStats[targetId]; + + if (!referencedImageId) { + throw new Error('Non-acquisition plane measurement mapping not supported'); + } + + const { SOPInstanceUID, SeriesInstanceUID, frameNumber } = + getSOPInstanceAttributes(referencedImageId); + + const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID( + SOPInstanceUID, + SeriesInstanceUID, + frameNumber + ); + + const { SeriesNumber } = displaySet; + const { value } = targetStats; + const unit = 'HU'; + + annotations.push({ + SeriesInstanceUID, + SOPInstanceUID, + SeriesNumber, + frameNumber, + unit, + value, + }); + }); + + return annotations; +} + +/* +This function is used to convert the measurement data to a format that is +suitable for the report generation (e.g. for the csv report). The report +returns a list of columns and corresponding values. +*/ +function _getReport(mappedAnnotations, points, FrameOfReferenceUID, customizationService) { + const columns = []; + const values = []; + + // Add Type + columns.push('AnnotationType'); + values.push('Cornerstone:Probe'); + + mappedAnnotations.forEach(annotation => { + const { value, unit } = annotation; + columns.push(`Probe (${unit})`); + values.push(value); + }); + + if (FrameOfReferenceUID) { + columns.push('FrameOfReferenceUID'); + values.push(FrameOfReferenceUID); + } + + if (points) { + columns.push('points'); + values.push(points.map(p => p.join(' ')).join(';')); + } + + return { + columns, + values, + }; +} + +function getDisplayText(mappedAnnotations, displaySet, customizationService) { + if (!mappedAnnotations || !mappedAnnotations.length) { + return ''; + } + + const displayText = []; + + const { value, unit, SeriesNumber, SOPInstanceUID, frameNumber } = mappedAnnotations[0]; + + const instance = displaySet.images.find(image => image.SOPInstanceUID === SOPInstanceUID); + + let InstanceNumber; + if (instance) { + InstanceNumber = instance.InstanceNumber; + } + + const instanceText = InstanceNumber ? ` I: ${InstanceNumber}` : ''; + const frameText = displaySet.isMultiFrame ? ` F: ${frameNumber}` : ''; + if (value === undefined) { + return displayText; + } + const roundedValue = utils.roundNumber(value, 2); + displayText.push( + `${roundedValue} ${getDisplayUnit(unit)} (S: ${SeriesNumber}${instanceText}${frameText})` + ); + + return displayText; +} + +export default Probe; diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/UltrasoundDirectional.ts b/extensions/cornerstone/src/utils/measurementServiceMappings/UltrasoundDirectional.ts new file mode 100644 index 00000000000..f88973ae9f9 --- /dev/null +++ b/extensions/cornerstone/src/utils/measurementServiceMappings/UltrasoundDirectional.ts @@ -0,0 +1,206 @@ +import SUPPORTED_TOOLS from './constants/supportedTools'; +import { getDisplayUnit } from './utils'; +import getSOPInstanceAttributes from './utils/getSOPInstanceAttributes'; +import { utils } from '@ohif/core'; + +const UltrasoundDirectional = { + toAnnotation: measurement => {}, + + /** + * Maps cornerstone annotation event data to measurement service format. + * + * @param {Object} cornerstone Cornerstone event data + * @return {Measurement} Measurement instance + */ + toMeasurement: ( + csToolsEventDetail, + displaySetService, + CornerstoneViewportService, + getValueTypeFromToolType, + customizationService + ) => { + const { annotation, viewportId } = csToolsEventDetail; + const { metadata, data, annotationUID } = annotation; + + if (!metadata || !data) { + console.warn('Length tool: Missing metadata or data'); + return null; + } + + const { toolName, referencedImageId, FrameOfReferenceUID } = metadata; + const validToolType = SUPPORTED_TOOLS.includes(toolName); + + if (!validToolType) { + throw new Error('Tool not supported'); + } + + const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } = + getSOPInstanceAttributes(referencedImageId); + + let displaySet; + + if (SOPInstanceUID) { + displaySet = displaySetService.getDisplaySetForSOPInstanceUID( + SOPInstanceUID, + SeriesInstanceUID + ); + } else { + displaySet = displaySetService.getDisplaySetsForSeries(SeriesInstanceUID); + } + + const { points } = data.handles; + + const mappedAnnotations = getMappedAnnotations(annotation, displaySetService); + + const displayText = getDisplayText(mappedAnnotations, displaySet, customizationService); + const getReport = () => + _getReport(mappedAnnotations, points, FrameOfReferenceUID, customizationService); + + return { + uid: annotationUID, + SOPInstanceUID, + FrameOfReferenceUID, + points, + metadata, + referenceSeriesUID: SeriesInstanceUID, + referenceStudyUID: StudyInstanceUID, + frameNumber: mappedAnnotations?.[0]?.frameNumber || 1, + toolName: metadata.toolName, + displaySetInstanceUID: displaySet.displaySetInstanceUID, + label: data.label, + displayText: displayText, + data: data.cachedStats, + type: getValueTypeFromToolType(toolName), + getReport, + }; + }, +}; + +function getMappedAnnotations(annotation, DisplaySetService) { + const { metadata, data } = annotation; + const { cachedStats } = data; + const { referencedImageId } = metadata; + const targets = Object.keys(cachedStats); + + if (!targets.length) { + return; + } + + const annotations = []; + Object.keys(cachedStats).forEach(targetId => { + const targetStats = cachedStats[targetId]; + + if (!referencedImageId) { + throw new Error('Non-acquisition plane measurement mapping not supported'); + } + + const { SOPInstanceUID, SeriesInstanceUID, frameNumber } = + getSOPInstanceAttributes(referencedImageId); + + const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID( + SOPInstanceUID, + SeriesInstanceUID, + frameNumber + ); + + const { SeriesNumber } = displaySet; + const { xValues, yValues, units, isUnitless, isHorizontal } = targetStats; + + annotations.push({ + SeriesInstanceUID, + SOPInstanceUID, + SeriesNumber, + frameNumber, + xValues, + yValues, + units, + isUnitless, + isHorizontal, + }); + }); + + return annotations; +} + +/* +This function is used to convert the measurement data to a format that is +suitable for the report generation (e.g. for the csv report). The report +returns a list of columns and corresponding values. +*/ +function _getReport(mappedAnnotations, points, FrameOfReferenceUID, customizationService) { + const columns = []; + const values = []; + + // Add Type + columns.push('AnnotationType'); + values.push('Cornerstone:UltrasoundDirectional'); + + mappedAnnotations.forEach(annotation => { + const { xValues, yValues, units, isUnitless } = annotation; + if (isUnitless) { + columns.push('Length' + units[0]); + values.push(utils.roundNumber(xValues[0], 2)); + } else { + const dist1 = Math.abs(xValues[1] - xValues[0]); + const dist2 = Math.abs(yValues[1] - yValues[0]); + columns.push('Time' + units[0]); + values.push(utils.roundNumber(dist1, 2)); + columns.push('Length' + units[1]); + values.push(utils.roundNumber(dist2, 2)); + } + }); + + if (FrameOfReferenceUID) { + columns.push('FrameOfReferenceUID'); + values.push(FrameOfReferenceUID); + } + + if (points) { + columns.push('points'); + values.push(points.map(p => p.join(' ')).join(';')); + } + + return { + columns, + values, + }; +} + +function getDisplayText(mappedAnnotations, displaySet, customizationService) { + if (!mappedAnnotations || !mappedAnnotations.length) { + return ''; + } + + const displayText = []; + + const { xValues, yValues, units, isUnitless, SeriesNumber, SOPInstanceUID, frameNumber } = + mappedAnnotations[0]; + + const instance = displaySet.images.find(image => image.SOPInstanceUID === SOPInstanceUID); + + let InstanceNumber; + if (instance) { + InstanceNumber = instance.InstanceNumber; + } + + const instanceText = InstanceNumber ? ` I: ${InstanceNumber}` : ''; + const frameText = displaySet.isMultiFrame ? ` F: ${frameNumber}` : ''; + const seriesText = `(S: ${SeriesNumber}${instanceText}${frameText})`; + + if (xValues === undefined || yValues === undefined) { + return displayText; + } + + if (isUnitless) { + displayText.push(`${utils.roundNumber(xValues[0], 2)} ${units[0]} ${seriesText}`); + } else { + const dist1 = Math.abs(xValues[1] - xValues[0]); + const dist2 = Math.abs(yValues[1] - yValues[0]); + displayText.push(`${utils.roundNumber(dist1)} ${units[0]} ${seriesText}`); + displayText.push(`${utils.roundNumber(dist2)} ${units[1]} ${seriesText}`); + } + + return displayText; +} + +export default UltrasoundDirectional; diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/constants/supportedTools.js b/extensions/cornerstone/src/utils/measurementServiceMappings/constants/supportedTools.js index 8f69319dae5..9f7bbb04a61 100644 --- a/extensions/cornerstone/src/utils/measurementServiceMappings/constants/supportedTools.js +++ b/extensions/cornerstone/src/utils/measurementServiceMappings/constants/supportedTools.js @@ -11,4 +11,6 @@ export default [ 'PlanarFreehandROI', 'SplineROI', 'LivewireContour', + 'Probe', + 'UltrasoundDirectionalTool', ]; diff --git a/extensions/cornerstone/src/utils/measurementServiceMappings/measurementServiceMappingsFactory.ts b/extensions/cornerstone/src/utils/measurementServiceMappings/measurementServiceMappingsFactory.ts index 19de0308f6a..0cc991fe7b6 100644 --- a/extensions/cornerstone/src/utils/measurementServiceMappings/measurementServiceMappingsFactory.ts +++ b/extensions/cornerstone/src/utils/measurementServiceMappings/measurementServiceMappingsFactory.ts @@ -10,6 +10,8 @@ import PlanarFreehandROI from './PlanarFreehandROI'; import RectangleROI from './RectangleROI'; import SplineROI from './SplineROI'; import LivewireContour from './LivewireContour'; +import Probe from './Probe'; +import UltrasoundDirectional from './UltrasoundDirectional'; const measurementServiceMappingsFactory = ( measurementService: MeasurementService, @@ -44,6 +46,8 @@ const measurementServiceMappingsFactory = ( Angle: ANGLE, SplineROI: POLYLINE, LivewireContour: POLYLINE, + Probe: POINT, + UltrasoundDirectional: POLYLINE, }; return TOOL_TYPE_TO_VALUE_TYPE[toolType]; @@ -211,6 +215,24 @@ const measurementServiceMappingsFactory = ( ], }, + Probe: { + toAnnotation: Probe.toAnnotation, + toMeasurement: csToolsAnnotation => + Probe.toMeasurement( + csToolsAnnotation, + displaySetService, + cornerstoneViewportService, + _getValueTypeFromToolType, + customizationService + ), + matchingCriteria: [ + { + valueType: MeasurementService.VALUE_TYPES.POINT, + points: 1, + }, + ], + }, + CobbAngle: { toAnnotation: CobbAngle.toAnnotation, toMeasurement: csToolsAnnotation => @@ -244,6 +266,23 @@ const measurementServiceMappingsFactory = ( }, ], }, + UltrasoundDirectional: { + toAnnotation: UltrasoundDirectional.toAnnotation, + toMeasurement: csToolsAnnotation => + UltrasoundDirectional.toMeasurement( + csToolsAnnotation, + displaySetService, + cornerstoneViewportService, + _getValueTypeFromToolType, + customizationService + ), + matchingCriteria: [ + { + valueType: MeasurementService.VALUE_TYPES.POLYLINE, + points: 2, + }, + ], + }, }; return factories; diff --git a/extensions/default/src/ViewerLayout/ViewerHeader.tsx b/extensions/default/src/ViewerLayout/ViewerHeader.tsx index 9d676bcbe1f..6d5ab60f734 100644 --- a/extensions/default/src/ViewerLayout/ViewerHeader.tsx +++ b/extensions/default/src/ViewerLayout/ViewerHeader.tsx @@ -53,6 +53,7 @@ function ViewerHeader({ hotkeysManager, extensionManager, servicesManager, appCo content: AboutModal, title: t('AboutModal:About OHIF Viewer'), contentProps: { versionNumber, commitHash }, + containerDimensions: 'max-w-4xl max-h-4xl', }), }, { @@ -114,7 +115,7 @@ function ViewerHeader({ hotkeysManager, extensionManager, servicesManager, appCo appConfig={appConfig} > -
+
diff --git a/extensions/default/src/commandsModule.ts b/extensions/default/src/commandsModule.ts index c8666323987..04fd5402911 100644 --- a/extensions/default/src/commandsModule.ts +++ b/extensions/default/src/commandsModule.ts @@ -445,6 +445,7 @@ const commandsModule = ({ displaySetInstanceUID, onClose: UIModalService.hide, }, + containerDimensions: 'max-w-4xl max-h-4xl', title: 'DICOM Tag Browser', }); }, diff --git a/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptHydrateStructuredReport.js b/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptHydrateStructuredReport.js index 1881337ce2f..579ff9c7b32 100644 --- a/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptHydrateStructuredReport.js +++ b/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptHydrateStructuredReport.js @@ -74,6 +74,12 @@ function _askTrackMeasurements(uiViewportDialogService, viewportId) { uiViewportDialogService.hide(); resolve(RESPONSE.CANCEL); }, + onKeyPress: event => { + if (event.key === 'Enter') { + const action = actions.find(action => action.value === RESPONSE.HYDRATE_REPORT); + onSubmit(action.value); + } + }, }); }); } diff --git a/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx b/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx index c085b15fb03..4d9dc3a4d5e 100644 --- a/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx +++ b/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx @@ -329,6 +329,65 @@ function PanelStudyBrowserTracking({ } }, [expandedStudyInstanceUIDs, jumpToDisplaySet, tabs]); + const onClickUntrack = displaySetInstanceUID => { + const onConfirm = () => { + const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID); + sendTrackedMeasurementsEvent('UNTRACK_SERIES', { + SeriesInstanceUID: displaySet.SeriesInstanceUID, + }); + const measurements = measurementService.getMeasurements(); + measurements.forEach(m => { + if (m.referenceSeriesUID === displaySet.SeriesInstanceUID) { + measurementService.remove(m.uid); + } + }); + }; + + uiDialogService.create({ + id: 'untrack-series', + centralize: true, + isDraggable: false, + showOverlay: true, + content: Dialog, + contentProps: { + title: 'Untrack Series', + body: () => ( +
+

Are you sure you want to untrack this series?

+

+ This action cannot be undone and will delete all your existing measurements. +

+
+ ), + actions: [ + { + id: 'cancel', + text: 'Cancel', + type: ButtonEnums.type.secondary, + }, + { + id: 'yes', + text: 'Yes', + type: ButtonEnums.type.primary, + classes: ['untrack-yes-button'], + }, + ], + onClose: () => uiDialogService.dismiss({ id: 'untrack-series' }), + onSubmit: async ({ action }) => { + switch (action.id) { + case 'yes': + onConfirm(); + uiDialogService.dismiss({ id: 'untrack-series' }); + break; + case 'cancel': + uiDialogService.dismiss({ id: 'untrack-series' }); + break; + } + }, + }, + }); + }; + return ( { - const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID); - // TODO: shift this somewhere else where we're centralizing this logic? - // Potentially a helper from displaySetInstanceUID to this - sendTrackedMeasurementsEvent('UNTRACK_SERIES', { - SeriesInstanceUID: displaySet.SeriesInstanceUID, - }); - const measurements = measurementService.getMeasurements(); - measurements.forEach(m => { - if (m.referenceSeriesUID === displaySet.SeriesInstanceUID) { - measurementService.remove(m.uid); - } - }); + onClickUntrack(displaySetInstanceUID); }} onClickThumbnail={() => {}} onDoubleClickThumbnail={onDoubleClickThumbnailHandler} diff --git a/extensions/tmtv/src/Panels/PanelPetSUV.tsx b/extensions/tmtv/src/Panels/PanelPetSUV.tsx index 3252a08ac16..eccd76afbf8 100644 --- a/extensions/tmtv/src/Panels/PanelPetSUV.tsx +++ b/extensions/tmtv/src/Panels/PanelPetSUV.tsx @@ -127,7 +127,7 @@ export default function PanelPetSUV({ servicesManager, commandsManager }) { } return (
-
+
diff --git a/extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/PanelROIThresholdExport.tsx b/extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/PanelROIThresholdExport.tsx index d8da1f50459..181240e6cbd 100644 --- a/extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/PanelROIThresholdExport.tsx +++ b/extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/PanelROIThresholdExport.tsx @@ -77,7 +77,7 @@ export default function PanelRoiThresholdSegmentation({ servicesManager, command return ( <> -
+
{tmtvValue !== null ? (
@@ -87,7 +87,7 @@ export default function PanelRoiThresholdSegmentation({ servicesManager, command
{`${tmtvValue} mL`}
) : null} -
+
), title: (instances || 0).toString(), - gridCol: 4, + gridCol: 2, }, ], // Todo: This is actually running for all rows, even if they are @@ -454,6 +454,7 @@ function WorkList({ content: AboutModal, title: t('AboutModal:About OHIF Viewer'), contentProps: { versionNumber, commitHash }, + containerDimensions: 'max-w-4xl max-h-4xl', }), }, { diff --git a/platform/docs/docs/configuration/configurationFiles.md b/platform/docs/docs/configuration/configurationFiles.md index be62938f330..1c945f4cbf3 100644 --- a/platform/docs/docs/configuration/configurationFiles.md +++ b/platform/docs/docs/configuration/configurationFiles.md @@ -123,7 +123,8 @@ Here are a list of some options available: what is specified by `maxNumberOfWebWorkers`. Some windows machines require smaller values. - `acceptHeader` : accept header to request specific dicom transfer syntax ex : [ 'multipart/related; type=image/jls; q=1', 'multipart/related; type=application/octet-stream; q=0.1' ] - `investigationalUseDialog`: This should contain an object with `option` value, it can be either `always` which always shows the dialog once per session, `never` which never shows the dialog, or `configure` which shows the dialog once and won't show it again until a set number of days defined by the user, if it's set to configure, you are required to add an additional property `days` which is the number of days to wait before showing the dialog again. -- `groupEnabled`: boolean, if set to true, all valid modes for the study get grouped together first, then the rest of the modes. If false, all modes are shown in the order they are defined in the configuration. +- `groupEnabledModesFirst`: boolean, if set to true, all valid modes for the study get grouped together first, then the rest of the modes. If false, all modes are shown in the order they are defined in the configuration. +- `showPatientInfo`: string, if set to 'visible', the patient info header will be shown and its initial state is expanded. If set to 'visibleCollapsed', the patient info header will be shown but it's initial state is collapsed. If set to 'disabled', the patient info header will never be shown, and if set to 'visibleReadOnly', the patient info header will be shown and always expanded. - `requestTransferSyntaxUID` : Request a specific Transfer syntax from dicom web server ex: 1.2.840.10008.1.2.4.80 (applied only if acceptHeader is not set) - `omitQuotationForMultipartRequest`: Some servers (e.g., .NET) require the `multipart/related` request to be sent without quotation marks. Defaults to `false`. If your server doesn't require this, then setting this flag to `true` might improve performance (by removing the need for preflight requests). Also note that if auth headers are used, a preflight request is required. diff --git a/platform/ui/src/assets/icons/tool-layout.svg b/platform/ui/src/assets/icons/tool-layout.svg index 7e8bf149488..2ebbcabc6fa 100644 --- a/platform/ui/src/assets/icons/tool-layout.svg +++ b/platform/ui/src/assets/icons/tool-layout.svg @@ -3,19 +3,20 @@ tool-layout - - - - - + + + + + + + - + - \ No newline at end of file diff --git a/platform/ui/src/assets/icons/tool-seg-brush.svg b/platform/ui/src/assets/icons/tool-seg-brush.svg new file mode 100644 index 00000000000..2258260d96f --- /dev/null +++ b/platform/ui/src/assets/icons/tool-seg-brush.svg @@ -0,0 +1,9 @@ + + + tool-seg-brush + + + + + + \ No newline at end of file diff --git a/platform/ui/src/assets/icons/tool-seg-eraser.svg b/platform/ui/src/assets/icons/tool-seg-eraser.svg new file mode 100644 index 00000000000..a1f78fed4ee --- /dev/null +++ b/platform/ui/src/assets/icons/tool-seg-eraser.svg @@ -0,0 +1,10 @@ + + + tool-seg-eraser + + + + + + + \ No newline at end of file diff --git a/platform/ui/src/assets/icons/tool-seg-shape.svg b/platform/ui/src/assets/icons/tool-seg-shape.svg new file mode 100644 index 00000000000..290d156e6ca --- /dev/null +++ b/platform/ui/src/assets/icons/tool-seg-shape.svg @@ -0,0 +1,9 @@ + + + tool-seg-shape + + + + + + \ No newline at end of file diff --git a/platform/ui/src/assets/icons/tool-seg-threshold.svg b/platform/ui/src/assets/icons/tool-seg-threshold.svg new file mode 100644 index 00000000000..4870fa5a495 --- /dev/null +++ b/platform/ui/src/assets/icons/tool-seg-threshold.svg @@ -0,0 +1,17 @@ + + + tool-seg-threshold + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platform/ui/src/components/ButtonGroup/ButtonGroup.tsx b/platform/ui/src/components/ButtonGroup/ButtonGroup.tsx index a8f89d24957..32b29408293 100644 --- a/platform/ui/src/components/ButtonGroup/ButtonGroup.tsx +++ b/platform/ui/src/components/ButtonGroup/ButtonGroup.tsx @@ -40,27 +40,30 @@ const ButtonGroup = ({ 'border-secondary-light rounded-[5px] border bg-black': !separated, })} > - {!separated && - Children.map(children, (child, index) => { - if (React.isValidElement(child)) { - return cloneElement(child, { - key: index, - className: classnames( - 'rounded-[4px] px-2 py-1', - index === activeIndex - ? 'bg-customblue-40 text-white' - : 'text-primary-active bg-black', - child.props.className, - disabled ? 'ohif-disabled' : '' - ), - onClick: e => { - child.props.onClick && child.props.onClick(e); - handleButtonClick(index); - }, - }); - } - return child; - })} + {!separated && ( +
+ {Children.map(children, (child, index) => { + if (React.isValidElement(child)) { + return cloneElement(child, { + key: index, + className: classnames( + 'rounded-[4px] px-2 py-1', + index === activeIndex + ? 'bg-customblue-40 text-white' + : 'text-primary-active bg-black', + child.props.className, + disabled ? 'ohif-disabled' : '' + ), + onClick: e => { + child.props.onClick && child.props.onClick(e); + handleButtonClick(index); + }, + }); + } + return child; + })} +
+ )} {separated && (
{Children.map(children, (child, index) => { diff --git a/platform/ui/src/components/Header/Header.tsx b/platform/ui/src/components/Header/Header.tsx index 2ba958b089c..c75dfa9231b 100644 --- a/platform/ui/src/components/Header/Header.tsx +++ b/platform/ui/src/components/Header/Header.tsx @@ -65,8 +65,7 @@ function Header({
{children}
- {(showPatientInfo === PatientInfoVisibility.VISIBLE || - showPatientInfo === PatientInfoVisibility.VISIBLE_COLLAPSED) && ( + {showPatientInfo !== PatientInfoVisibility.DISABLED && ( { - if (!isMixedPatients) { + if (!isMixedPatients && appConfig.showPatientInfo !== PatientInfoVisibility.VISIBLE_READONLY) { setExpanded(!expanded); } }; diff --git a/platform/ui/src/components/Icon/getIcon.js b/platform/ui/src/components/Icon/getIcon.js index c2edee38dc9..494b8ce3bfe 100644 --- a/platform/ui/src/components/Icon/getIcon.js +++ b/platform/ui/src/components/Icon/getIcon.js @@ -145,11 +145,11 @@ import iconAdd from './../../assets/icons/icon-add.svg'; import iconRename from './../../assets/icons/icon-rename.svg'; import iconDelete from './../../assets/icons/icon-delete.svg'; import iconMoreMenu from './../../assets/icons/icon-more-menu.svg'; -import iconToolBrush from './../../assets/icons/icon-tool-brush.svg'; -import iconToolEraser from './../../assets/icons/icon-tool-eraser.svg'; +import iconToolBrush from './../../assets/icons/tool-seg-brush.svg'; +import iconToolEraser from './../../assets/icons/tool-seg-eraser.svg'; import iconToolScissor from './../../assets/icons/icon-tool-scissor.svg'; -import iconToolShape from './../../assets/icons/icon-tool-shape.svg'; -import iconToolThreshold from './../../assets/icons/icon-tool-threshold.svg'; +import iconToolShape from './../../assets/icons/tool-seg-shape.svg'; +import iconToolThreshold from './../../assets/icons/tool-seg-threshold.svg'; import viewportWindowLevel from './../../assets/icons/viewport-window-level.svg'; import dicomTagBrowser from './../../assets/icons/tool-dicom-tag-browser.svg'; import iconToolFreehandRoi from './../../assets/icons/tool-freehand-roi.svg'; diff --git a/platform/ui/src/components/IconButton/IconButton.tsx b/platform/ui/src/components/IconButton/IconButton.tsx index ea6922455d7..fff9d168f7b 100644 --- a/platform/ui/src/components/IconButton/IconButton.tsx +++ b/platform/ui/src/components/IconButton/IconButton.tsx @@ -64,6 +64,7 @@ const iconSizeClasses = { medium: 'w-5 h-5', large: 'w-6 h-6', toolbar: 'w-[28px] h-[28px]', + toolbox: 'w-[24px] h-[24px]', }; const fullWidthClasses = { @@ -92,7 +93,7 @@ const IconButton = ({ onClick(e); }; - const padding = size === 'toolbar' ? '6px' : size === 'toolbox' ? '6px' : null; + const padding = size === 'toolbar' ? '6px' : size === 'toolbox' ? '4px' : null; return (