From 3653de748731199d130f02200becde78c07d3303 Mon Sep 17 00:00:00 2001 From: Alireza Date: Mon, 7 Apr 2025 16:45:29 -0400 Subject: [PATCH] fix(segmentation): Add segment jump for new segments and make panels scrollable (#4928) --- .circleci/config.yml | 4 +- addOns/externals/devDependencies/package.json | 2 +- bun.lock | 284 +++++++++--------- .../cornerstone-dicom-pmap/package.json | 4 +- extensions/cornerstone-dicom-seg/package.json | 4 +- extensions/cornerstone-dicom-sr/package.json | 6 +- .../cornerstone-dynamic-volume/package.json | 4 +- extensions/cornerstone/package.json | 14 +- .../segmentationPanelCustomization.tsx | 1 + .../SegmentationService.ts | 14 +- .../Panels/StudyBrowser/PanelStudyBrowser.tsx | 4 +- .../src/ViewerLayout/constants/panels.ts | 2 +- extensions/measurement-tracking/package.json | 4 +- .../PanelROIThresholdExport.tsx | 38 ++- platform/app/package.json | 2 +- platform/cli/package.json | 2 +- platform/core/package.json | 4 +- .../SegmentationExpanded.tsx | 51 ++-- .../SegmentationSegments.tsx | 172 ++++++----- .../ThumbnailList/ThumbnailList.tsx | 122 ++++---- .../ui-next/src/hooks/useDynamicMaxHeight.ts | 50 +++ platform/ui/package.json | 2 +- yarn.lock | 69 +++-- 23 files changed, 491 insertions(+), 368 deletions(-) create mode 100644 platform/ui-next/src/hooks/useDynamicMaxHeight.ts diff --git a/.circleci/config.yml b/.circleci/config.yml index 8079e8eb1..b378b8573 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -242,7 +242,7 @@ jobs: - setup_remote_docker: docker_layer_caching: false - run: - name: Build Docker image for arm64 + name: Build Docker image for arm64 (Release) command: | # This file will exist if a new version was published by # our command in the previous job. @@ -369,7 +369,7 @@ jobs: - setup_remote_docker: docker_layer_caching: false - run: - name: Create and push multi-architecture manifest + name: Create and push multi-architecture manifest (Release) command: | # This file will exist if a new version was published by # our command in the previous job. diff --git a/addOns/externals/devDependencies/package.json b/addOns/externals/devDependencies/package.json index 17532676a..fc075f023 100644 --- a/addOns/externals/devDependencies/package.json +++ b/addOns/externals/devDependencies/package.json @@ -13,7 +13,7 @@ "@kitware/vtk.js": "32.12.0", "clsx": "^2.1.1", "core-js": "^3.2.1", - "moment": "^2.9.4" + "moment": "^2.30.1" }, "peerDependencies": { "react": "^18.3.1", diff --git a/bun.lock b/bun.lock index 7739c1f2d..1855c6374 100644 --- a/bun.lock +++ b/bun.lock @@ -33,13 +33,13 @@ }, "addOns/externals/devDependencies": { "name": "@externals/devDependencies", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "@kitware/vtk.js": "32.12.0", "clsx": "^2.1.1", "core-js": "^3.2.1", - "moment": "^2.9.4", + "moment": "^2.30.1", }, "devDependencies": { "@pmmmwh/react-refresh-webpack-plugin": "^0.5.15", @@ -121,22 +121,22 @@ }, "addOns/externals/dicom-microscopy-viewer": { "name": "@externals/dicom-microscopy-viewer", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "dicom-microscopy-viewer": "^0.46.1", }, }, "extensions/cornerstone": { "name": "@ohif/extension-cornerstone", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^3.8.5", - "@cornerstonejs/ai": "^3.8.5", - "@cornerstonejs/core": "^3.8.5", - "@cornerstonejs/labelmap-interpolation": "^3.8.5", - "@cornerstonejs/polymorphic-segmentation": "^3.8.5", - "@cornerstonejs/tools": "^3.8.5", + "@cornerstonejs/adapters": "^3.9.1", + "@cornerstonejs/ai": "^3.9.1", + "@cornerstonejs/core": "^3.9.1", + "@cornerstonejs/labelmap-interpolation": "^3.9.1", + "@cornerstonejs/polymorphic-segmentation": "^3.9.1", + "@cornerstonejs/tools": "^3.9.1", "@itk-wasm/morphological-contour-interpolation": "1.1.0", "@kitware/vtk.js": "32.12.0", "html2canvas": "^1.4.1", @@ -153,9 +153,9 @@ "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjph": "^2.4.5", - "@cornerstonejs/dicom-image-loader": "^3.8.5", - "@ohif/core": "3.10.0-beta.147", - "@ohif/ui": "3.10.0-beta.147", + "@cornerstonejs/dicom-image-loader": "^3.9.1", + "@ohif/core": "3.10.0-beta.150", + "@ohif/ui": "3.10.0-beta.150", "dcmjs": "*", "dicom-parser": "^1.8.21", "hammerjs": "^2.0.8", @@ -167,19 +167,19 @@ }, "extensions/cornerstone-dicom-pmap": { "name": "@ohif/extension-cornerstone-dicom-pmap", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^3.8.5", - "@cornerstonejs/core": "^3.8.5", + "@cornerstonejs/adapters": "^3.9.1", + "@cornerstonejs/core": "^3.9.1", "@kitware/vtk.js": "32.12.0", "react-color": "^2.19.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.147", - "@ohif/extension-cornerstone": "3.10.0-beta.147", - "@ohif/extension-default": "3.10.0-beta.147", - "@ohif/i18n": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/extension-cornerstone": "3.10.0-beta.150", + "@ohif/extension-default": "3.10.0-beta.150", + "@ohif/i18n": "3.10.0-beta.150", "prop-types": "^15.6.2", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -190,16 +190,16 @@ }, "extensions/cornerstone-dicom-rt": { "name": "@ohif/extension-cornerstone-dicom-rt", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "react-color": "^2.19.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.147", - "@ohif/extension-cornerstone": "3.10.0-beta.147", - "@ohif/extension-default": "3.10.0-beta.147", - "@ohif/i18n": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/extension-cornerstone": "3.10.0-beta.150", + "@ohif/extension-default": "3.10.0-beta.150", + "@ohif/i18n": "3.10.0-beta.150", "prop-types": "^15.6.2", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -210,19 +210,19 @@ }, "extensions/cornerstone-dicom-seg": { "name": "@ohif/extension-cornerstone-dicom-seg", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^3.8.5", - "@cornerstonejs/core": "^3.8.5", + "@cornerstonejs/adapters": "^3.9.1", + "@cornerstonejs/core": "^3.9.1", "@kitware/vtk.js": "32.12.0", "react-color": "^2.19.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.147", - "@ohif/extension-cornerstone": "3.10.0-beta.147", - "@ohif/extension-default": "3.10.0-beta.147", - "@ohif/i18n": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/extension-cornerstone": "3.10.0-beta.150", + "@ohif/extension-default": "3.10.0-beta.150", + "@ohif/i18n": "3.10.0-beta.150", "prop-types": "^15.6.2", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -233,19 +233,19 @@ }, "extensions/cornerstone-dicom-sr": { "name": "@ohif/extension-cornerstone-dicom-sr", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^3.8.5", - "@cornerstonejs/core": "^3.8.5", - "@cornerstonejs/tools": "^3.8.5", + "@cornerstonejs/adapters": "^3.9.1", + "@cornerstonejs/core": "^3.9.1", + "@cornerstonejs/tools": "^3.9.1", "classnames": "^2.3.2", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.147", - "@ohif/extension-cornerstone": "3.10.0-beta.147", - "@ohif/extension-measurement-tracking": "3.10.0-beta.147", - "@ohif/ui": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/extension-cornerstone": "3.10.0-beta.150", + "@ohif/extension-measurement-tracking": "3.10.0-beta.150", + "@ohif/ui": "3.10.0-beta.150", "dcmjs": "*", "dicom-parser": "^1.8.9", "hammerjs": "^2.0.8", @@ -255,19 +255,19 @@ }, "extensions/cornerstone-dynamic-volume": { "name": "@ohif/extension-cornerstone-dynamic-volume", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/core": "^3.8.5", - "@cornerstonejs/tools": "^3.8.5", + "@cornerstonejs/core": "^3.9.1", + "@cornerstonejs/tools": "^3.9.1", "classnames": "^2.3.2", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.147", - "@ohif/extension-cornerstone": "3.10.0-beta.147", - "@ohif/extension-default": "3.10.0-beta.147", - "@ohif/i18n": "3.10.0-beta.147", - "@ohif/ui": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/extension-cornerstone": "3.10.0-beta.150", + "@ohif/extension-default": "3.10.0-beta.150", + "@ohif/i18n": "3.10.0-beta.150", + "@ohif/ui": "3.10.0-beta.150", "dcmjs": "*", "dicom-parser": "^1.8.21", "hammerjs": "^2.0.8", @@ -277,7 +277,7 @@ }, "extensions/default": { "name": "@ohif/extension-default", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/calculate-suv": "^1.1.0", @@ -285,8 +285,8 @@ "lodash.uniqby": "^4.7.0", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.147", - "@ohif/i18n": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/i18n": "3.10.0-beta.150", "dcmjs": "*", "dicomweb-client": "^0.10.4", "prop-types": "^15.6.2", @@ -300,7 +300,7 @@ }, "extensions/dicom-microscopy": { "name": "@ohif/extension-dicom-microscopy", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/codec-charls": "^1.2.3", @@ -311,10 +311,10 @@ "mathjs": "^12.4.2", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.147", - "@ohif/extension-default": "3.10.0-beta.147", - "@ohif/i18n": "3.10.0-beta.147", - "@ohif/ui": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/extension-default": "3.10.0-beta.150", + "@ohif/i18n": "3.10.0-beta.150", + "@ohif/ui": "3.10.0-beta.150", "prop-types": "^15.6.2", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -325,14 +325,14 @@ }, "extensions/dicom-pdf": { "name": "@ohif/extension-dicom-pdf", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.147", - "@ohif/ui": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/ui": "3.10.0-beta.150", "dcmjs": "*", "dicom-parser": "^1.8.9", "hammerjs": "^2.0.8", @@ -342,14 +342,14 @@ }, "extensions/dicom-video": { "name": "@ohif/extension-dicom-video", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.147", - "@ohif/ui": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/ui": "3.10.0-beta.150", "dcmjs": "*", "dicom-parser": "^1.8.9", "hammerjs": "^2.0.8", @@ -359,20 +359,20 @@ }, "extensions/measurement-tracking": { "name": "@ohif/extension-measurement-tracking", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", - "@ohif/ui": "3.10.0-beta.147", + "@ohif/ui": "3.10.0-beta.150", "@xstate/react": "^3.2.2", "xstate": "^4.10.0", }, "peerDependencies": { - "@cornerstonejs/core": "^3.8.5", - "@cornerstonejs/tools": "^3.8.5", - "@ohif/core": "3.10.0-beta.147", - "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.147", - "@ohif/extension-default": "3.10.0-beta.147", - "@ohif/ui": "3.10.0-beta.147", + "@cornerstonejs/core": "^3.9.1", + "@cornerstonejs/tools": "^3.9.1", + "@ohif/core": "3.10.0-beta.150", + "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.150", + "@ohif/extension-default": "3.10.0-beta.150", + "@ohif/ui": "3.10.0-beta.150", "classnames": "^2.3.2", "dcmjs": "*", "lodash.debounce": "^4.0.8", @@ -385,14 +385,14 @@ }, "extensions/test-extension": { "name": "@ohif/extension-test", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.147", - "@ohif/ui": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/ui": "3.10.0-beta.150", "dcmjs": "0.38.0", "dicom-parser": "^1.8.9", "hammerjs": "^2.0.8", @@ -402,7 +402,7 @@ }, "extensions/tmtv": { "name": "@ohif/extension-tmtv", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "classnames": "^2.3.2", @@ -419,7 +419,7 @@ }, "modes/basic-dev-mode": { "name": "@ohif/mode-basic-dev-mode", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -429,17 +429,17 @@ "webpack-merge": "^5.7.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.147", - "@ohif/extension-cornerstone": "3.10.0-beta.147", - "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.147", - "@ohif/extension-default": "3.10.0-beta.147", - "@ohif/extension-dicom-pdf": "3.10.0-beta.147", - "@ohif/extension-dicom-video": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/extension-cornerstone": "3.10.0-beta.150", + "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.150", + "@ohif/extension-default": "3.10.0-beta.150", + "@ohif/extension-dicom-pdf": "3.10.0-beta.150", + "@ohif/extension-dicom-video": "3.10.0-beta.150", }, }, "modes/basic-test-mode": { "name": "@ohif/mode-test", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -449,19 +449,19 @@ "webpack-merge": "^5.7.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.147", - "@ohif/extension-cornerstone": "3.10.0-beta.147", - "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.147", - "@ohif/extension-default": "3.10.0-beta.147", - "@ohif/extension-dicom-pdf": "3.10.0-beta.147", - "@ohif/extension-dicom-video": "3.10.0-beta.147", - "@ohif/extension-measurement-tracking": "3.10.0-beta.147", - "@ohif/extension-test": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/extension-cornerstone": "3.10.0-beta.150", + "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.150", + "@ohif/extension-default": "3.10.0-beta.150", + "@ohif/extension-dicom-pdf": "3.10.0-beta.150", + "@ohif/extension-dicom-video": "3.10.0-beta.150", + "@ohif/extension-measurement-tracking": "3.10.0-beta.150", + "@ohif/extension-test": "3.10.0-beta.150", }, }, "modes/longitudinal": { "name": "@ohif/mode-longitudinal", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -471,32 +471,32 @@ "webpack-merge": "^5.7.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.147", - "@ohif/extension-cornerstone": "3.10.0-beta.147", - "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.147", - "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.147", - "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.147", - "@ohif/extension-default": "3.10.0-beta.147", - "@ohif/extension-dicom-pdf": "3.10.0-beta.147", - "@ohif/extension-dicom-video": "3.10.0-beta.147", - "@ohif/extension-measurement-tracking": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/extension-cornerstone": "3.10.0-beta.150", + "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.150", + "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.150", + "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.150", + "@ohif/extension-default": "3.10.0-beta.150", + "@ohif/extension-dicom-pdf": "3.10.0-beta.150", + "@ohif/extension-dicom-video": "3.10.0-beta.150", + "@ohif/extension-measurement-tracking": "3.10.0-beta.150", }, }, "modes/microscopy": { "name": "@ohif/mode-microscopy", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", }, "peerDependencies": { - "@ohif/core": "3.10.0-beta.147", - "@ohif/extension-dicom-microscopy": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/extension-dicom-microscopy": "3.10.0-beta.150", }, }, "modes/preclinical-4d": { "name": "@ohif/mode-preclinical-4d", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", }, @@ -515,7 +515,7 @@ }, "modes/segmentation": { "name": "@ohif/mode-segmentation", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -559,7 +559,7 @@ }, "modes/tmtv": { "name": "@ohif/mode-tmtv", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "i18next": "^17.0.3", @@ -580,32 +580,32 @@ }, "platform/app": { "name": "@ohif/app", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "@cornerstonejs/codec-charls": "^1.2.3", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjph": "^2.4.5", - "@cornerstonejs/dicom-image-loader": "^3.8.5", + "@cornerstonejs/dicom-image-loader": "^3.9.1", "@emotion/serialize": "^1.1.3", - "@ohif/core": "3.10.0-beta.147", - "@ohif/extension-cornerstone": "3.10.0-beta.147", - "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.147", - "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.147", - "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.147", - "@ohif/extension-default": "3.10.0-beta.147", - "@ohif/extension-dicom-microscopy": "3.10.0-beta.147", - "@ohif/extension-dicom-pdf": "3.10.0-beta.147", - "@ohif/extension-dicom-video": "3.10.0-beta.147", - "@ohif/extension-test": "3.10.0-beta.147", - "@ohif/i18n": "3.10.0-beta.147", - "@ohif/mode-basic-dev-mode": "3.10.0-beta.147", - "@ohif/mode-longitudinal": "3.10.0-beta.147", - "@ohif/mode-microscopy": "3.10.0-beta.147", - "@ohif/mode-test": "3.10.0-beta.147", - "@ohif/ui": "3.10.0-beta.147", - "@ohif/ui-next": "3.10.0-beta.147", + "@ohif/core": "3.10.0-beta.150", + "@ohif/extension-cornerstone": "3.10.0-beta.150", + "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.150", + "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.150", + "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.150", + "@ohif/extension-default": "3.10.0-beta.150", + "@ohif/extension-dicom-microscopy": "3.10.0-beta.150", + "@ohif/extension-dicom-pdf": "3.10.0-beta.150", + "@ohif/extension-dicom-video": "3.10.0-beta.150", + "@ohif/extension-test": "3.10.0-beta.150", + "@ohif/i18n": "3.10.0-beta.150", + "@ohif/mode-basic-dev-mode": "3.10.0-beta.150", + "@ohif/mode-longitudinal": "3.10.0-beta.150", + "@ohif/mode-microscopy": "3.10.0-beta.150", + "@ohif/mode-test": "3.10.0-beta.150", + "@ohif/ui": "3.10.0-beta.150", + "@ohif/ui-next": "3.10.0-beta.150", "@svgr/webpack": "^8.1.0", "@types/react": "^18.3.3", "classnames": "^2.3.2", @@ -646,13 +646,13 @@ }, "platform/cli": { "name": "@ohif/cli", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "bin": { "ohif-cli": "src/index.js", }, "dependencies": { "@babel/core": "7.24.7", - "axios": "^1.8.2", + "axios": "^1.8.4", "chalk": "^5.0.0", "execa": "^8.0.1", "gitignore": "^0.7.0", @@ -670,7 +670,7 @@ }, "platform/core": { "name": "@ohif/core", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "dcmjs": "*", @@ -680,7 +680,7 @@ "isomorphic-base64": "^1.0.2", "lodash.clonedeep": "^4.5.0", "lodash.isequal": "^4.5.0", - "moment": "*", + "moment": "^2.30.1", "object-hash": "2.1.1", "query-string": "^6.14.0", "react-shepherd": "6.1.1", @@ -695,15 +695,15 @@ "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjph": "^2.4.5", - "@cornerstonejs/dicom-image-loader": "^3.8.5", - "@ohif/ui": "3.10.0-beta.147", + "@cornerstonejs/dicom-image-loader": "^3.9.1", + "@ohif/ui": "3.10.0-beta.150", "cornerstone-math": "0.1.9", "dicom-parser": "^1.8.21", }, }, "platform/i18n": { "name": "@ohif/i18n", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@babel/runtime": "^7.20.13", "i18next-locize-backend": "^2.0.0", @@ -728,7 +728,7 @@ }, "platform/ui": { "name": "@ohif/ui", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@testing-library/react": "^13.1.0", "browser-detect": "^0.2.28", @@ -743,7 +743,7 @@ "lodash.clonedeep": "^4.5.0", "lodash.debounce": "^4.0.8", "lodash.merge": "^4.6.1", - "moment": "*", + "moment": "^2.30.1", "mousetrap": "^1.6.5", "react": "^18.3.1", "react-dates": "^21.8.0", @@ -788,7 +788,7 @@ }, "platform/ui-next": { "name": "@ohif/ui-next", - "version": "3.10.0-beta.147", + "version": "3.10.0-beta.150", "dependencies": { "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-checkbox": "^1.1.1", @@ -1099,9 +1099,9 @@ "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], - "@cornerstonejs/adapters": ["@cornerstonejs/adapters@3.8.5", "", { "dependencies": { "@babel/runtime-corejs2": "^7.17.8", "buffer": "^6.0.3", "dcmjs": "^0.29.8", "gl-matrix": "^3.4.3", "ndarray": "^1.0.19" }, "peerDependencies": { "@cornerstonejs/core": "^3.8.5", "@cornerstonejs/tools": "^3.8.5" } }, "sha512-dQlKKSCbV6V3QpivDdZZiI7N792l1VqsOj8H+e8iiarpy6MvwiEvck2u50/GBhto9D/U9QvRkZVs9TH0ewUs5w=="], + "@cornerstonejs/adapters": ["@cornerstonejs/adapters@3.9.1", "", { "dependencies": { "@babel/runtime-corejs2": "^7.17.8", "buffer": "^6.0.3", "dcmjs": "^0.29.8", "gl-matrix": "^3.4.3", "ndarray": "^1.0.19" }, "peerDependencies": { "@cornerstonejs/core": "^3.9.1", "@cornerstonejs/tools": "^3.9.1" } }, "sha512-Wkbh3+oj+9TQOnwYACj8w8IqEaCFdIVL2F3TaQKvsPC7/sP/WLKDiRVtAV951NI1/AJiiWd2UFze0kKU8DrsvQ=="], - "@cornerstonejs/ai": ["@cornerstonejs/ai@3.8.5", "", { "dependencies": { "@babel/runtime-corejs2": "^7.17.8", "buffer": "^6.0.3", "dcmjs": "^0.29.8", "gl-matrix": "^3.4.3", "lodash.clonedeep": "^4.5.0", "ndarray": "^1.0.19", "onnxruntime-common": "1.17.1", "onnxruntime-web": "1.17.1" }, "peerDependencies": { "@cornerstonejs/core": "^3.8.5", "@cornerstonejs/tools": "^3.8.5" } }, "sha512-9QR7PmTtkeXZOjDFh9WulLJGnraWLaM/g/qNB0ZaPKDMo1PLT7/tHn1F6wsyT2cmpEb3/G5towdxtEvhvlpm/w=="], + "@cornerstonejs/ai": ["@cornerstonejs/ai@3.9.1", "", { "dependencies": { "@babel/runtime-corejs2": "^7.17.8", "buffer": "^6.0.3", "dcmjs": "^0.29.8", "gl-matrix": "^3.4.3", "lodash.clonedeep": "^4.5.0", "ndarray": "^1.0.19", "onnxruntime-common": "1.17.1", "onnxruntime-web": "1.17.1" }, "peerDependencies": { "@cornerstonejs/core": "^3.9.1", "@cornerstonejs/tools": "^3.9.1" } }, "sha512-wa//BGNEaiTbZXBFZWoNSzBrWW6FgF3cmD+So+V40k7m0AZGuhJwIDamtV1nsS3iUwEvBDWghzpgAD7OqMNLhA=="], "@cornerstonejs/calculate-suv": ["@cornerstonejs/calculate-suv@1.1.0", "", {}, "sha512-Q9XraiDJif9aMFArD2iEuDO/HXbcRVCqB7KfaHgDrdTTjgDFovS91Psbdim7crypRSvE6dh/+HKeFNHdvNkA6w=="], @@ -1113,15 +1113,15 @@ "@cornerstonejs/codec-openjph": ["@cornerstonejs/codec-openjph@2.4.7", "", {}, "sha512-qvP4q4JDib7mi9r7LqKOwqz7YZ8gjtDX4ZCezeYf8+eb7MBXCz5uXAMeVF3yz9Axw4XiIMdB/pqXkm8tqCl13w=="], - "@cornerstonejs/core": ["@cornerstonejs/core@3.8.5", "", { "dependencies": { "@kitware/vtk.js": "32.12.1", "comlink": "^4.4.1", "gl-matrix": "^3.4.3", "loglevel": "^1.9.2" } }, "sha512-x3LZwZUqhVldChpwtLqNwUWx8eXq9q1ndwrx5lVpnX4ZUT9qQIAro01Ih8DPiXlLb1NXbN3sG4e/x/TxuQ+5bw=="], + "@cornerstonejs/core": ["@cornerstonejs/core@3.9.1", "", { "dependencies": { "@kitware/vtk.js": "32.12.1", "comlink": "^4.4.1", "gl-matrix": "^3.4.3", "loglevel": "^1.9.2" } }, "sha512-1R6plBRfKX3hYzeIisXmYquqpRLCnF51abl49vfKVu48TEB+cD8zvQO0xCQWC6QfcuxmFfw9BQmtIXLvDoo38A=="], - "@cornerstonejs/dicom-image-loader": ["@cornerstonejs/dicom-image-loader@3.8.5", "", { "dependencies": { "@cornerstonejs/codec-charls": "^1.2.3", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.2", "@cornerstonejs/codec-openjph": "^2.4.5", "comlink": "^4.4.1", "dicom-parser": "^1.8.9", "jpeg-lossless-decoder-js": "^2.1.0", "pako": "^2.0.4", "uuid": "^9.0.0" }, "peerDependencies": { "@cornerstonejs/core": "^3.8.5" } }, "sha512-yuLLU2sbtFWueNKVbeYBddPoJnfhrUQ+rRnXJb+y9iczwZMQLy4tYyk3Q5INo+/nIdwCVeZg7P9qORZERsBivw=="], + "@cornerstonejs/dicom-image-loader": ["@cornerstonejs/dicom-image-loader@3.9.1", "", { "dependencies": { "@cornerstonejs/codec-charls": "^1.2.3", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.2", "@cornerstonejs/codec-openjph": "^2.4.5", "comlink": "^4.4.1", "dicom-parser": "^1.8.9", "jpeg-lossless-decoder-js": "^2.1.0", "pako": "^2.0.4", "uuid": "^9.0.0" }, "peerDependencies": { "@cornerstonejs/core": "^3.9.1" } }, "sha512-FHhFJTzrF2+CIfjDiHYWRqquInuxCYP8F16gTBDWT9FxNEMNjHqkTo7qVYhB/mG2nIV+sKcTMs4OSx3hBDqikQ=="], - "@cornerstonejs/labelmap-interpolation": ["@cornerstonejs/labelmap-interpolation@3.8.5", "", { "dependencies": { "@itk-wasm/morphological-contour-interpolation": "1.1.0", "itk-wasm": "1.0.0-b.165" }, "peerDependencies": { "@cornerstonejs/core": "^3.8.5", "@cornerstonejs/tools": "^3.8.5", "@kitware/vtk.js": "32.12.1" } }, "sha512-u80OTJE8eju+tZ+S/N1b/HTIw2mPjEE2o5u3T/7/w90FX7OaxJJiMYjPPfnSZWXjE2HhRu0gEAKHOU3dr8pL4w=="], + "@cornerstonejs/labelmap-interpolation": ["@cornerstonejs/labelmap-interpolation@3.9.1", "", { "dependencies": { "@itk-wasm/morphological-contour-interpolation": "1.1.0", "itk-wasm": "1.0.0-b.165" }, "peerDependencies": { "@cornerstonejs/core": "^3.9.1", "@cornerstonejs/tools": "^3.9.1", "@kitware/vtk.js": "32.12.1" } }, "sha512-todwKvOCxnQsc5X9KNjAOjC74bop8UYgA/Mnhl+fCagGaVxS5t+GlnV2PG29Yw9Klw+S4vJkd0XiMCgO2BevLw=="], - "@cornerstonejs/polymorphic-segmentation": ["@cornerstonejs/polymorphic-segmentation@3.8.5", "", { "dependencies": { "@icr/polyseg-wasm": "0.4.0" }, "peerDependencies": { "@cornerstonejs/core": "^3.8.5", "@cornerstonejs/tools": "^3.8.5", "@kitware/vtk.js": "32.12.1" } }, "sha512-6L9a9f36CnUIuGsydA8kkkC0z1Gjid4KfclCQoYYaxcsLWLDpba5usFERmxCLIm9VyBsA3POqesIGDqWTgJmFg=="], + "@cornerstonejs/polymorphic-segmentation": ["@cornerstonejs/polymorphic-segmentation@3.9.1", "", { "dependencies": { "@icr/polyseg-wasm": "0.4.0" }, "peerDependencies": { "@cornerstonejs/core": "^3.9.1", "@cornerstonejs/tools": "^3.9.1", "@kitware/vtk.js": "32.12.1" } }, "sha512-QAJYYBtXNpHSKFiN4kVuCOlQB2Cnl6UrnTgAgBKw1sE00wrmbjyF/z1x1qBR34IkAe1ggMbF1QmhQpR90s1M6A=="], - "@cornerstonejs/tools": ["@cornerstonejs/tools@3.8.5", "", { "dependencies": { "@types/offscreencanvas": "2019.7.3", "comlink": "^4.4.1", "lodash.get": "^4.4.2" }, "peerDependencies": { "@cornerstonejs/core": "^3.8.5", "@kitware/vtk.js": "32.12.1", "@types/d3-array": "^3.0.4", "@types/d3-interpolate": "^3.0.1", "d3-array": "^3.2.3", "d3-interpolate": "^3.0.1", "gl-matrix": "^3.4.3" } }, "sha512-aTaziRHJakCCxvbHhbrSkEuiamURGakcK83KXGJPjSdStWC/2cVpkCzPxc8V7FZBIstsvo5pgciXSpNc6Yt7Og=="], + "@cornerstonejs/tools": ["@cornerstonejs/tools@3.9.1", "", { "dependencies": { "@types/offscreencanvas": "2019.7.3", "comlink": "^4.4.1", "lodash.get": "^4.4.2" }, "peerDependencies": { "@cornerstonejs/core": "^3.9.1", "@kitware/vtk.js": "32.12.1", "@types/d3-array": "^3.0.4", "@types/d3-interpolate": "^3.0.1", "d3-array": "^3.2.3", "d3-interpolate": "^3.0.1", "gl-matrix": "^3.4.3" } }, "sha512-OP3oZ+Af3ax3Kdo7DLaRs74XlRHTpBuePZvUuYb21VsWBVr50E9nRV5zyCo/4klRb+/zEKlWGQbQogmQxv9+NA=="], "@csstools/postcss-cascade-layers": ["@csstools/postcss-cascade-layers@1.1.1", "", { "dependencies": { "@csstools/selector-specificity": "^2.0.2", "postcss-selector-parser": "^6.0.10" }, "peerDependencies": { "postcss": "^8.2" } }, "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA=="], diff --git a/extensions/cornerstone-dicom-pmap/package.json b/extensions/cornerstone-dicom-pmap/package.json index fa85bec4b..60a170d8b 100644 --- a/extensions/cornerstone-dicom-pmap/package.json +++ b/extensions/cornerstone-dicom-pmap/package.json @@ -46,8 +46,8 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^3.8.5", - "@cornerstonejs/core": "^3.8.5", + "@cornerstonejs/adapters": "^3.9.1", + "@cornerstonejs/core": "^3.9.1", "@kitware/vtk.js": "32.12.0", "react-color": "^2.19.3" } diff --git a/extensions/cornerstone-dicom-seg/package.json b/extensions/cornerstone-dicom-seg/package.json index d3add046c..bb20cc212 100644 --- a/extensions/cornerstone-dicom-seg/package.json +++ b/extensions/cornerstone-dicom-seg/package.json @@ -46,8 +46,8 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^3.8.5", - "@cornerstonejs/core": "^3.8.5", + "@cornerstonejs/adapters": "^3.9.1", + "@cornerstonejs/core": "^3.9.1", "@kitware/vtk.js": "32.12.0", "react-color": "^2.19.3" } diff --git a/extensions/cornerstone-dicom-sr/package.json b/extensions/cornerstone-dicom-sr/package.json index c990f4bcb..3d757ebce 100644 --- a/extensions/cornerstone-dicom-sr/package.json +++ b/extensions/cornerstone-dicom-sr/package.json @@ -46,9 +46,9 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^3.8.5", - "@cornerstonejs/core": "^3.8.5", - "@cornerstonejs/tools": "^3.8.5", + "@cornerstonejs/adapters": "^3.9.1", + "@cornerstonejs/core": "^3.9.1", + "@cornerstonejs/tools": "^3.9.1", "classnames": "^2.3.2" } } diff --git a/extensions/cornerstone-dynamic-volume/package.json b/extensions/cornerstone-dynamic-volume/package.json index 23557a825..b671b76ed 100644 --- a/extensions/cornerstone-dynamic-volume/package.json +++ b/extensions/cornerstone-dynamic-volume/package.json @@ -42,8 +42,8 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/core": "^3.8.5", - "@cornerstonejs/tools": "^3.8.5", + "@cornerstonejs/core": "^3.9.1", + "@cornerstonejs/tools": "^3.9.1", "classnames": "^2.3.2" } } diff --git a/extensions/cornerstone/package.json b/extensions/cornerstone/package.json index ff277b8d9..c4d91d88e 100644 --- a/extensions/cornerstone/package.json +++ b/extensions/cornerstone/package.json @@ -38,7 +38,7 @@ "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjph": "^2.4.5", - "@cornerstonejs/dicom-image-loader": "^3.8.5", + "@cornerstonejs/dicom-image-loader": "^3.9.1", "@ohif/core": "3.10.0-beta.151", "@ohif/ui": "3.10.0-beta.151", "dcmjs": "*", @@ -51,12 +51,12 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^3.8.5", - "@cornerstonejs/ai": "^3.8.5", - "@cornerstonejs/core": "^3.8.5", - "@cornerstonejs/labelmap-interpolation": "^3.8.5", - "@cornerstonejs/polymorphic-segmentation": "^3.8.5", - "@cornerstonejs/tools": "^3.8.5", + "@cornerstonejs/adapters": "^3.9.1", + "@cornerstonejs/ai": "^3.9.1", + "@cornerstonejs/core": "^3.9.1", + "@cornerstonejs/labelmap-interpolation": "^3.9.1", + "@cornerstonejs/polymorphic-segmentation": "^3.9.1", + "@cornerstonejs/tools": "^3.9.1", "@itk-wasm/morphological-contour-interpolation": "1.1.0", "@kitware/vtk.js": "32.12.0", "html2canvas": "^1.4.1", diff --git a/extensions/cornerstone/src/customizations/segmentationPanelCustomization.tsx b/extensions/cornerstone/src/customizations/segmentationPanelCustomization.tsx index ae9ec4bab..3b182d7fb 100644 --- a/extensions/cornerstone/src/customizations/segmentationPanelCustomization.tsx +++ b/extensions/cornerstone/src/customizations/segmentationPanelCustomization.tsx @@ -31,6 +31,7 @@ export default function getSegmentationPanelCustomization({ commandsManager, ser peakLPS: 'Peak Coord', volume: 'Volume', lesionGlycolysis: 'Lesion Glycolysis', + center: 'Center', }, 'segmentationToolbox.config': () => { // Get initial states based on current configuration diff --git a/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts b/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts index bb0d9cad1..e19f0ecc8 100644 --- a/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts +++ b/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts @@ -277,6 +277,11 @@ class SegmentationService extends PubSubService { ): Promise { const segmentation = this.getSegmentation(segmentationId); const csViewport = this.getAndValidateViewport(viewportId); + + if (!csViewport) { + return; + } + const colorLUTIndex = this._segmentationIdToColorLUTIndexMap.get(segmentationId); const defaultRepresentationType = csToolsEnums.SegmentationRepresentations.Labelmap; @@ -1251,7 +1256,8 @@ class SegmentationService extends PubSubService { const csViewport = this.servicesManager.services.cornerstoneViewportService.getCornerstoneViewport(viewportId); if (!csViewport) { - throw new Error(`Viewport with id ${viewportId} not found.`); + console.warn(`Viewport with id ${viewportId} not found.`); + return null; } return csViewport; } @@ -1766,6 +1772,12 @@ class SegmentationService extends PubSubService { const { center } = cachedStats; + if (!center) { + return { + world: cachedStats.namedStats.center.value, + }; + } + return center; } diff --git a/extensions/default/src/Panels/StudyBrowser/PanelStudyBrowser.tsx b/extensions/default/src/Panels/StudyBrowser/PanelStudyBrowser.tsx index c8add4e50..59a04d477 100644 --- a/extensions/default/src/Panels/StudyBrowser/PanelStudyBrowser.tsx +++ b/extensions/default/src/Panels/StudyBrowser/PanelStudyBrowser.tsx @@ -1,10 +1,8 @@ import React, { useState, useEffect, useCallback } from 'react'; import { useImageViewer } from '@ohif/ui'; -import { useViewportGrid } from '@ohif/ui-next'; -import { StudyBrowser } from '@ohif/ui-next'; import { useSystem, utils } from '@ohif/core'; import { useNavigate } from 'react-router-dom'; -import { Separator } from '@ohif/ui-next'; +import { useViewportGrid, StudyBrowser, Separator } from '@ohif/ui-next'; import { PanelStudyBrowserHeader } from './PanelStudyBrowserHeader'; import { defaultActionIcons } from './constants'; import MoreDropdownMenu from '../../Components/MoreDropdownMenu'; diff --git a/extensions/default/src/ViewerLayout/constants/panels.ts b/extensions/default/src/ViewerLayout/constants/panels.ts index 3219e6c51..2c6684032 100644 --- a/extensions/default/src/ViewerLayout/constants/panels.ts +++ b/extensions/default/src/ViewerLayout/constants/panels.ts @@ -4,7 +4,7 @@ const collapsedOutsideBorderSize = 4; const collapsedWidth = 25; const rightPanelInitialExpandedWidth = 280; -const leftPanelInitialExpandedWidth = 282; +const leftPanelInitialExpandedWidth = 292; const panelGroupDefinition = { groupId: 'viewerLayoutResizablePanelGroup', diff --git a/extensions/measurement-tracking/package.json b/extensions/measurement-tracking/package.json index ef0d88039..b8b0eb103 100644 --- a/extensions/measurement-tracking/package.json +++ b/extensions/measurement-tracking/package.json @@ -32,8 +32,8 @@ "start": "yarn run dev" }, "peerDependencies": { - "@cornerstonejs/core": "^3.8.5", - "@cornerstonejs/tools": "^3.8.5", + "@cornerstonejs/core": "^3.9.1", + "@cornerstonejs/tools": "^3.9.1", "@ohif/core": "3.10.0-beta.151", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.151", "@ohif/extension-default": "3.10.0-beta.151", diff --git a/extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/PanelROIThresholdExport.tsx b/extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/PanelROIThresholdExport.tsx index 09878600d..1a3b95098 100644 --- a/extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/PanelROIThresholdExport.tsx +++ b/extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/PanelROIThresholdExport.tsx @@ -3,6 +3,7 @@ import { useActiveViewportSegmentationRepresentations } from '@ohif/extension-co import { handleROIThresholding } from '../../utils/handleROIThresholding'; import { debounce } from '@ohif/core/src/utils'; import { useSystem } from '@ohif/core/src'; +import { Button } from '@ohif/ui-next'; export default function PanelRoiThresholdSegmentation() { const { commandsManager, servicesManager } = useSystem(); @@ -11,6 +12,7 @@ export default function PanelRoiThresholdSegmentation() { useActiveViewportSegmentationRepresentations({ servicesManager }); const segmentationIds = segmentationsInfo?.map(info => info.segmentation.segmentationId) || []; + const segmentations = segmentationsInfo?.map(info => info.segmentation) || []; useEffect(() => { const initialRun = async () => { @@ -54,17 +56,37 @@ export default function PanelRoiThresholdSegmentation() { const stats = segmentationService.getSegmentationGroupStats(segmentationIds); const tmtvValue = stats?.tmtv; + const handleExportCSV = () => { + if (!segmentations.length) { + return; + } + + commandsManager.runCommand('exportTMTVReportCSV', { + segmentations, + tmtv: tmtvValue, + config: {}, + }); + }; + return ( -
+
- {tmtvValue !== null && tmtvValue !== undefined ? ( -
- - {'TMTV:'} - -
{`${tmtvValue?.toFixed(3)} mL`}
+
+
+ {'TMTV: '} + {tmtvValue ? `${tmtvValue.toFixed(3)} mL` : ''}
- ) : null} +
+ +
+
); diff --git a/platform/app/package.json b/platform/app/package.json index 7dc08ec13..b85e70dfc 100644 --- a/platform/app/package.json +++ b/platform/app/package.json @@ -54,7 +54,7 @@ "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjph": "^2.4.5", - "@cornerstonejs/dicom-image-loader": "^3.8.5", + "@cornerstonejs/dicom-image-loader": "^3.9.1", "@emotion/serialize": "^1.1.3", "@ohif/core": "3.10.0-beta.151", "@ohif/extension-cornerstone": "3.10.0-beta.151", diff --git a/platform/cli/package.json b/platform/cli/package.json index 16007f4dd..d5502cdb4 100644 --- a/platform/cli/package.json +++ b/platform/cli/package.json @@ -21,7 +21,7 @@ "license": "MIT", "dependencies": { "@babel/core": "7.24.7", - "axios": "^1.8.2", + "axios": "^1.8.4", "chalk": "^5.0.0", "execa": "^8.0.1", "gitignore": "^0.7.0", diff --git a/platform/core/package.json b/platform/core/package.json index a901b503c..ef981f9ba 100644 --- a/platform/core/package.json +++ b/platform/core/package.json @@ -37,7 +37,7 @@ "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjph": "^2.4.5", - "@cornerstonejs/dicom-image-loader": "^3.8.5", + "@cornerstonejs/dicom-image-loader": "^3.9.1", "@ohif/ui": "3.10.0-beta.151", "cornerstone-math": "0.1.9", "dicom-parser": "^1.8.21" @@ -51,7 +51,7 @@ "isomorphic-base64": "^1.0.2", "lodash.clonedeep": "^4.5.0", "lodash.isequal": "^4.5.0", - "moment": "*", + "moment": "^2.30.1", "object-hash": "2.1.1", "query-string": "^6.14.0", "react-shepherd": "6.1.1", diff --git a/platform/ui-next/src/components/SegmentationTable/SegmentationExpanded.tsx b/platform/ui-next/src/components/SegmentationTable/SegmentationExpanded.tsx index d57abda78..81df8f778 100644 --- a/platform/ui-next/src/components/SegmentationTable/SegmentationExpanded.tsx +++ b/platform/ui-next/src/components/SegmentationTable/SegmentationExpanded.tsx @@ -9,6 +9,8 @@ import { Button } from '../Button'; import { Icons } from '../Icons/Icons'; import { DropdownMenu, DropdownMenuTrigger } from '../DropdownMenu'; import { Tooltip, TooltipTrigger, TooltipContent } from '../Tooltip/Tooltip'; +import { ScrollArea } from '../../components'; +import { useDynamicMaxHeight } from '../../hooks/useDynamicMaxHeight'; // The Header container component const SegmentationExpandedHeader = ({ children }: { children: React.ReactNode }) => { @@ -94,33 +96,44 @@ const SegmentationExpandedRoot = ({ children }) => { const { data, activeSegmentationId, onSegmentationClick, mode } = useSegmentationTableContext('SegmentationExpanded'); + const { ref: scrollableContainerRef, maxHeight } = useDynamicMaxHeight(data); + // Check if we should render based on mode if (mode !== 'expanded' || !data || data.length === 0) { return null; } return ( -
- {data.map(segmentationInfo => { - const isActive = segmentationInfo.segmentation.segmentationId === activeSegmentationId; + +
+ {data.map(segmentationInfo => { + const isActive = segmentationInfo.segmentation.segmentationId === activeSegmentationId; - return ( - - - {children} - - - ); - })} -
+ + {children} + + + ); + })} +
+ ); }; diff --git a/platform/ui-next/src/components/SegmentationTable/SegmentationSegments.tsx b/platform/ui-next/src/components/SegmentationTable/SegmentationSegments.tsx index 6e0069f7c..48b99efdf 100644 --- a/platform/ui-next/src/components/SegmentationTable/SegmentationSegments.tsx +++ b/platform/ui-next/src/components/SegmentationTable/SegmentationSegments.tsx @@ -3,6 +3,7 @@ import { ScrollArea, DataRow } from '../../components'; import { HoverCard, HoverCardTrigger, HoverCardContent } from '../../components/HoverCard'; import { useSegmentationTableContext, useSegmentationExpanded } from './contexts'; import { SegmentStatistics } from './SegmentStatistics'; +import { useDynamicMaxHeight } from '../../hooks/useDynamicMaxHeight'; export const SegmentationSegments = ({ children = null }: { children?: React.ReactNode }) => { const { @@ -35,101 +36,108 @@ export const SegmentationSegments = ({ children = null }: { children?: React.Rea representation = segmentationInfo?.representation; } + const segments = Object.values(representation.segments); + const isActiveSegmentation = segmentation.segmentationId === activeSegmentationId; + + const { ref: scrollableContainerRef, maxHeight } = useDynamicMaxHeight(segments); + if (!representation || !segmentation) { return null; } - const segments = Object.values(representation.segments); - const isActiveSegmentation = segmentation.segmentationId === activeSegmentationId; - return ( - {segments.map(segment => { - if (!segment) { - return null; - } - const { segmentIndex, color, visible } = segment as { - segmentIndex: number; - color: number[]; - visible: boolean; - }; - const segmentFromSegmentation = segmentation.segments[segmentIndex]; +
+ {segments.map(segment => { + if (!segment) { + return null; + } + const { segmentIndex, color, visible } = segment as { + segmentIndex: number; + color: number[]; + visible: boolean; + }; + const segmentFromSegmentation = segmentation.segments[segmentIndex]; - if (!segmentFromSegmentation) { - return null; - } + if (!segmentFromSegmentation) { + return null; + } - const { locked, active, label, displayText } = segmentFromSegmentation; - const cssColor = `rgb(${color[0]},${color[1]},${color[2]})`; + const { locked, active, label, displayText } = segmentFromSegmentation; + const cssColor = `rgb(${color[0]},${color[1]},${color[2]})`; - const hasStats = segmentFromSegmentation.cachedStats?.namedStats; - const DataRowComponent = ( - onSegmentColorClick(segmentation.segmentationId, segmentIndex)} - onToggleVisibility={() => - onToggleSegmentVisibility( - segmentation.segmentationId, - segmentIndex, - representation.type - ) - } - onToggleLocked={() => onToggleSegmentLock(segmentation.segmentationId, segmentIndex)} - onSelect={() => onSegmentClick(segmentation.segmentationId, segmentIndex)} - onRename={() => onSegmentEdit(segmentation.segmentationId, segmentIndex)} - onDelete={() => onSegmentDelete(segmentation.segmentationId, segmentIndex)} - /> - ); - - return hasStats ? ( - - -
{DataRowComponent}
-
- -
-
-

{label}

-
- - onSegmentColorClick(segmentation.segmentationId, segmentIndex)} + onToggleVisibility={() => + onToggleSegmentVisibility( + segmentation.segmentationId, segmentIndex, - }} - segmentationId={segmentation.segmentationId} + representation.type + ) + } + onToggleLocked={() => onToggleSegmentLock(segmentation.segmentationId, segmentIndex)} + onSelect={() => onSegmentClick(segmentation.segmentationId, segmentIndex)} + onRename={() => onSegmentEdit(segmentation.segmentationId, segmentIndex)} + onDelete={() => onSegmentDelete(segmentation.segmentationId, segmentIndex)} + /> + ); + + return hasStats ? ( + + +
{DataRowComponent}
+
+ - {children} -
-
-
- ) : ( - DataRowComponent - ); - })} +
+
+

{label}

+
+ + + {children} + + + + ) : ( + DataRowComponent + ); + })} +
); }; diff --git a/platform/ui-next/src/components/ThumbnailList/ThumbnailList.tsx b/platform/ui-next/src/components/ThumbnailList/ThumbnailList.tsx index b1a088bac..660af511d 100644 --- a/platform/ui-next/src/components/ThumbnailList/ThumbnailList.tsx +++ b/platform/ui-next/src/components/ThumbnailList/ThumbnailList.tsx @@ -2,6 +2,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Thumbnail } from '../Thumbnail'; +import { useDynamicMaxHeight } from '../../hooks/useDynamicMaxHeight'; +import { ScrollArea } from '../ScrollArea'; const ThumbnailList = ({ thumbnails, @@ -12,6 +14,9 @@ const ThumbnailList = ({ viewPreset, ThumbnailMenuItems, }) => { + // Use the dynamic height hook on the parent container + const { ref, maxHeight } = useDynamicMaxHeight(thumbnails); + // Filter thumbnails into list items and thumbnail items const listItems = thumbnails?.filter( ({ componentType }) => componentType === 'thumbnailNoImage' || viewPreset === 'list' @@ -22,63 +27,68 @@ const ThumbnailList = ({ ); return ( -
- {/* Thumbnail Items */} - {thumbnailItems.length > 0 && ( -
- {thumbnailItems.map(item => { - const { displaySetInstanceUID, componentType, numInstances, ...rest } = item; + +
+ {thumbnailItems.length > 0 && ( +
+ {thumbnailItems.map(item => { + const { displaySetInstanceUID, componentType, numInstances, ...rest } = item; - const isActive = activeDisplaySetInstanceUIDs.includes(displaySetInstanceUID); - return ( - - ); - })} -
- )} - {/* List Items */} - {listItems.length > 0 && ( -
- {listItems.map(item => { - const { displaySetInstanceUID, componentType, numInstances, ...rest } = item; - const isActive = activeDisplaySetInstanceUIDs.includes(displaySetInstanceUID); - return ( - - ); - })} -
- )} -
+ const isActive = activeDisplaySetInstanceUIDs.includes(displaySetInstanceUID); + return ( + + ); + })} +
+ )} + {/* List Items */} + {listItems.length > 0 && ( +
+ {listItems.map(item => { + const { displaySetInstanceUID, componentType, numInstances, ...rest } = item; + const isActive = activeDisplaySetInstanceUIDs.includes(displaySetInstanceUID); + return ( + + ); + })} +
+ )} +
+ ); }; diff --git a/platform/ui-next/src/hooks/useDynamicMaxHeight.ts b/platform/ui-next/src/hooks/useDynamicMaxHeight.ts new file mode 100644 index 000000000..fb403742c --- /dev/null +++ b/platform/ui-next/src/hooks/useDynamicMaxHeight.ts @@ -0,0 +1,50 @@ +import { useRef, useState, useEffect, RefObject } from 'react'; + +/** + * Calculates the maximum height for an element based on its position + * relative to the bottom of the viewport. + * + * @param data The data that, when changed, should trigger a recalculation. + * @param buffer Optional buffer space (in pixels) to leave below the element. Defaults to 20. + * @param minHeight Optional minimum height (in pixels) for the element. Defaults to 100. + * @returns An object containing: + * - `ref`: A RefObject to attach to the target DOM element. + * - `maxHeight`: The calculated maximum height string (e.g., "500px"). + */ +export function useDynamicMaxHeight( + data: any, + buffer = 20, + minHeight = 100 +): { + ref: RefObject; + maxHeight: string; +} { + const ref = useRef(null); + const [maxHeight, setMaxHeight] = useState('100vh'); // Start with full viewport height initially + + useEffect(() => { + const calculateMaxHeight = () => { + if (ref.current) { + const rect = ref.current.getBoundingClientRect(); + const availableHeight = window.innerHeight - rect.top - buffer; + setMaxHeight(`${Math.max(minHeight, availableHeight)}px`); + } + }; + + // Calculate initially + // Use requestAnimationFrame to ensure layout is stable after initial render + const rafId = requestAnimationFrame(calculateMaxHeight); + + // Recalculate on window resize + window.addEventListener('resize', calculateMaxHeight); + + // Cleanup listener and requestAnimationFrame on component unmount + return () => { + window.removeEventListener('resize', calculateMaxHeight); + cancelAnimationFrame(rafId); + }; + // Dependencies: buffer, minHeight, and data. + }, [data, buffer, minHeight]); + + return { ref, maxHeight }; +} diff --git a/platform/ui/package.json b/platform/ui/package.json index d3441b697..18c94c853 100644 --- a/platform/ui/package.json +++ b/platform/ui/package.json @@ -46,7 +46,7 @@ "lodash.clonedeep": "^4.5.0", "lodash.debounce": "^4.0.8", "lodash.merge": "^4.6.1", - "moment": "*", + "moment": "^2.30.1", "mousetrap": "^1.6.5", "react": "^18.3.1", "react-dates": "^21.8.0", diff --git a/yarn.lock b/yarn.lock index 486c21f5a..d6b285315 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1393,10 +1393,10 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== -"@cornerstonejs/adapters@^3.8.5": - version "3.8.5" - resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-3.8.5.tgz#d516a8fba29d200b47d77fe0ef586ed8962506de" - integrity sha512-dQlKKSCbV6V3QpivDdZZiI7N792l1VqsOj8H+e8iiarpy6MvwiEvck2u50/GBhto9D/U9QvRkZVs9TH0ewUs5w== +"@cornerstonejs/adapters@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-3.9.1.tgz#94c2806c9bc55d3f6d25c4f8e888f766c396d6bc" + integrity sha512-Wkbh3+oj+9TQOnwYACj8w8IqEaCFdIVL2F3TaQKvsPC7/sP/WLKDiRVtAV951NI1/AJiiWd2UFze0kKU8DrsvQ== dependencies: "@babel/runtime-corejs2" "^7.17.8" buffer "^6.0.3" @@ -1404,10 +1404,10 @@ gl-matrix "^3.4.3" ndarray "^1.0.19" -"@cornerstonejs/ai@^3.8.5": - version "3.8.5" - resolved "https://registry.yarnpkg.com/@cornerstonejs/ai/-/ai-3.8.5.tgz#8f6be57b7bc660afacd52b34ce56a71c696419ed" - integrity sha512-9QR7PmTtkeXZOjDFh9WulLJGnraWLaM/g/qNB0ZaPKDMo1PLT7/tHn1F6wsyT2cmpEb3/G5towdxtEvhvlpm/w== +"@cornerstonejs/ai@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@cornerstonejs/ai/-/ai-3.9.1.tgz#94a69937b0c46e0c4156ddab022b408f4452b5a2" + integrity sha512-wa//BGNEaiTbZXBFZWoNSzBrWW6FgF3cmD+So+V40k7m0AZGuhJwIDamtV1nsS3iUwEvBDWghzpgAD7OqMNLhA== dependencies: "@babel/runtime-corejs2" "^7.17.8" buffer "^6.0.3" @@ -1443,20 +1443,20 @@ resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.5.tgz#8690b61a86fa53ef38a70eee9d665a79229517c0" integrity sha512-MZCUy8VG0VG5Nl1l58+g+kH3LujAzLYTfJqkwpWI2gjSrGXnP6lgwyy4GmPRZWVoS40/B1LDNALK905cNWm+sg== -"@cornerstonejs/core@^3.8.5": - version "3.8.5" - resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-3.8.5.tgz#577bd32f0a3da36f895bf89c821b02a4cf97e225" - integrity sha512-x3LZwZUqhVldChpwtLqNwUWx8eXq9q1ndwrx5lVpnX4ZUT9qQIAro01Ih8DPiXlLb1NXbN3sG4e/x/TxuQ+5bw== +"@cornerstonejs/core@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-3.9.1.tgz#88619a436013a34bd04c6e5304d89aeec1c51804" + integrity sha512-1R6plBRfKX3hYzeIisXmYquqpRLCnF51abl49vfKVu48TEB+cD8zvQO0xCQWC6QfcuxmFfw9BQmtIXLvDoo38A== dependencies: "@kitware/vtk.js" "32.12.1" comlink "^4.4.1" gl-matrix "^3.4.3" loglevel "^1.9.2" -"@cornerstonejs/dicom-image-loader@^3.8.5": - version "3.8.5" - resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-3.8.5.tgz#963a3174af3603e4beb096d448671442a0d5f10a" - integrity sha512-yuLLU2sbtFWueNKVbeYBddPoJnfhrUQ+rRnXJb+y9iczwZMQLy4tYyk3Q5INo+/nIdwCVeZg7P9qORZERsBivw== +"@cornerstonejs/dicom-image-loader@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-3.9.1.tgz#37ce24da222271b0363d9c762674d322c56104ce" + integrity sha512-FHhFJTzrF2+CIfjDiHYWRqquInuxCYP8F16gTBDWT9FxNEMNjHqkTo7qVYhB/mG2nIV+sKcTMs4OSx3hBDqikQ== dependencies: "@cornerstonejs/codec-charls" "^1.2.3" "@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2" @@ -1468,25 +1468,25 @@ pako "^2.0.4" uuid "^9.0.0" -"@cornerstonejs/labelmap-interpolation@^3.8.5": - version "3.8.5" - resolved "https://registry.yarnpkg.com/@cornerstonejs/labelmap-interpolation/-/labelmap-interpolation-3.8.5.tgz#19e8142362d5b83540bcb764306cd6bdf277c9ce" - integrity sha512-u80OTJE8eju+tZ+S/N1b/HTIw2mPjEE2o5u3T/7/w90FX7OaxJJiMYjPPfnSZWXjE2HhRu0gEAKHOU3dr8pL4w== +"@cornerstonejs/labelmap-interpolation@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@cornerstonejs/labelmap-interpolation/-/labelmap-interpolation-3.9.1.tgz#41fc327da444136139ed046df663ad43b0a68e47" + integrity sha512-todwKvOCxnQsc5X9KNjAOjC74bop8UYgA/Mnhl+fCagGaVxS5t+GlnV2PG29Yw9Klw+S4vJkd0XiMCgO2BevLw== dependencies: "@itk-wasm/morphological-contour-interpolation" "1.1.0" itk-wasm "1.0.0-b.165" -"@cornerstonejs/polymorphic-segmentation@^3.8.5": - version "3.8.5" - resolved "https://registry.yarnpkg.com/@cornerstonejs/polymorphic-segmentation/-/polymorphic-segmentation-3.8.5.tgz#5289f1b9d7f8fdbf3164330c4d30dd03fffa16be" - integrity sha512-6L9a9f36CnUIuGsydA8kkkC0z1Gjid4KfclCQoYYaxcsLWLDpba5usFERmxCLIm9VyBsA3POqesIGDqWTgJmFg== +"@cornerstonejs/polymorphic-segmentation@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@cornerstonejs/polymorphic-segmentation/-/polymorphic-segmentation-3.9.1.tgz#599307c3e606d6199d3cf9351a17be9dbc028029" + integrity sha512-QAJYYBtXNpHSKFiN4kVuCOlQB2Cnl6UrnTgAgBKw1sE00wrmbjyF/z1x1qBR34IkAe1ggMbF1QmhQpR90s1M6A== dependencies: "@icr/polyseg-wasm" "0.4.0" -"@cornerstonejs/tools@^3.8.5": - version "3.8.5" - resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-3.8.5.tgz#15fe20fa051dc12084141515c2a715a4f0a9a858" - integrity sha512-aTaziRHJakCCxvbHhbrSkEuiamURGakcK83KXGJPjSdStWC/2cVpkCzPxc8V7FZBIstsvo5pgciXSpNc6Yt7Og== +"@cornerstonejs/tools@^3.9.1": + version "3.9.1" + resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-3.9.1.tgz#e821057de4eb773337380c7f4143bebe25281a8c" + integrity sha512-OP3oZ+Af3ax3Kdo7DLaRs74XlRHTpBuePZvUuYb21VsWBVr50E9nRV5zyCo/4klRb+/zEKlWGQbQogmQxv9+NA== dependencies: "@types/offscreencanvas" "2019.7.3" comlink "^4.4.1" @@ -6729,7 +6729,7 @@ axios@^0.27.2: follow-redirects "^1.14.9" form-data "^4.0.0" -axios@^1.0.0, axios@^1.4.0, axios@^1.6.2, axios@^1.8.2: +axios@^1.0.0, axios@^1.4.0, axios@^1.6.2: version "1.8.3" resolved "https://registry.yarnpkg.com/axios/-/axios-1.8.3.tgz#9ebccd71c98651d547162a018a1a95a4b4ed4de8" integrity sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A== @@ -6738,6 +6738,15 @@ axios@^1.0.0, axios@^1.4.0, axios@^1.6.2, axios@^1.8.2: form-data "^4.0.0" proxy-from-env "^1.1.0" +axios@^1.8.4: + version "1.8.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.8.4.tgz#78990bb4bc63d2cae072952d374835950a82f447" + integrity sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + axobject-query@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" @@ -15313,7 +15322,7 @@ modify-values@^1.0.1: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== -moment@*, moment@>=1.6.0, moment@^2.9.4: +moment@>=1.6.0, moment@^2.30.1: version "2.30.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==