fix(segmentation): List surface representations in the segmentation table for 3D views. (#5700)

This was done by using an array of representation types instead of a single type for a panel.
The first element of the array is the primary type of the panel, and the rest are secondary types
that can also be displayed in the panel.

PR feedback:
- added test to check number of segments in side panel for 3D only view
- fixed jumping to segment in 3D only view
- fixed exception when adding contour segment in 3D only view
This commit is contained in:
Joe Boccanfuso 2026-01-13 15:57:44 -05:00 committed by GitHub
parent 83c9ce0f5f
commit 82e6a18735
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 356 additions and 293 deletions

330
bun.lock
View File

@ -52,7 +52,7 @@
},
"addOns/externals/devDependencies": {
"name": "@externals/devDependencies",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"@kitware/vtk.js": "34.15.1",
@ -137,22 +137,22 @@
},
"addOns/externals/dicom-microscopy-viewer": {
"name": "@externals/dicom-microscopy-viewer",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"dicom-microscopy-viewer": "0.48.6",
},
},
"extensions/cornerstone": {
"name": "@ohif/extension-cornerstone",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/adapters": "4.15.6",
"@cornerstonejs/ai": "4.15.6",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/labelmap-interpolation": "4.15.6",
"@cornerstonejs/polymorphic-segmentation": "4.15.6",
"@cornerstonejs/tools": "4.15.6",
"@cornerstonejs/adapters": "4.15.7",
"@cornerstonejs/ai": "4.15.7",
"@cornerstonejs/core": "4.15.7",
"@cornerstonejs/labelmap-interpolation": "4.15.7",
"@cornerstonejs/polymorphic-segmentation": "4.15.7",
"@cornerstonejs/tools": "4.15.7",
"@itk-wasm/morphological-contour-interpolation": "1.1.0",
"@kitware/vtk.js": "34.15.1",
"html2canvas": "1.4.1",
@ -169,9 +169,9 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "1.2.2",
"@cornerstonejs/codec-openjpeg": "1.3.0",
"@cornerstonejs/codec-openjph": "2.4.7",
"@cornerstonejs/dicom-image-loader": "4.15.6",
"@ohif/core": "3.12.0-beta.120",
"@ohif/ui": "3.12.0-beta.120",
"@cornerstonejs/dicom-image-loader": "4.15.7",
"@ohif/core": "3.12.0-beta.121",
"@ohif/ui": "3.12.0-beta.121",
"dcmjs": "0.45.0",
"dicom-parser": "1.8.21",
"hammerjs": "2.0.8",
@ -183,19 +183,19 @@
},
"extensions/cornerstone-dicom-pmap": {
"name": "@ohif/extension-cornerstone-dicom-pmap",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/adapters": "4.15.6",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/adapters": "4.15.7",
"@cornerstonejs/core": "4.15.7",
"@kitware/vtk.js": "34.15.1",
"react-color": "2.19.3",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-cornerstone": "3.12.0-beta.120",
"@ohif/extension-default": "3.12.0-beta.120",
"@ohif/i18n": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone": "3.12.0-beta.121",
"@ohif/extension-default": "3.12.0-beta.121",
"@ohif/i18n": "3.12.0-beta.121",
"prop-types": "15.8.1",
"react": "18.3.1",
"react-dom": "18.3.1",
@ -206,16 +206,16 @@
},
"extensions/cornerstone-dicom-rt": {
"name": "@ohif/extension-cornerstone-dicom-rt",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"react-color": "2.19.3",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-cornerstone": "3.12.0-beta.120",
"@ohif/extension-default": "3.12.0-beta.120",
"@ohif/i18n": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone": "3.12.0-beta.121",
"@ohif/extension-default": "3.12.0-beta.121",
"@ohif/i18n": "3.12.0-beta.121",
"prop-types": "15.8.1",
"react": "18.3.1",
"react-dom": "18.3.1",
@ -226,19 +226,19 @@
},
"extensions/cornerstone-dicom-seg": {
"name": "@ohif/extension-cornerstone-dicom-seg",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/adapters": "4.15.6",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/adapters": "4.15.7",
"@cornerstonejs/core": "4.15.7",
"@kitware/vtk.js": "34.15.1",
"react-color": "2.19.3",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-cornerstone": "3.12.0-beta.120",
"@ohif/extension-default": "3.12.0-beta.120",
"@ohif/i18n": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone": "3.12.0-beta.121",
"@ohif/extension-default": "3.12.0-beta.121",
"@ohif/i18n": "3.12.0-beta.121",
"prop-types": "15.8.1",
"react": "18.3.1",
"react-dom": "18.3.1",
@ -249,19 +249,19 @@
},
"extensions/cornerstone-dicom-sr": {
"name": "@ohif/extension-cornerstone-dicom-sr",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/adapters": "4.15.6",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/tools": "4.15.6",
"@cornerstonejs/adapters": "4.15.7",
"@cornerstonejs/core": "4.15.7",
"@cornerstonejs/tools": "4.15.7",
"classnames": "2.5.1",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-cornerstone": "3.12.0-beta.120",
"@ohif/extension-measurement-tracking": "3.12.0-beta.120",
"@ohif/ui": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone": "3.12.0-beta.121",
"@ohif/extension-measurement-tracking": "3.12.0-beta.121",
"@ohif/ui": "3.12.0-beta.121",
"dcmjs": "0.45.0",
"dicom-parser": "1.8.21",
"hammerjs": "2.0.8",
@ -271,19 +271,19 @@
},
"extensions/cornerstone-dynamic-volume": {
"name": "@ohif/extension-cornerstone-dynamic-volume",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/tools": "4.15.6",
"@cornerstonejs/core": "4.15.7",
"@cornerstonejs/tools": "4.15.7",
"classnames": "2.5.1",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-cornerstone": "3.12.0-beta.120",
"@ohif/extension-default": "3.12.0-beta.120",
"@ohif/i18n": "3.12.0-beta.120",
"@ohif/ui": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone": "3.12.0-beta.121",
"@ohif/extension-default": "3.12.0-beta.121",
"@ohif/i18n": "3.12.0-beta.121",
"@ohif/ui": "3.12.0-beta.121",
"dcmjs": "0.45.0",
"dicom-parser": "1.8.21",
"hammerjs": "2.0.8",
@ -293,7 +293,7 @@
},
"extensions/default": {
"name": "@ohif/extension-default",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/calculate-suv": "1.1.0",
@ -301,8 +301,8 @@
"lodash.uniqby": "4.7.0",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/i18n": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/i18n": "3.12.0-beta.121",
"dcmjs": "0.45.0",
"dicomweb-client": "0.10.4",
"prop-types": "15.8.1",
@ -316,7 +316,7 @@
},
"extensions/dicom-microscopy": {
"name": "@ohif/extension-dicom-microscopy",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/codec-charls": "1.2.3",
@ -327,10 +327,10 @@
"mathjs": "12.4.3",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-default": "3.12.0-beta.120",
"@ohif/i18n": "3.12.0-beta.120",
"@ohif/ui": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-default": "3.12.0-beta.121",
"@ohif/i18n": "3.12.0-beta.121",
"@ohif/ui": "3.12.0-beta.121",
"prop-types": "15.8.1",
"react": "18.3.1",
"react-dom": "18.3.1",
@ -341,14 +341,14 @@
},
"extensions/dicom-pdf": {
"name": "@ohif/extension-dicom-pdf",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"classnames": "2.5.1",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/ui": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/ui": "3.12.0-beta.121",
"dcmjs": "0.45.0",
"dicom-parser": "1.8.21",
"hammerjs": "2.0.8",
@ -358,14 +358,14 @@
},
"extensions/dicom-video": {
"name": "@ohif/extension-dicom-video",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"classnames": "2.5.1",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/ui": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/ui": "3.12.0-beta.121",
"dcmjs": "0.45.0",
"dicom-parser": "1.8.21",
"hammerjs": "2.0.8",
@ -375,20 +375,20 @@
},
"extensions/measurement-tracking": {
"name": "@ohif/extension-measurement-tracking",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"@ohif/ui": "3.12.0-beta.120",
"@ohif/ui": "3.12.0-beta.121",
"@xstate/react": "3.2.2",
"xstate": "4.38.3",
},
"peerDependencies": {
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/tools": "4.15.6",
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.120",
"@ohif/extension-default": "3.12.0-beta.120",
"@ohif/ui": "3.12.0-beta.120",
"@cornerstonejs/core": "4.15.7",
"@cornerstonejs/tools": "4.15.7",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.121",
"@ohif/extension-default": "3.12.0-beta.121",
"@ohif/ui": "3.12.0-beta.121",
"classnames": "2.5.1",
"dcmjs": "0.45.0",
"lodash.debounce": "4.0.8",
@ -401,14 +401,14 @@
},
"extensions/test-extension": {
"name": "@ohif/extension-test",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"classnames": "2.5.1",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/ui": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/ui": "3.12.0-beta.121",
"dcmjs": "0.45.0",
"dicom-parser": "1.8.21",
"hammerjs": "2.0.8",
@ -418,7 +418,7 @@
},
"extensions/tmtv": {
"name": "@ohif/extension-tmtv",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"classnames": "2.5.1",
@ -435,16 +435,16 @@
},
"extensions/usAnnotation": {
"name": "@ohif/extension-ultrasound-pleura-bline",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/tools": "4.15.6",
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-cornerstone": "3.12.0-beta.120",
"@ohif/extension-default": "3.12.0-beta.120",
"@ohif/i18n": "3.12.0-beta.120",
"@ohif/ui-next": "3.12.0-beta.120",
"@cornerstonejs/core": "4.15.7",
"@cornerstonejs/tools": "4.15.7",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone": "3.12.0-beta.121",
"@ohif/extension-default": "3.12.0-beta.121",
"@ohif/i18n": "3.12.0-beta.121",
"@ohif/ui-next": "3.12.0-beta.121",
},
"devDependencies": {
"@babel/core": "7.28.0",
@ -487,7 +487,7 @@
},
"modes/basic": {
"name": "@ohif/mode-basic",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
},
@ -496,19 +496,19 @@
"webpack-merge": "5.10.0",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-cornerstone": "3.12.0-beta.120",
"@ohif/extension-cornerstone-dicom-rt": "3.12.0-beta.120",
"@ohif/extension-cornerstone-dicom-seg": "3.12.0-beta.120",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.120",
"@ohif/extension-default": "3.12.0-beta.120",
"@ohif/extension-dicom-pdf": "3.12.0-beta.120",
"@ohif/extension-dicom-video": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-rt": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-seg": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.121",
"@ohif/extension-default": "3.12.0-beta.121",
"@ohif/extension-dicom-pdf": "3.12.0-beta.121",
"@ohif/extension-dicom-video": "3.12.0-beta.121",
},
},
"modes/basic-dev-mode": {
"name": "@ohif/mode-basic-dev-mode",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"i18next": "17.3.1",
@ -518,17 +518,17 @@
"webpack-merge": "5.10.0",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-cornerstone": "3.12.0-beta.120",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.120",
"@ohif/extension-default": "3.12.0-beta.120",
"@ohif/extension-dicom-pdf": "3.12.0-beta.120",
"@ohif/extension-dicom-video": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.121",
"@ohif/extension-default": "3.12.0-beta.121",
"@ohif/extension-dicom-pdf": "3.12.0-beta.121",
"@ohif/extension-dicom-video": "3.12.0-beta.121",
},
},
"modes/basic-test-mode": {
"name": "@ohif/mode-test",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"i18next": "17.3.1",
@ -538,19 +538,19 @@
"webpack-merge": "5.10.0",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-cornerstone": "3.12.0-beta.120",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.120",
"@ohif/extension-default": "3.12.0-beta.120",
"@ohif/extension-dicom-pdf": "3.12.0-beta.120",
"@ohif/extension-dicom-video": "3.12.0-beta.120",
"@ohif/extension-measurement-tracking": "3.12.0-beta.120",
"@ohif/extension-test": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.121",
"@ohif/extension-default": "3.12.0-beta.121",
"@ohif/extension-dicom-pdf": "3.12.0-beta.121",
"@ohif/extension-dicom-video": "3.12.0-beta.121",
"@ohif/extension-measurement-tracking": "3.12.0-beta.121",
"@ohif/extension-test": "3.12.0-beta.121",
},
},
"modes/longitudinal": {
"name": "@ohif/mode-longitudinal",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"i18next": "17.3.1",
@ -560,33 +560,33 @@
"webpack-merge": "5.10.0",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-cornerstone": "3.12.0-beta.120",
"@ohif/extension-cornerstone-dicom-rt": "3.12.0-beta.120",
"@ohif/extension-cornerstone-dicom-seg": "3.12.0-beta.120",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.120",
"@ohif/extension-default": "3.12.0-beta.120",
"@ohif/extension-dicom-pdf": "3.12.0-beta.120",
"@ohif/extension-dicom-video": "3.12.0-beta.120",
"@ohif/extension-measurement-tracking": "3.12.0-beta.120",
"@ohif/mode-basic": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-rt": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-seg": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.121",
"@ohif/extension-default": "3.12.0-beta.121",
"@ohif/extension-dicom-pdf": "3.12.0-beta.121",
"@ohif/extension-dicom-video": "3.12.0-beta.121",
"@ohif/extension-measurement-tracking": "3.12.0-beta.121",
"@ohif/mode-basic": "3.12.0-beta.121",
},
},
"modes/microscopy": {
"name": "@ohif/mode-microscopy",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"i18next": "17.3.1",
},
"peerDependencies": {
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-dicom-microscopy": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-dicom-microscopy": "3.12.0-beta.121",
},
},
"modes/preclinical-4d": {
"name": "@ohif/mode-preclinical-4d",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
},
@ -605,7 +605,7 @@
},
"modes/segmentation": {
"name": "@ohif/mode-segmentation",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"i18next": "17.3.1",
@ -650,7 +650,7 @@
},
"modes/tmtv": {
"name": "@ohif/mode-tmtv",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"i18next": "17.3.1",
@ -671,14 +671,14 @@
},
"modes/usAnnotation": {
"name": "@ohif/mode-ultrasound-pleura-bline",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/tools": "4.15.6",
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.120",
"@ohif/extension-ultrasound-pleura-bline": "3.12.0-beta.120",
"@cornerstonejs/core": "4.15.7",
"@cornerstonejs/tools": "4.15.7",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.121",
"@ohif/extension-ultrasound-pleura-bline": "3.12.0-beta.121",
"i18next": "17.3.1",
},
"devDependencies": {
@ -710,34 +710,34 @@
},
"platform/app": {
"name": "@ohif/app",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/codec-charls": "1.2.3",
"@cornerstonejs/codec-libjpeg-turbo-8bit": "1.2.2",
"@cornerstonejs/codec-openjpeg": "1.3.0",
"@cornerstonejs/codec-openjph": "2.4.7",
"@cornerstonejs/dicom-image-loader": "4.15.6",
"@cornerstonejs/dicom-image-loader": "4.15.7",
"@emotion/serialize": "1.3.3",
"@ohif/core": "3.12.0-beta.120",
"@ohif/extension-cornerstone": "3.12.0-beta.120",
"@ohif/extension-cornerstone-dicom-rt": "3.12.0-beta.120",
"@ohif/extension-cornerstone-dicom-seg": "3.12.0-beta.120",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.120",
"@ohif/extension-default": "3.12.0-beta.120",
"@ohif/extension-dicom-microscopy": "3.12.0-beta.120",
"@ohif/extension-dicom-pdf": "3.12.0-beta.120",
"@ohif/extension-dicom-video": "3.12.0-beta.120",
"@ohif/extension-test": "3.12.0-beta.120",
"@ohif/extension-ultrasound-pleura-bline": "3.12.0-beta.120",
"@ohif/i18n": "3.12.0-beta.120",
"@ohif/mode-basic-dev-mode": "3.12.0-beta.120",
"@ohif/mode-longitudinal": "3.12.0-beta.120",
"@ohif/mode-microscopy": "3.12.0-beta.120",
"@ohif/mode-test": "3.12.0-beta.120",
"@ohif/mode-ultrasound-pleura-bline": "3.12.0-beta.120",
"@ohif/ui": "3.12.0-beta.120",
"@ohif/ui-next": "3.12.0-beta.120",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-rt": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-seg": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.121",
"@ohif/extension-default": "3.12.0-beta.121",
"@ohif/extension-dicom-microscopy": "3.12.0-beta.121",
"@ohif/extension-dicom-pdf": "3.12.0-beta.121",
"@ohif/extension-dicom-video": "3.12.0-beta.121",
"@ohif/extension-test": "3.12.0-beta.121",
"@ohif/extension-ultrasound-pleura-bline": "3.12.0-beta.121",
"@ohif/i18n": "3.12.0-beta.121",
"@ohif/mode-basic-dev-mode": "3.12.0-beta.121",
"@ohif/mode-longitudinal": "3.12.0-beta.121",
"@ohif/mode-microscopy": "3.12.0-beta.121",
"@ohif/mode-test": "3.12.0-beta.121",
"@ohif/mode-ultrasound-pleura-bline": "3.12.0-beta.121",
"@ohif/ui": "3.12.0-beta.121",
"@ohif/ui-next": "3.12.0-beta.121",
"@svgr/webpack": "8.1.0",
"@types/react": "18.3.23",
"classnames": "2.5.1",
@ -789,7 +789,7 @@
},
"platform/cli": {
"name": "@ohif/cli",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"bin": {
"ohif-cli": "src/index.js",
},
@ -813,7 +813,7 @@
},
"platform/core": {
"name": "@ohif/core",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"dcmjs": "0.45.0",
@ -838,16 +838,16 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "1.2.2",
"@cornerstonejs/codec-openjpeg": "1.3.0",
"@cornerstonejs/codec-openjph": "2.4.7",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/dicom-image-loader": "4.15.6",
"@ohif/ui": "3.12.0-beta.120",
"@cornerstonejs/core": "4.15.7",
"@cornerstonejs/dicom-image-loader": "4.15.7",
"@ohif/ui": "3.12.0-beta.121",
"cornerstone-math": "0.1.9",
"dicom-parser": "1.8.21",
},
},
"platform/i18n": {
"name": "@ohif/i18n",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@babel/runtime": "7.28.2",
"i18next-locize-backend": "2.2.2",
@ -872,7 +872,7 @@
},
"platform/ui": {
"name": "@ohif/ui",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@testing-library/react": "13.4.0",
"browser-detect": "0.2.28",
@ -923,7 +923,7 @@
},
"platform/ui-next": {
"name": "@ohif/ui-next",
"version": "3.12.0-beta.120",
"version": "3.12.0-beta.121",
"dependencies": {
"@radix-ui/react-accordion": "1.2.11",
"@radix-ui/react-checkbox": "1.3.2",
@ -1232,9 +1232,9 @@
"@bcoe/v8-coverage": ["@bcoe/v8-coverage@0.2.3", "", {}, "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="],
"@cornerstonejs/adapters": ["@cornerstonejs/adapters@4.15.6", "", { "dependencies": { "@babel/runtime-corejs2": "7.26.10", "buffer": "6.0.3", "dcmjs": "0.45.0", "gl-matrix": "3.4.3", "ndarray": "1.0.19" }, "peerDependencies": { "@cornerstonejs/core": "4.15.6", "@cornerstonejs/tools": "4.15.6" } }, "sha512-pl4yKwkJRc9CxYMIKs4XGsXPWeLbrpfFRJmUDE/S8oNhZgqNQ1KsL6I0epN5aU9Igo9kpzNTpFVwIhWScbbZTQ=="],
"@cornerstonejs/adapters": ["@cornerstonejs/adapters@4.15.7", "", { "dependencies": { "@babel/runtime-corejs2": "7.26.10", "buffer": "6.0.3", "dcmjs": "0.45.0", "gl-matrix": "3.4.3", "ndarray": "1.0.19" }, "peerDependencies": { "@cornerstonejs/core": "4.15.7", "@cornerstonejs/tools": "4.15.7" } }, "sha512-3ScwvPoa4v0mIQ52+Ua9dgPhsShH+sHo5hHRWICRPZ9vl99vMWLXK2vfSPc1U2iFLDP553JoT7g3D6V2DaUPWQ=="],
"@cornerstonejs/ai": ["@cornerstonejs/ai@4.15.6", "", { "dependencies": { "@babel/runtime-corejs2": "7.26.10", "buffer": "6.0.3", "dcmjs": "0.45.0", "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": "4.15.6", "@cornerstonejs/tools": "4.15.6" } }, "sha512-aqsZrO/nDWP8g9PrDantWm4+7IWwbTuqRstxVyGQ6oH+mZYIkcq4IHrISEnnEMrZMQ8GAcz3+ORV3EieO00Ovg=="],
"@cornerstonejs/ai": ["@cornerstonejs/ai@4.15.7", "", { "dependencies": { "@babel/runtime-corejs2": "7.26.10", "buffer": "6.0.3", "dcmjs": "0.45.0", "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": "4.15.7", "@cornerstonejs/tools": "4.15.7" } }, "sha512-A7Sr+2Kv3uFfw2/nWf/Qi1l1fB/6J54uM3p9OnOB/F6G9pFaGkdRJtUBm133TfRPo0xL7nCT79x5cAw006josw=="],
"@cornerstonejs/calculate-suv": ["@cornerstonejs/calculate-suv@1.1.0", "", {}, "sha512-Q9XraiDJif9aMFArD2iEuDO/HXbcRVCqB7KfaHgDrdTTjgDFovS91Psbdim7crypRSvE6dh/+HKeFNHdvNkA6w=="],
@ -1246,15 +1246,15 @@
"@cornerstonejs/codec-openjph": ["@cornerstonejs/codec-openjph@2.4.7", "", {}, "sha512-qvP4q4JDib7mi9r7LqKOwqz7YZ8gjtDX4ZCezeYf8+eb7MBXCz5uXAMeVF3yz9Axw4XiIMdB/pqXkm8tqCl13w=="],
"@cornerstonejs/core": ["@cornerstonejs/core@4.15.6", "", { "dependencies": { "@kitware/vtk.js": "34.15.1", "comlink": "4.4.2", "gl-matrix": "3.4.3", "loglevel": "1.9.2" } }, "sha512-7faicjRwUSeVhSRpM1MaLiEdH8daxnQm0BZl7HAnhrbS1zTHSrzKVxtj9zVJJ2SP3QCzBZmMfFan8MgWo61L0A=="],
"@cornerstonejs/core": ["@cornerstonejs/core@4.15.7", "", { "dependencies": { "@kitware/vtk.js": "34.15.1", "comlink": "4.4.2", "gl-matrix": "3.4.3", "loglevel": "1.9.2" } }, "sha512-uPdNSbGz7TtFQdNHpSx8ilC0NJngfaOGJsuZMcHFvtjvMRuXhOyzuxJ/RhbgmDjWE1Jig65zI6Wd7prnKo9uKA=="],
"@cornerstonejs/dicom-image-loader": ["@cornerstonejs/dicom-image-loader@4.15.6", "", { "dependencies": { "@cornerstonejs/codec-charls": "1.2.3", "@cornerstonejs/codec-libjpeg-turbo-8bit": "1.2.2", "@cornerstonejs/codec-openjpeg": "1.3.0", "@cornerstonejs/codec-openjph": "2.4.7", "comlink": "4.4.2", "dicom-parser": "1.8.21", "jpeg-lossless-decoder-js": "2.1.2", "pako": "2.1.0", "uuid": "9.0.1" }, "peerDependencies": { "@cornerstonejs/core": "4.15.6" } }, "sha512-VYNMYIcK9EaUYO7pYpr0AiEyTUZqXHJWSGak77MbpjYJ8PWeHgNaQzPHp0gvcaQUT1uwIfU1Wo/rVlu0cALLpA=="],
"@cornerstonejs/dicom-image-loader": ["@cornerstonejs/dicom-image-loader@4.15.7", "", { "dependencies": { "@cornerstonejs/codec-charls": "1.2.3", "@cornerstonejs/codec-libjpeg-turbo-8bit": "1.2.2", "@cornerstonejs/codec-openjpeg": "1.3.0", "@cornerstonejs/codec-openjph": "2.4.7", "comlink": "4.4.2", "dicom-parser": "1.8.21", "jpeg-lossless-decoder-js": "2.1.2", "pako": "2.1.0", "uuid": "9.0.1" }, "peerDependencies": { "@cornerstonejs/core": "4.15.7" } }, "sha512-U00F2XiQRARAKIxQCnhIOZBEZwVfV0AiU02iZ49Chw7VsBm/6zt+zJMVh6veGNd8PHrIJKKuXONYLa5OB08ffg=="],
"@cornerstonejs/labelmap-interpolation": ["@cornerstonejs/labelmap-interpolation@4.15.6", "", { "dependencies": { "@itk-wasm/morphological-contour-interpolation": "1.1.0", "itk-wasm": "1.0.0-b.165" }, "peerDependencies": { "@cornerstonejs/core": "4.15.6", "@cornerstonejs/tools": "4.15.6", "@kitware/vtk.js": "34.15.1" } }, "sha512-GtklMlxmlaG1XrzaYrTnFrosWoLEPbZwlMc/kbrdrMZAYe8hXvGrkoIYPM0GnBrfQYL1Pjfqi+VhiSyCFX+ehQ=="],
"@cornerstonejs/labelmap-interpolation": ["@cornerstonejs/labelmap-interpolation@4.15.7", "", { "dependencies": { "@itk-wasm/morphological-contour-interpolation": "1.1.0", "itk-wasm": "1.0.0-b.165" }, "peerDependencies": { "@cornerstonejs/core": "4.15.7", "@cornerstonejs/tools": "4.15.7", "@kitware/vtk.js": "34.15.1" } }, "sha512-4rZr+Jt5tw2jYAP9Pku2QCVq3hZH/+8O4YdsGtdlLLz+z6YNyWG9qSzQHIzDqbpbZRRlOdmxd2vDOBvr+I3axg=="],
"@cornerstonejs/polymorphic-segmentation": ["@cornerstonejs/polymorphic-segmentation@4.15.6", "", { "dependencies": { "@icr/polyseg-wasm": "0.4.0" }, "peerDependencies": { "@cornerstonejs/core": "4.15.6", "@cornerstonejs/tools": "4.15.6", "@kitware/vtk.js": "34.15.1" } }, "sha512-t+OqolPp1DhlOVMtS6D088d3iQGOAjS4O5Sw8gOCZ4C/pg+jHmNJpkrGlFw8qUhnJ1D9JU3+dTJdLL8Xwq9HNg=="],
"@cornerstonejs/polymorphic-segmentation": ["@cornerstonejs/polymorphic-segmentation@4.15.7", "", { "dependencies": { "@icr/polyseg-wasm": "0.4.0" }, "peerDependencies": { "@cornerstonejs/core": "4.15.7", "@cornerstonejs/tools": "4.15.7", "@kitware/vtk.js": "34.15.1" } }, "sha512-N+YpP2qwdVhPyKd3kcmXQhTZfj+C/Xo+Bko9Jg9FCIk03OkTK3FUndDxWlLoGraIWhME9GfMz1aocKvCyUnDgg=="],
"@cornerstonejs/tools": ["@cornerstonejs/tools@4.15.6", "", { "dependencies": { "@types/offscreencanvas": "2019.7.3", "comlink": "4.4.2", "lodash.get": "4.4.2" }, "peerDependencies": { "@cornerstonejs/core": "4.15.6", "@kitware/vtk.js": "34.15.1", "@types/d3-array": "3.2.1", "@types/d3-interpolate": "3.0.4", "d3-array": "3.2.4", "d3-interpolate": "3.0.1", "gl-matrix": "3.4.3" } }, "sha512-MPZwkMkZqJVdGXiKqsO4T7jiR9m0KFNfp5DV/KdyUchrz7TPBfbO2r2aBxowo3ARutlJuQWDgPv9hcLRueLhIw=="],
"@cornerstonejs/tools": ["@cornerstonejs/tools@4.15.7", "", { "dependencies": { "@types/offscreencanvas": "2019.7.3", "comlink": "4.4.2", "lodash.get": "4.4.2" }, "peerDependencies": { "@cornerstonejs/core": "4.15.7", "@kitware/vtk.js": "34.15.1", "@types/d3-array": "3.2.1", "@types/d3-interpolate": "3.0.4", "d3-array": "3.2.4", "d3-interpolate": "3.0.1", "gl-matrix": "3.4.3" } }, "sha512-LHroV6ZrQ/aGkpyoVHSx+qAPSol30jlSpwUIvguirnmFW4VwUgAaWeLmKpyy78EgqukzEDCFPXtGiD+TPIITKw=="],
"@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="],

View File

@ -46,8 +46,8 @@
},
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/adapters": "4.15.6",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/adapters": "4.15.7",
"@cornerstonejs/core": "4.15.7",
"@kitware/vtk.js": "34.15.1",
"react-color": "2.19.3"
}

View File

@ -46,8 +46,8 @@
},
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/adapters": "4.15.6",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/adapters": "4.15.7",
"@cornerstonejs/core": "4.15.7",
"@kitware/vtk.js": "34.15.1",
"react-color": "2.19.3"
}

View File

@ -46,9 +46,9 @@
},
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/adapters": "4.15.6",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/tools": "4.15.6",
"@cornerstonejs/adapters": "4.15.7",
"@cornerstonejs/core": "4.15.7",
"@cornerstonejs/tools": "4.15.7",
"classnames": "2.5.1"
}
}

View File

@ -42,8 +42,8 @@
},
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/tools": "4.15.6",
"@cornerstonejs/core": "4.15.7",
"@cornerstonejs/tools": "4.15.7",
"classnames": "2.5.1"
}
}

View File

@ -40,7 +40,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "1.2.2",
"@cornerstonejs/codec-openjpeg": "1.3.0",
"@cornerstonejs/codec-openjph": "2.4.7",
"@cornerstonejs/dicom-image-loader": "4.15.6",
"@cornerstonejs/dicom-image-loader": "4.15.7",
"@ohif/core": "3.12.0-beta.121",
"@ohif/ui": "3.12.0-beta.121",
"dcmjs": "0.45.0",
@ -53,12 +53,12 @@
},
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/adapters": "4.15.6",
"@cornerstonejs/ai": "4.15.6",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/labelmap-interpolation": "4.15.6",
"@cornerstonejs/polymorphic-segmentation": "4.15.6",
"@cornerstonejs/tools": "4.15.6",
"@cornerstonejs/adapters": "4.15.7",
"@cornerstonejs/ai": "4.15.7",
"@cornerstonejs/core": "4.15.7",
"@cornerstonejs/labelmap-interpolation": "4.15.7",
"@cornerstonejs/polymorphic-segmentation": "4.15.7",
"@cornerstonejs/tools": "4.15.7",
"@itk-wasm/morphological-contour-interpolation": "1.1.0",
"@kitware/vtk.js": "34.15.1",
"html2canvas": "1.4.1",

View File

@ -5,6 +5,7 @@ import { utils } from '../..';
import { useViewportSegmentations } from '../../hooks';
import { useMeasurementTracking } from '../../hooks/useMeasurementTracking';
import { useViewportDisplaySets } from '../../hooks/useViewportDisplaySets';
import { SegmentationRepresentations } from '@cornerstonejs/tools/enums';
/**
* NavigationComponent provides navigation controls for viewports containing
@ -27,7 +28,11 @@ function NavigationComponent({ viewportId }: { viewportId: string }) {
viewportId,
});
const hasSegmentations = segmentationsWithRepresentations.length > 0;
const hasSegmentations =
segmentationsWithRepresentations.length > 0 &&
segmentationsWithRepresentations.some(
segmentation => segmentation?.representation?.type !== SegmentationRepresentations.Surface
);
// prefer segment navigation if available
const navigationMode = hasSegmentations

View File

@ -26,7 +26,7 @@ export const CustomDropdownMenuContent = () => {
exportOptions,
activeSegmentation,
activeSegmentationId,
segmentationRepresentationType,
segmentationRepresentationTypes,
disableEditing,
} = useSegmentationTableContext('CustomDropdownMenu');
@ -79,7 +79,12 @@ export const CustomDropdownMenuContent = () => {
<DropdownMenuContent align="start">
{!disableEditing && (
<DropdownMenuItem
onClick={() => onSegmentationAdd({ segmentationId, segmentationRepresentationType })}
onClick={() =>
onSegmentationAdd({
segmentationId,
segmentationRepresentationType: segmentationRepresentationTypes?.[0],
})
}
>
<Icons.Add className="text-foreground" />
<span className="pl-2">{t('Create New Segmentation')}</span>
@ -97,7 +102,7 @@ export const CustomDropdownMenuContent = () => {
</DropdownMenuItem>
<ExportSegmentationSubMenuItem
segmentationId={segmentationId}
segmentationRepresentationType={segmentationRepresentationType}
segmentationRepresentationType={segmentationRepresentationTypes?.[0]}
allowExport={allowExport}
actions={actions}
/>

View File

@ -24,7 +24,7 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
configuration={{
...props?.configuration,
}}
segmentationRepresentationType={props?.segmentationRepresentationType}
segmentationRepresentationTypes={props?.segmentationRepresentationTypes}
/>
);
};
@ -38,20 +38,20 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
configuration={{
...props?.configuration,
}}
segmentationRepresentationType={props?.segmentationRepresentationType}
segmentationRepresentationTypes={props?.segmentationRepresentationTypes}
/>
);
};
const wrappedPanelSegmentationWithTools = props => {
const { t } = useTranslation('SegmentationPanel');
const tKey = `${props.segmentationRepresentationType ?? 'Segmentation'} tools`;
const tKey = `${props.segmentationRepresentationTypes?.[0] ?? 'Segmentation'} tools`;
const tValue = t(tKey);
return (
<>
<Toolbox
buttonSectionId={toolSectionMap[props.segmentationRepresentationType]}
buttonSectionId={toolSectionMap[props.segmentationRepresentationTypes?.[0]]}
title={tValue}
/>
<PanelSegmentation
@ -61,7 +61,7 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
configuration={{
...props?.configuration,
}}
segmentationRepresentationType={props?.segmentationRepresentationType}
segmentationRepresentationTypes={props?.segmentationRepresentationTypes}
/>
</>
);
@ -103,7 +103,10 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
component: props =>
wrappedPanelSegmentationWithTools({
...props,
segmentationRepresentationType: SegmentationRepresentations.Labelmap,
segmentationRepresentationTypes: [
SegmentationRepresentations.Labelmap,
SegmentationRepresentations.Surface,
],
}),
},
{
@ -114,7 +117,7 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
component: props =>
wrappedPanelSegmentationWithTools({
...props,
segmentationRepresentationType: SegmentationRepresentations.Contour,
segmentationRepresentationTypes: [SegmentationRepresentations.Contour],
}),
},
];

View File

@ -21,13 +21,14 @@ import {
type PanelSegmentationProps = {
children?: React.ReactNode;
// The representation type for this segmentation panel. Undefined means all types.
segmentationRepresentationType?: SegmentationRepresentations;
// The representation types for this segmentation panel. Undefined means all types.
// The first element is the primary type. Additional elements are secondary types.
segmentationRepresentationTypes?: SegmentationRepresentations[];
} & withAppTypes;
export default function PanelSegmentation({
children,
segmentationRepresentationType,
segmentationRepresentationTypes,
}: PanelSegmentationProps) {
const { commandsManager, servicesManager } = useSystem();
const {
@ -48,11 +49,20 @@ export default function PanelSegmentation({
store => store.selectedSegmentationsForViewport[activeViewportId]
);
const selectedSegmentationIdForType = segmentationRepresentationType
? selectedSegmentationsForViewportMap?.get(segmentationRepresentationType)
const selectedSegmentationIdForType = segmentationRepresentationTypes
? segmentationRepresentationTypes.reduce(
(selectedSegmentation, type) =>
selectedSegmentation ||
(selectedSegmentationsForViewportMap?.has(type)
? selectedSegmentationsForViewportMap?.get(type)
: undefined),
undefined
)
: segmentationService?.getActiveSegmentation(activeViewportId)?.segmentationId;
const buttonSection = utilitiesSectionMap[segmentationRepresentationType];
const buttonSection = segmentationRepresentationTypes?.[0]
? utilitiesSectionMap[segmentationRepresentationTypes[0]]
: undefined;
const { activeToolOptions: activeUtilityOptions } = useActiveToolOptions({
buttonSectionId: buttonSection,
@ -129,7 +139,7 @@ export default function PanelSegmentation({
commandsManager.run('deleteSegment', { segmentationId, segmentIndex });
},
onSegmentCopy:
segmentationRepresentationType === SegmentationRepresentations.Contour
segmentationRepresentationTypes?.[0] === SegmentationRepresentations.Contour
? (segmentationId, segmentIndex) => {
commandsManager.run('copyContourSegment', {
sourceSegmentInfo: { segmentationId, segmentIndex },
@ -227,13 +237,13 @@ export default function PanelSegmentation({
disabled,
data: segmentationsWithRepresentations,
mode: segmentationTableMode,
title: `${segmentationRepresentationType ? `${segmentationRepresentationType} ` : ''}Segmentations`,
title: `${segmentationRepresentationTypes?.[0] ? `${segmentationRepresentationTypes[0]} ` : ''}Segmentations`,
exportOptions,
disableEditing,
onSegmentationAdd,
showAddSegment,
renderInactiveSegmentations: handlers.getRenderInactiveSegmentations(),
segmentationRepresentationType,
segmentationRepresentationTypes,
selectedSegmentationIdForType,
...handlers,
};

View File

@ -1271,6 +1271,10 @@ class SegmentationService extends PubSubService {
viewportIds.forEach(viewportId => {
const { viewport } = getEnabledElementByViewportId(viewportId);
if (!viewport?.jumpToWorld) {
return;
}
viewport.jumpToWorld(world);
highlightSegment &&

View File

@ -32,8 +32,8 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/tools": "4.15.6",
"@cornerstonejs/core": "4.15.7",
"@cornerstonejs/tools": "4.15.7",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.121",
"@ohif/extension-default": "3.12.0-beta.121",

View File

@ -42,8 +42,8 @@
},
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/tools": "4.15.6",
"@cornerstonejs/core": "4.15.7",
"@cornerstonejs/tools": "4.15.7",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone": "3.12.0-beta.121",
"@ohif/extension-default": "3.12.0-beta.121",

View File

@ -34,8 +34,8 @@
},
"dependencies": {
"@babel/runtime": "7.28.2",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/tools": "4.15.6",
"@cornerstonejs/core": "4.15.7",
"@cornerstonejs/tools": "4.15.7",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone-dicom-sr": "3.12.0-beta.121",
"@ohif/extension-ultrasound-pleura-bline": "3.12.0-beta.121",

View File

@ -53,7 +53,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "1.2.2",
"@cornerstonejs/codec-openjpeg": "1.3.0",
"@cornerstonejs/codec-openjph": "2.4.7",
"@cornerstonejs/dicom-image-loader": "4.15.6",
"@cornerstonejs/dicom-image-loader": "4.15.7",
"@emotion/serialize": "1.3.3",
"@ohif/core": "3.12.0-beta.121",
"@ohif/extension-cornerstone": "3.12.0-beta.121",

View File

@ -37,8 +37,8 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "1.2.2",
"@cornerstonejs/codec-openjpeg": "1.3.0",
"@cornerstonejs/codec-openjph": "2.4.7",
"@cornerstonejs/core": "4.15.6",
"@cornerstonejs/dicom-image-loader": "4.15.6",
"@cornerstonejs/core": "4.15.7",
"@cornerstonejs/dicom-image-loader": "4.15.7",
"@ohif/ui": "3.12.0-beta.121",
"cornerstone-math": "0.1.9",
"dicom-parser": "1.8.21"

View File

@ -14,13 +14,13 @@ export const AddSegmentationRow: React.FC<{ children?: React.ReactNode }> = ({
disableEditing,
mode,
disabled,
segmentationRepresentationType,
segmentationRepresentationTypes,
} = useSegmentationTableContext('AddSegmentationRow');
// Check if we have at least one segmentation of the representation type for the panel this component is contained in.
const hasRepresentationType =
(!segmentationRepresentationType && data.length > 0) ||
data.some(info => segmentationRepresentationType === info.representation?.type);
(!segmentationRepresentationTypes && data.length > 0) ||
data.some(info => segmentationRepresentationTypes?.includes(info.representation?.type));
if (hasRepresentationType && mode === 'collapsed') {
return null;
@ -35,7 +35,11 @@ export const AddSegmentationRow: React.FC<{ children?: React.ReactNode }> = ({
data-cy="addSegmentation"
className={`group ${disabled ? 'pointer-events-none cursor-not-allowed opacity-70' : ''}`}
onClick={() =>
!disabled && onSegmentationAdd({ segmentationId: '', segmentationRepresentationType })
!disabled &&
onSegmentationAdd({
segmentationId: '',
segmentationRepresentationType: segmentationRepresentationTypes?.[0],
})
}
>
{children}

View File

@ -50,9 +50,8 @@ const SegmentationCollapsedDropdownMenu = ({ children }: { children: React.React
// Selector component - for the segmentation selection dropdown
const SegmentationCollapsedSelector = () => {
const { t } = useTranslation('SegmentationPanel.HeaderCollapsed');
const { data, onSegmentationClick, segmentationRepresentationType } = useSegmentationTableContext(
'SegmentationCollapsedSelector'
);
const { data, onSegmentationClick, segmentationRepresentationTypes } =
useSegmentationTableContext('SegmentationCollapsedSelector');
const { segmentation } = useSegmentationExpanded('SegmentationCollapsedSelector');
if (!data?.length) {
@ -63,8 +62,8 @@ const SegmentationCollapsedSelector = () => {
// Only show segmentations of the representation type for this panel. Show all segmentations if no type is specified.
.filter(
seg =>
!segmentationRepresentationType ||
segmentationRepresentationType === seg.representation.type
!segmentationRepresentationTypes ||
segmentationRepresentationTypes.includes(seg.representation?.type)
)
.map(seg => ({
id: seg.segmentation.segmentationId,
@ -132,14 +131,14 @@ const SegmentationCollapsedContent = ({ children }: { children: React.ReactNode
const SegmentationCollapsedRoot: React.FC<{ children?: React.ReactNode }> = ({
children = null,
}) => {
const { mode, data, segmentationRepresentationType, selectedSegmentationIdForType } =
const { mode, data, segmentationRepresentationTypes, selectedSegmentationIdForType } =
useSegmentationTableContext('SegmentationCollapsed');
// Find the segmentations for the representation type for this collapsed view.
const segmentations = data.filter(
segmentation =>
!segmentationRepresentationType ||
segmentationRepresentationType === segmentation.representation?.type
!segmentationRepresentationTypes ||
segmentationRepresentationTypes.includes(segmentation.representation?.type)
);
// Check if we should render.

View File

@ -93,7 +93,7 @@ const SegmentationExpandedContent = ({ children }: { children: React.ReactNode }
// Main compound component
const SegmentationExpandedRoot = ({ children }) => {
const { data, activeSegmentationId, onSegmentationClick, mode, segmentationRepresentationType } =
const { data, activeSegmentationId, onSegmentationClick, mode, segmentationRepresentationTypes } =
useSegmentationTableContext('SegmentationExpanded');
const { ref: scrollableContainerRef, maxHeight } = useDynamicMaxHeight(data);
@ -116,8 +116,8 @@ const SegmentationExpandedRoot = ({ children }) => {
{data
.filter(
segmentationInfo =>
!segmentationRepresentationType ||
segmentationInfo.representation.type === segmentationRepresentationType
!segmentationRepresentationTypes ||
segmentationRepresentationTypes.includes(segmentationInfo.representation.type)
)
.map(segmentationInfo => {
const isActive = segmentationInfo.segmentation.segmentationId === activeSegmentationId;

View File

@ -1,7 +1,10 @@
import React, { ReactNode, useState, Children, isValidElement } from 'react';
import { useTranslation } from 'react-i18next';
import { PanelSection } from '../PanelSection';
import { SegmentationTableProvider, SegmentationTableContextType } from './contexts';
import {
SegmentationTableProvider,
SegmentationTableContextType,
} from './contexts/SegmentationTableContext';
import { SegmentationSegments } from './SegmentationSegments';
import { SegmentStatistics } from './SegmentStatistics';
import { SegmentationTableConfig } from './SegmentationTableConfig';

View File

@ -25,7 +25,7 @@ export const SegmentationTableConfig: React.FC<{ children?: React.ReactNode }> =
setOutlineWidth,
renderInactiveSegmentations,
toggleRenderInactiveSegmentations,
segmentationRepresentationType,
segmentationRepresentationTypes,
data,
} = useSegmentationTableContext('SegmentationTableConfig');
@ -49,21 +49,22 @@ export const SegmentationTableConfig: React.FC<{ children?: React.ReactNode }> =
renderFill && renderOutline ? 'fill-and-outline' : renderOutline ? 'outline' : 'fill'
}
onValueChange={value => {
const type = segmentationRepresentationTypes?.[0];
if (value === 'fill-and-outline') {
setRenderFill({ type: segmentationRepresentationType }, true);
setRenderOutline({ type: segmentationRepresentationType }, true);
setRenderFillInactive({ type: segmentationRepresentationType }, true);
setRenderOutlineInactive({ type: segmentationRepresentationType }, true);
setRenderFill({ type }, true);
setRenderOutline({ type }, true);
setRenderFillInactive({ type }, true);
setRenderOutlineInactive({ type }, true);
} else if (value === 'outline') {
setRenderFill({ type: segmentationRepresentationType }, false);
setRenderOutline({ type: segmentationRepresentationType }, true);
setRenderFillInactive({ type: segmentationRepresentationType }, false);
setRenderOutlineInactive({ type: segmentationRepresentationType }, true);
setRenderFill({ type }, false);
setRenderOutline({ type }, true);
setRenderFillInactive({ type }, false);
setRenderOutlineInactive({ type }, true);
} else {
setRenderFill({ type: segmentationRepresentationType }, true);
setRenderOutline({ type: segmentationRepresentationType }, false);
setRenderFillInactive({ type: segmentationRepresentationType }, true);
setRenderOutlineInactive({ type: segmentationRepresentationType }, false);
setRenderFill({ type }, true);
setRenderOutline({ type }, false);
setRenderFillInactive({ type }, true);
setRenderOutlineInactive({ type }, false);
}
}}
>
@ -90,7 +91,7 @@ export const SegmentationTableConfig: React.FC<{ children?: React.ReactNode }> =
className="mx-1 flex-1"
value={[fillAlpha]}
onValueChange={([value]) =>
setFillAlpha({ type: segmentationRepresentationType }, value)
setFillAlpha({ type: segmentationRepresentationTypes?.[0] }, value)
}
max={1}
min={0}
@ -100,7 +101,7 @@ export const SegmentationTableConfig: React.FC<{ children?: React.ReactNode }> =
className="mx-1 w-10 flex-none"
value={fillAlpha}
onChange={e =>
setFillAlpha({ type: segmentationRepresentationType }, Number(e.target.value))
setFillAlpha({ type: segmentationRepresentationTypes?.[0] }, Number(e.target.value))
}
/>
</div>
@ -112,7 +113,7 @@ export const SegmentationTableConfig: React.FC<{ children?: React.ReactNode }> =
<Slider
value={[outlineWidth]}
onValueChange={([value]) =>
setOutlineWidth({ type: segmentationRepresentationType }, value)
setOutlineWidth({ type: segmentationRepresentationTypes?.[0] }, value)
}
max={10}
min={0}
@ -122,7 +123,10 @@ export const SegmentationTableConfig: React.FC<{ children?: React.ReactNode }> =
<Input
value={outlineWidth}
onChange={e =>
setOutlineWidth({ type: segmentationRepresentationType }, Number(e.target.value))
setOutlineWidth(
{ type: segmentationRepresentationTypes?.[0] },
Number(e.target.value)
)
}
className="mx-1 w-10 flex-none text-center"
/>

View File

@ -65,11 +65,12 @@ export interface SegmentationTableContextType {
showSegmentIndex?: boolean;
renderInactiveSegmentations?: boolean;
// The type segmentations displayed/filtered in this table. If undefined, show all types.
segmentationRepresentationType?: string;
// The types of segmentations displayed/filtered in this table. If undefined, show all types.
// The first element is the primary type. Additional elements are secondary types.
segmentationRepresentationTypes?: string[];
// The (last) selected segmentation ID for the representation type above.
// If the type above is undefined, then it will store the last active segmentation ID.
// The (last) selected segmentation ID for the representation types above.
// If the representation types above is undefined, then it will store the last active segmentation ID.
selectedSegmentationIdForType?: string;
// Function handlers

View File

@ -21,9 +21,7 @@ test('should hydrate RT reports correctly', async ({
await page.waitForTimeout(5000);
await checkForScreenshot(page, page, screenShotPaths.rtHydration.rtPostHydration);
await rightPanelPageObject.labelMapSegmentationPanel.panel
.segmentationByText('Small Sphere')
.click();
await rightPanelPageObject.labelMapSegmentationPanel.panel.segmentByText('Small Sphere').click();
await page.waitForTimeout(5000);
await checkForScreenshot(page, page, screenShotPaths.rtHydration.rtJumpToStructure);
});

View File

@ -0,0 +1,29 @@
import { expect, test, visitStudy } from './utils';
test.beforeEach(
async ({
page,
rightPanelPageObject,
leftPanelPageObject,
DOMOverlayPageObject,
mainToolbarPageObject,
}) => {
const studyInstanceUID = '1.3.6.1.4.1.14519.5.2.1.256467663913010332776401703474716742458';
const mode = 'viewer';
await visitStudy(page, studyInstanceUID, mode, 2000);
await rightPanelPageObject.toggle();
await leftPanelPageObject.loadSeriesByDescription('SEG');
await DOMOverlayPageObject.viewport.segmentationHydration.yes.click();
await page.waitForTimeout(5000);
await mainToolbarPageObject.layoutSelection.threeDOnly.click();
await page.waitForTimeout(5000);
}
);
test('should list segments in side panel for 3D only view', async ({ rightPanelPageObject }) => {
const numberOfSegments =
await rightPanelPageObject.labelMapSegmentationPanel.panel.getSegmentCount();
expect(numberOfSegments, 'The side panel should list 13 segments for the 3D only view.').toBe(13);
});

View File

@ -19,8 +19,8 @@ test('checks basic add, rename, delete segments from panel', async ({ rightPanel
await rightPanelPageObject.labelMapSegmentationPanel.addSegmentationButton.click();
// Expect new segmentation and blank segment named "Segment 1"
const segment1 = rightPanelPageObject.labelMapSegmentationPanel.panel.nthSegmentation(0);
expect(await rightPanelPageObject.labelMapSegmentationPanel.panel.getSegmentationCount()).toBe(1);
const segment1 = rightPanelPageObject.labelMapSegmentationPanel.panel.nthSegment(0);
expect(await rightPanelPageObject.labelMapSegmentationPanel.panel.getSegmentCount()).toBe(1);
await expect(segment1.locator).toContainText('Segment 1');
// Rename
@ -32,7 +32,7 @@ test('checks basic add, rename, delete segments from panel', async ({ rightPanel
// Delete
await segment1.actions.delete();
expect(await rightPanelPageObject.labelMapSegmentationPanel.panel.getSegmentationCount()).toBe(0);
expect(await rightPanelPageObject.labelMapSegmentationPanel.panel.getSegmentCount()).toBe(0);
});
test('checks saved segmentations loads and jumps to slices', async ({
@ -62,19 +62,17 @@ test('checks saved segmentations loads and jumps to slices', async ({
// Confirm spleen jumps to slice 17
// First iteration repeat to account for segmentation loading delays
await expect(async () => {
await rightPanelPageObject.labelMapSegmentationPanel.panel.segmentationByText('Spleen').click();
await rightPanelPageObject.labelMapSegmentationPanel.panel.segmentByText('Spleen').click();
await expect(viewportInfoBottomRight).toContainText('17/');
}).toPass({
timeout: 10000,
});
// Esophagus - 5
await rightPanelPageObject.labelMapSegmentationPanel.panel
.segmentationByText('Esophagus')
.click();
await rightPanelPageObject.labelMapSegmentationPanel.panel.segmentByText('Esophagus').click();
await expect(viewportInfoBottomRight).toContainText('5/');
// Pancreas - 22
await rightPanelPageObject.labelMapSegmentationPanel.panel.segmentationByText('Pancreas').click();
await rightPanelPageObject.labelMapSegmentationPanel.panel.segmentByText('Pancreas').click();
await expect(viewportInfoBottomRight).toContainText('22/');
});

View File

@ -111,20 +111,20 @@ export class RightPanelPageObject {
private get segmentationPanel() {
const page = this.page;
const getSegmentationByIdx = (index: number) => this.getPanelRowByIdx(index);
const getSegmentationByText = (text: string) => this.getPanelRowByText(text);
const getSegmentByIdx = (index: number) => this.getPanelRowByIdx(index);
const getSegmentByText = (text: string) => this.getPanelRowByText(text);
return {
getSegmentationCount: async () => {
getSegmentCount: async () => {
return await page.getByTestId('data-row').count();
},
// No data-cy exists in this panel, using Segmentation header button
locator: page.getByRole('button', { name: 'Segmentations' }),
nthSegmentation(index: number) {
return getSegmentationByIdx(index);
nthSegment(index: number) {
return getSegmentByIdx(index);
},
segmentationByText(text: string) {
return getSegmentationByText(text);
segmentByText(text: string) {
return getSegmentByText(text);
},
};
}

View File

@ -1278,10 +1278,10 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@cornerstonejs/adapters@4.15.6":
version "4.15.6"
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-4.15.6.tgz#864195f7af7fbfacebcb8726f80b6b474e1f7950"
integrity sha512-pl4yKwkJRc9CxYMIKs4XGsXPWeLbrpfFRJmUDE/S8oNhZgqNQ1KsL6I0epN5aU9Igo9kpzNTpFVwIhWScbbZTQ==
"@cornerstonejs/adapters@4.15.7":
version "4.15.7"
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-4.15.7.tgz#de47e915f402e8e731da746c959621dbc85834f8"
integrity sha512-3ScwvPoa4v0mIQ52+Ua9dgPhsShH+sHo5hHRWICRPZ9vl99vMWLXK2vfSPc1U2iFLDP553JoT7g3D6V2DaUPWQ==
dependencies:
"@babel/runtime-corejs2" "7.26.10"
buffer "6.0.3"
@ -1289,10 +1289,10 @@
gl-matrix "3.4.3"
ndarray "1.0.19"
"@cornerstonejs/ai@4.15.6":
version "4.15.6"
resolved "https://registry.yarnpkg.com/@cornerstonejs/ai/-/ai-4.15.6.tgz#60d9bfb531364da98b4d813d5124ee089db796c1"
integrity sha512-aqsZrO/nDWP8g9PrDantWm4+7IWwbTuqRstxVyGQ6oH+mZYIkcq4IHrISEnnEMrZMQ8GAcz3+ORV3EieO00Ovg==
"@cornerstonejs/ai@4.15.7":
version "4.15.7"
resolved "https://registry.yarnpkg.com/@cornerstonejs/ai/-/ai-4.15.7.tgz#fe1922335534575c1561ef865b335876c90d95bc"
integrity sha512-A7Sr+2Kv3uFfw2/nWf/Qi1l1fB/6J54uM3p9OnOB/F6G9pFaGkdRJtUBm133TfRPo0xL7nCT79x5cAw006josw==
dependencies:
"@babel/runtime-corejs2" "7.26.10"
buffer "6.0.3"
@ -1328,20 +1328,20 @@
resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.7.tgz#784394d05d8cf735640e9c3baa206535ee8e0376"
integrity sha512-qvP4q4JDib7mi9r7LqKOwqz7YZ8gjtDX4ZCezeYf8+eb7MBXCz5uXAMeVF3yz9Axw4XiIMdB/pqXkm8tqCl13w==
"@cornerstonejs/core@4.15.6":
version "4.15.6"
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-4.15.6.tgz#1e25a219b469c96f6c5f8fce03dfb9d0ff4d6f98"
integrity sha512-7faicjRwUSeVhSRpM1MaLiEdH8daxnQm0BZl7HAnhrbS1zTHSrzKVxtj9zVJJ2SP3QCzBZmMfFan8MgWo61L0A==
"@cornerstonejs/core@4.15.7":
version "4.15.7"
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-4.15.7.tgz#edfd1250d6dc8b20a315e42ca9308274f5df8194"
integrity sha512-uPdNSbGz7TtFQdNHpSx8ilC0NJngfaOGJsuZMcHFvtjvMRuXhOyzuxJ/RhbgmDjWE1Jig65zI6Wd7prnKo9uKA==
dependencies:
"@kitware/vtk.js" "34.15.1"
comlink "4.4.2"
gl-matrix "3.4.3"
loglevel "1.9.2"
"@cornerstonejs/dicom-image-loader@4.15.6":
version "4.15.6"
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-4.15.6.tgz#0e7853dd5e5d9762f7b7776d461493f3cce2a2e4"
integrity sha512-VYNMYIcK9EaUYO7pYpr0AiEyTUZqXHJWSGak77MbpjYJ8PWeHgNaQzPHp0gvcaQUT1uwIfU1Wo/rVlu0cALLpA==
"@cornerstonejs/dicom-image-loader@4.15.7":
version "4.15.7"
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-4.15.7.tgz#693059404b0f0d1b98c9035514f4e1eda3c85449"
integrity sha512-U00F2XiQRARAKIxQCnhIOZBEZwVfV0AiU02iZ49Chw7VsBm/6zt+zJMVh6veGNd8PHrIJKKuXONYLa5OB08ffg==
dependencies:
"@cornerstonejs/codec-charls" "1.2.3"
"@cornerstonejs/codec-libjpeg-turbo-8bit" "1.2.2"
@ -1353,25 +1353,25 @@
pako "2.1.0"
uuid "9.0.1"
"@cornerstonejs/labelmap-interpolation@4.15.6":
version "4.15.6"
resolved "https://registry.yarnpkg.com/@cornerstonejs/labelmap-interpolation/-/labelmap-interpolation-4.15.6.tgz#4973ea030ef551104cc5ab5a2c7e1d4916a164ee"
integrity sha512-GtklMlxmlaG1XrzaYrTnFrosWoLEPbZwlMc/kbrdrMZAYe8hXvGrkoIYPM0GnBrfQYL1Pjfqi+VhiSyCFX+ehQ==
"@cornerstonejs/labelmap-interpolation@4.15.7":
version "4.15.7"
resolved "https://registry.yarnpkg.com/@cornerstonejs/labelmap-interpolation/-/labelmap-interpolation-4.15.7.tgz#2257a3f0716eca5b1a85a1c0bb2ef3b22a9c7515"
integrity sha512-4rZr+Jt5tw2jYAP9Pku2QCVq3hZH/+8O4YdsGtdlLLz+z6YNyWG9qSzQHIzDqbpbZRRlOdmxd2vDOBvr+I3axg==
dependencies:
"@itk-wasm/morphological-contour-interpolation" "1.1.0"
itk-wasm "1.0.0-b.165"
"@cornerstonejs/polymorphic-segmentation@4.15.6":
version "4.15.6"
resolved "https://registry.yarnpkg.com/@cornerstonejs/polymorphic-segmentation/-/polymorphic-segmentation-4.15.6.tgz#91066e4172df954585f2c3a236af364480d07caa"
integrity sha512-t+OqolPp1DhlOVMtS6D088d3iQGOAjS4O5Sw8gOCZ4C/pg+jHmNJpkrGlFw8qUhnJ1D9JU3+dTJdLL8Xwq9HNg==
"@cornerstonejs/polymorphic-segmentation@4.15.7":
version "4.15.7"
resolved "https://registry.yarnpkg.com/@cornerstonejs/polymorphic-segmentation/-/polymorphic-segmentation-4.15.7.tgz#8fa43d32dcf07fa86dff395553e5ac84b4b3ed57"
integrity sha512-N+YpP2qwdVhPyKd3kcmXQhTZfj+C/Xo+Bko9Jg9FCIk03OkTK3FUndDxWlLoGraIWhME9GfMz1aocKvCyUnDgg==
dependencies:
"@icr/polyseg-wasm" "0.4.0"
"@cornerstonejs/tools@4.15.6":
version "4.15.6"
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-4.15.6.tgz#ec2af21acf95d3900f5624808f891e1072d7b6e0"
integrity sha512-MPZwkMkZqJVdGXiKqsO4T7jiR9m0KFNfp5DV/KdyUchrz7TPBfbO2r2aBxowo3ARutlJuQWDgPv9hcLRueLhIw==
"@cornerstonejs/tools@4.15.7":
version "4.15.7"
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-4.15.7.tgz#0f7e816e1896de3c804a9d6e8852a2ae20bd9c83"
integrity sha512-LHroV6ZrQ/aGkpyoVHSx+qAPSol30jlSpwUIvguirnmFW4VwUgAaWeLmKpyy78EgqukzEDCFPXtGiD+TPIITKw==
dependencies:
"@types/offscreencanvas" "2019.7.3"
comlink "4.4.2"