From 0afb3fc75314c1d8d6c50d13f31d5c2fc6849ce2 Mon Sep 17 00:00:00 2001 From: Joe Boccanfuso <109477394+jbocce@users.noreply.github.com> Date: Sat, 7 Jun 2025 13:55:33 -0400 Subject: [PATCH] fix(WindowLevelActionMenu): The window level menu must show different contents for 3D volume viewports (#5113) --- bun.lock | 56 +++++++++---------- .../VolumeRenderingPresetsContent.tsx | 9 +-- .../WindowLevelActionMenu.tsx | 1 - .../src/hooks/useViewportRendering.tsx | 12 +++- .../src/components/AllInOneMenu/Menu.tsx | 9 +++ 5 files changed, 50 insertions(+), 37 deletions(-) diff --git a/bun.lock b/bun.lock index 67b267182..5ee66e261 100644 --- a/bun.lock +++ b/bun.lock @@ -40,7 +40,7 @@ }, "addOns/externals/devDependencies": { "name": "@externals/devDependencies", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "@kitware/vtk.js": "32.12.0", @@ -127,14 +127,14 @@ }, "addOns/externals/dicom-microscopy-viewer": { "name": "@externals/dicom-microscopy-viewer", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "dicom-microscopy-viewer": "^0.46.1", }, }, "extensions/cornerstone": { "name": "@ohif/extension-cornerstone", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^3.15.6", @@ -173,7 +173,7 @@ }, "extensions/cornerstone-dicom-pmap": { "name": "@ohif/extension-cornerstone-dicom-pmap", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^3.15.6", @@ -196,7 +196,7 @@ }, "extensions/cornerstone-dicom-rt": { "name": "@ohif/extension-cornerstone-dicom-rt", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "react-color": "^2.19.3", @@ -216,7 +216,7 @@ }, "extensions/cornerstone-dicom-seg": { "name": "@ohif/extension-cornerstone-dicom-seg", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^3.15.6", @@ -239,7 +239,7 @@ }, "extensions/cornerstone-dicom-sr": { "name": "@ohif/extension-cornerstone-dicom-sr", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/adapters": "^3.15.6", @@ -261,7 +261,7 @@ }, "extensions/cornerstone-dynamic-volume": { "name": "@ohif/extension-cornerstone-dynamic-volume", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/core": "^3.15.6", @@ -283,7 +283,7 @@ }, "extensions/default": { "name": "@ohif/extension-default", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/calculate-suv": "^1.1.0", @@ -306,7 +306,7 @@ }, "extensions/dicom-microscopy": { "name": "@ohif/extension-dicom-microscopy", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/codec-charls": "^1.2.3", @@ -331,7 +331,7 @@ }, "extensions/dicom-pdf": { "name": "@ohif/extension-dicom-pdf", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", @@ -348,7 +348,7 @@ }, "extensions/dicom-video": { "name": "@ohif/extension-dicom-video", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", @@ -365,7 +365,7 @@ }, "extensions/measurement-tracking": { "name": "@ohif/extension-measurement-tracking", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "@ohif/ui": "platform/ui", @@ -391,7 +391,7 @@ }, "extensions/test-extension": { "name": "@ohif/extension-test", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", @@ -408,7 +408,7 @@ }, "extensions/tmtv": { "name": "@ohif/extension-tmtv", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", @@ -425,7 +425,7 @@ }, "modes/basic-dev-mode": { "name": "@ohif/mode-basic-dev-mode", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -445,7 +445,7 @@ }, "modes/basic-test-mode": { "name": "@ohif/mode-test", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -467,7 +467,7 @@ }, "modes/longitudinal": { "name": "@ohif/mode-longitudinal", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -490,7 +490,7 @@ }, "modes/microscopy": { "name": "@ohif/mode-microscopy", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -502,7 +502,7 @@ }, "modes/preclinical-4d": { "name": "@ohif/mode-preclinical-4d", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", }, @@ -521,7 +521,7 @@ }, "modes/segmentation": { "name": "@ohif/mode-segmentation", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -565,7 +565,7 @@ }, "modes/tmtv": { "name": "@ohif/mode-tmtv", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -586,7 +586,7 @@ }, "platform/app": { "name": "@ohif/app", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/codec-charls": "^1.2.3", @@ -652,7 +652,7 @@ }, "platform/cli": { "name": "@ohif/cli", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/core": "7.24.7", "axios": "^1.8.4", @@ -673,7 +673,7 @@ }, "platform/core": { "name": "@ohif/core", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "dcmjs": "*", @@ -707,7 +707,7 @@ }, "platform/i18n": { "name": "@ohif/i18n", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@babel/runtime": "^7.20.13", "i18next-locize-backend": "^2.0.0", @@ -732,7 +732,7 @@ }, "platform/ui": { "name": "@ohif/ui", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@testing-library/react": "^13.1.0", "browser-detect": "^0.2.28", @@ -792,7 +792,7 @@ }, "platform/ui-next": { "name": "@ohif/ui-next", - "version": "3.11.0-beta.47", + "version": "3.11.0-beta.48", "dependencies": { "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-checkbox": "^1.1.1", diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingPresetsContent.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingPresetsContent.tsx index c1275ea65..1d048bba4 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingPresetsContent.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/VolumeRenderingPresetsContent.tsx @@ -2,17 +2,14 @@ import { Icons, FooterAction } from '@ohif/ui-next'; import React, { ReactElement, useState, useCallback } from 'react'; import { PresetDialog } from '@ohif/ui-next'; import { ViewportPreset, VolumeRenderingPresetsContentProps } from '../../types/ViewportPresets'; +import { useSystem } from '@ohif/core'; interface Props extends VolumeRenderingPresetsContentProps { hide: () => void; } -export function VolumeRenderingPresetsContent({ - presets, - viewportId, - commandsManager, - hide, -}: Props): ReactElement { +export function VolumeRenderingPresetsContent({ presets, viewportId, hide }: Props): ReactElement { + const { commandsManager } = useSystem(); const [searchValue, setSearchValue] = useState(''); const [selectedPreset, setSelectedPreset] = useState(null); diff --git a/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevelActionMenu.tsx b/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevelActionMenu.tsx index 0634d15bf..4bd9bdca8 100644 --- a/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevelActionMenu.tsx +++ b/extensions/cornerstone/src/components/WindowLevelActionMenu/WindowLevelActionMenu.tsx @@ -53,7 +53,6 @@ export function WindowLevelActionMenuContent({ return ( { return Math.pow(opacityValue, 1.0 / GAMMA); }; +const is3DViewport = ({ viewportId, cornerstoneViewportService }) => { + const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId); + return viewport instanceof VolumeViewport3D; +}; + /** * Hook to access window level functionality for a specific viewport * @@ -119,7 +124,9 @@ export function useViewportRendering( const { cornerstoneViewportService, colorbarService, customizationService } = servicesManager.services; - const [is3DVolume, setIs3DVolume] = useState(false); + const [is3DVolume, setIs3DVolume] = useState( + is3DViewport({ viewportId, cornerstoneViewportService }) + ); const [hasColorbar, setHasColorbar] = useState(colorbarService.hasColorbar(viewportId)); const [colorbarPosition, setColorbarPosition] = useState( options?.location ? getPosition(options.location) : 'bottom' @@ -233,8 +240,9 @@ export function useViewportRendering( }, [allWindowLevelPresets, activeDisplaySetInstanceUID]); useEffect(() => { + setIs3DVolume(is3DViewport({ viewportId, cornerstoneViewportService })); + const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId); - setIs3DVolume(viewport instanceof VolumeViewport3D); // Initialize the VOI range from the viewport if (viewport && activeDisplaySetInstanceUID) { diff --git a/platform/ui-next/src/components/AllInOneMenu/Menu.tsx b/platform/ui-next/src/components/AllInOneMenu/Menu.tsx index d769ddb5b..8fb497414 100644 --- a/platform/ui-next/src/components/AllInOneMenu/Menu.tsx +++ b/platform/ui-next/src/components/AllInOneMenu/Menu.tsx @@ -108,6 +108,15 @@ const Menu = (props: MenuProps) => { ]); const [itemPanelLabels, setItemPanelLabels] = useState>([]); + // If the props change for the this top level menu then we have to update the menu path + // because the props to be rendered are maintained in the state. + useEffect(() => { + setMenuPath(menuPath => [ + { props, activePanelIndex: activePanelIndex || 0 }, + ...menuPath.slice(1), + ]); + }, [activePanelIndex, props]); + const hideMenu = useCallback(() => { if (preventHideMenu) { return;