feat(image capture): Enhance SEG and RTSS Support with Dependency Updates and Bug Fixes (#4924)

This commit is contained in:
Alireza 2025-04-04 12:11:29 -04:00 committed by GitHub
parent 479e280fdf
commit fc33bd0d59
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
57 changed files with 1247 additions and 935 deletions

276
bun.lock
View File

@ -33,7 +33,7 @@
}, },
"addOns/externals/devDependencies": { "addOns/externals/devDependencies": {
"name": "@externals/devDependencies", "name": "@externals/devDependencies",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@kitware/vtk.js": "32.12.0", "@kitware/vtk.js": "32.12.0",
@ -121,22 +121,22 @@
}, },
"addOns/externals/dicom-microscopy-viewer": { "addOns/externals/dicom-microscopy-viewer": {
"name": "@externals/dicom-microscopy-viewer", "name": "@externals/dicom-microscopy-viewer",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"dicom-microscopy-viewer": "^0.46.1", "dicom-microscopy-viewer": "^0.46.1",
}, },
}, },
"extensions/cornerstone": { "extensions/cornerstone": {
"name": "@ohif/extension-cornerstone", "name": "@ohif/extension-cornerstone",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^3.8.4", "@cornerstonejs/adapters": "^3.8.5",
"@cornerstonejs/ai": "^3.8.4", "@cornerstonejs/ai": "^3.8.5",
"@cornerstonejs/core": "^3.8.4", "@cornerstonejs/core": "^3.8.5",
"@cornerstonejs/labelmap-interpolation": "^3.8.4", "@cornerstonejs/labelmap-interpolation": "^3.8.5",
"@cornerstonejs/polymorphic-segmentation": "^3.8.4", "@cornerstonejs/polymorphic-segmentation": "^3.8.5",
"@cornerstonejs/tools": "^3.8.4", "@cornerstonejs/tools": "^3.8.5",
"@itk-wasm/morphological-contour-interpolation": "1.1.0", "@itk-wasm/morphological-contour-interpolation": "1.1.0",
"@kitware/vtk.js": "32.12.0", "@kitware/vtk.js": "32.12.0",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
@ -153,9 +153,9 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjpeg": "^1.2.4",
"@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^3.8.4", "@cornerstonejs/dicom-image-loader": "^3.8.5",
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/ui": "3.10.0-beta.144", "@ohif/ui": "3.10.0-beta.147",
"dcmjs": "*", "dcmjs": "*",
"dicom-parser": "^1.8.21", "dicom-parser": "^1.8.21",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -167,19 +167,19 @@
}, },
"extensions/cornerstone-dicom-pmap": { "extensions/cornerstone-dicom-pmap": {
"name": "@ohif/extension-cornerstone-dicom-pmap", "name": "@ohif/extension-cornerstone-dicom-pmap",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^3.8.4", "@cornerstonejs/adapters": "^3.8.5",
"@cornerstonejs/core": "^3.8.4", "@cornerstonejs/core": "^3.8.5",
"@kitware/vtk.js": "32.12.0", "@kitware/vtk.js": "32.12.0",
"react-color": "^2.19.3", "react-color": "^2.19.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/extension-cornerstone": "3.10.0-beta.144", "@ohif/extension-cornerstone": "3.10.0-beta.147",
"@ohif/extension-default": "3.10.0-beta.144", "@ohif/extension-default": "3.10.0-beta.147",
"@ohif/i18n": "3.10.0-beta.144", "@ohif/i18n": "3.10.0-beta.147",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
@ -190,16 +190,16 @@
}, },
"extensions/cornerstone-dicom-rt": { "extensions/cornerstone-dicom-rt": {
"name": "@ohif/extension-cornerstone-dicom-rt", "name": "@ohif/extension-cornerstone-dicom-rt",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"react-color": "^2.19.3", "react-color": "^2.19.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/extension-cornerstone": "3.10.0-beta.144", "@ohif/extension-cornerstone": "3.10.0-beta.147",
"@ohif/extension-default": "3.10.0-beta.144", "@ohif/extension-default": "3.10.0-beta.147",
"@ohif/i18n": "3.10.0-beta.144", "@ohif/i18n": "3.10.0-beta.147",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
@ -210,19 +210,19 @@
}, },
"extensions/cornerstone-dicom-seg": { "extensions/cornerstone-dicom-seg": {
"name": "@ohif/extension-cornerstone-dicom-seg", "name": "@ohif/extension-cornerstone-dicom-seg",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^3.8.4", "@cornerstonejs/adapters": "^3.8.5",
"@cornerstonejs/core": "^3.8.4", "@cornerstonejs/core": "^3.8.5",
"@kitware/vtk.js": "32.12.0", "@kitware/vtk.js": "32.12.0",
"react-color": "^2.19.3", "react-color": "^2.19.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/extension-cornerstone": "3.10.0-beta.144", "@ohif/extension-cornerstone": "3.10.0-beta.147",
"@ohif/extension-default": "3.10.0-beta.144", "@ohif/extension-default": "3.10.0-beta.147",
"@ohif/i18n": "3.10.0-beta.144", "@ohif/i18n": "3.10.0-beta.147",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
@ -233,19 +233,19 @@
}, },
"extensions/cornerstone-dicom-sr": { "extensions/cornerstone-dicom-sr": {
"name": "@ohif/extension-cornerstone-dicom-sr", "name": "@ohif/extension-cornerstone-dicom-sr",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^3.8.4", "@cornerstonejs/adapters": "^3.8.5",
"@cornerstonejs/core": "^3.8.4", "@cornerstonejs/core": "^3.8.5",
"@cornerstonejs/tools": "^3.8.4", "@cornerstonejs/tools": "^3.8.5",
"classnames": "^2.3.2", "classnames": "^2.3.2",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/extension-cornerstone": "3.10.0-beta.144", "@ohif/extension-cornerstone": "3.10.0-beta.147",
"@ohif/extension-measurement-tracking": "3.10.0-beta.144", "@ohif/extension-measurement-tracking": "3.10.0-beta.147",
"@ohif/ui": "3.10.0-beta.144", "@ohif/ui": "3.10.0-beta.147",
"dcmjs": "*", "dcmjs": "*",
"dicom-parser": "^1.8.9", "dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -255,19 +255,19 @@
}, },
"extensions/cornerstone-dynamic-volume": { "extensions/cornerstone-dynamic-volume": {
"name": "@ohif/extension-cornerstone-dynamic-volume", "name": "@ohif/extension-cornerstone-dynamic-volume",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/core": "^3.8.4", "@cornerstonejs/core": "^3.8.5",
"@cornerstonejs/tools": "^3.8.4", "@cornerstonejs/tools": "^3.8.5",
"classnames": "^2.3.2", "classnames": "^2.3.2",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/extension-cornerstone": "3.10.0-beta.144", "@ohif/extension-cornerstone": "3.10.0-beta.147",
"@ohif/extension-default": "3.10.0-beta.144", "@ohif/extension-default": "3.10.0-beta.147",
"@ohif/i18n": "3.10.0-beta.144", "@ohif/i18n": "3.10.0-beta.147",
"@ohif/ui": "3.10.0-beta.144", "@ohif/ui": "3.10.0-beta.147",
"dcmjs": "*", "dcmjs": "*",
"dicom-parser": "^1.8.21", "dicom-parser": "^1.8.21",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -277,7 +277,7 @@
}, },
"extensions/default": { "extensions/default": {
"name": "@ohif/extension-default", "name": "@ohif/extension-default",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/calculate-suv": "^1.1.0", "@cornerstonejs/calculate-suv": "^1.1.0",
@ -285,8 +285,8 @@
"lodash.uniqby": "^4.7.0", "lodash.uniqby": "^4.7.0",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/i18n": "3.10.0-beta.144", "@ohif/i18n": "3.10.0-beta.147",
"dcmjs": "*", "dcmjs": "*",
"dicomweb-client": "^0.10.4", "dicomweb-client": "^0.10.4",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
@ -300,7 +300,7 @@
}, },
"extensions/dicom-microscopy": { "extensions/dicom-microscopy": {
"name": "@ohif/extension-dicom-microscopy", "name": "@ohif/extension-dicom-microscopy",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/codec-charls": "^1.2.3", "@cornerstonejs/codec-charls": "^1.2.3",
@ -311,10 +311,10 @@
"mathjs": "^12.4.2", "mathjs": "^12.4.2",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/extension-default": "3.10.0-beta.144", "@ohif/extension-default": "3.10.0-beta.147",
"@ohif/i18n": "3.10.0-beta.144", "@ohif/i18n": "3.10.0-beta.147",
"@ohif/ui": "3.10.0-beta.144", "@ohif/ui": "3.10.0-beta.147",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
@ -325,14 +325,14 @@
}, },
"extensions/dicom-pdf": { "extensions/dicom-pdf": {
"name": "@ohif/extension-dicom-pdf", "name": "@ohif/extension-dicom-pdf",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"classnames": "^2.3.2", "classnames": "^2.3.2",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/ui": "3.10.0-beta.144", "@ohif/ui": "3.10.0-beta.147",
"dcmjs": "*", "dcmjs": "*",
"dicom-parser": "^1.8.9", "dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -342,14 +342,14 @@
}, },
"extensions/dicom-video": { "extensions/dicom-video": {
"name": "@ohif/extension-dicom-video", "name": "@ohif/extension-dicom-video",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"classnames": "^2.3.2", "classnames": "^2.3.2",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/ui": "3.10.0-beta.144", "@ohif/ui": "3.10.0-beta.147",
"dcmjs": "*", "dcmjs": "*",
"dicom-parser": "^1.8.9", "dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -359,20 +359,20 @@
}, },
"extensions/measurement-tracking": { "extensions/measurement-tracking": {
"name": "@ohif/extension-measurement-tracking", "name": "@ohif/extension-measurement-tracking",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@ohif/ui": "3.10.0-beta.144", "@ohif/ui": "3.10.0-beta.147",
"@xstate/react": "^3.2.2", "@xstate/react": "^3.2.2",
"xstate": "^4.10.0", "xstate": "^4.10.0",
}, },
"peerDependencies": { "peerDependencies": {
"@cornerstonejs/core": "^3.8.4", "@cornerstonejs/core": "^3.8.5",
"@cornerstonejs/tools": "^3.8.4", "@cornerstonejs/tools": "^3.8.5",
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.144", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.147",
"@ohif/extension-default": "3.10.0-beta.144", "@ohif/extension-default": "3.10.0-beta.147",
"@ohif/ui": "3.10.0-beta.144", "@ohif/ui": "3.10.0-beta.147",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"dcmjs": "*", "dcmjs": "*",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
@ -385,14 +385,14 @@
}, },
"extensions/test-extension": { "extensions/test-extension": {
"name": "@ohif/extension-test", "name": "@ohif/extension-test",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"classnames": "^2.3.2", "classnames": "^2.3.2",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/ui": "3.10.0-beta.144", "@ohif/ui": "3.10.0-beta.147",
"dcmjs": "0.38.0", "dcmjs": "0.38.0",
"dicom-parser": "^1.8.9", "dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -402,7 +402,7 @@
}, },
"extensions/tmtv": { "extensions/tmtv": {
"name": "@ohif/extension-tmtv", "name": "@ohif/extension-tmtv",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"classnames": "^2.3.2", "classnames": "^2.3.2",
@ -419,7 +419,7 @@
}, },
"modes/basic-dev-mode": { "modes/basic-dev-mode": {
"name": "@ohif/mode-basic-dev-mode", "name": "@ohif/mode-basic-dev-mode",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"i18next": "^17.0.3", "i18next": "^17.0.3",
@ -429,17 +429,17 @@
"webpack-merge": "^5.7.3", "webpack-merge": "^5.7.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/extension-cornerstone": "3.10.0-beta.144", "@ohif/extension-cornerstone": "3.10.0-beta.147",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.144", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.147",
"@ohif/extension-default": "3.10.0-beta.144", "@ohif/extension-default": "3.10.0-beta.147",
"@ohif/extension-dicom-pdf": "3.10.0-beta.144", "@ohif/extension-dicom-pdf": "3.10.0-beta.147",
"@ohif/extension-dicom-video": "3.10.0-beta.144", "@ohif/extension-dicom-video": "3.10.0-beta.147",
}, },
}, },
"modes/basic-test-mode": { "modes/basic-test-mode": {
"name": "@ohif/mode-test", "name": "@ohif/mode-test",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"i18next": "^17.0.3", "i18next": "^17.0.3",
@ -449,19 +449,19 @@
"webpack-merge": "^5.7.3", "webpack-merge": "^5.7.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/extension-cornerstone": "3.10.0-beta.144", "@ohif/extension-cornerstone": "3.10.0-beta.147",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.144", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.147",
"@ohif/extension-default": "3.10.0-beta.144", "@ohif/extension-default": "3.10.0-beta.147",
"@ohif/extension-dicom-pdf": "3.10.0-beta.144", "@ohif/extension-dicom-pdf": "3.10.0-beta.147",
"@ohif/extension-dicom-video": "3.10.0-beta.144", "@ohif/extension-dicom-video": "3.10.0-beta.147",
"@ohif/extension-measurement-tracking": "3.10.0-beta.144", "@ohif/extension-measurement-tracking": "3.10.0-beta.147",
"@ohif/extension-test": "3.10.0-beta.144", "@ohif/extension-test": "3.10.0-beta.147",
}, },
}, },
"modes/longitudinal": { "modes/longitudinal": {
"name": "@ohif/mode-longitudinal", "name": "@ohif/mode-longitudinal",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"i18next": "^17.0.3", "i18next": "^17.0.3",
@ -471,32 +471,32 @@
"webpack-merge": "^5.7.3", "webpack-merge": "^5.7.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/extension-cornerstone": "3.10.0-beta.144", "@ohif/extension-cornerstone": "3.10.0-beta.147",
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.144", "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.147",
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.144", "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.147",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.144", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.147",
"@ohif/extension-default": "3.10.0-beta.144", "@ohif/extension-default": "3.10.0-beta.147",
"@ohif/extension-dicom-pdf": "3.10.0-beta.144", "@ohif/extension-dicom-pdf": "3.10.0-beta.147",
"@ohif/extension-dicom-video": "3.10.0-beta.144", "@ohif/extension-dicom-video": "3.10.0-beta.147",
"@ohif/extension-measurement-tracking": "3.10.0-beta.144", "@ohif/extension-measurement-tracking": "3.10.0-beta.147",
}, },
}, },
"modes/microscopy": { "modes/microscopy": {
"name": "@ohif/mode-microscopy", "name": "@ohif/mode-microscopy",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"i18next": "^17.0.3", "i18next": "^17.0.3",
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/extension-dicom-microscopy": "3.10.0-beta.144", "@ohif/extension-dicom-microscopy": "3.10.0-beta.147",
}, },
}, },
"modes/preclinical-4d": { "modes/preclinical-4d": {
"name": "@ohif/mode-preclinical-4d", "name": "@ohif/mode-preclinical-4d",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
}, },
@ -515,7 +515,7 @@
}, },
"modes/segmentation": { "modes/segmentation": {
"name": "@ohif/mode-segmentation", "name": "@ohif/mode-segmentation",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"i18next": "^17.0.3", "i18next": "^17.0.3",
@ -559,7 +559,7 @@
}, },
"modes/tmtv": { "modes/tmtv": {
"name": "@ohif/mode-tmtv", "name": "@ohif/mode-tmtv",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"i18next": "^17.0.3", "i18next": "^17.0.3",
@ -580,32 +580,32 @@
}, },
"platform/app": { "platform/app": {
"name": "@ohif/app", "name": "@ohif/app",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/codec-charls": "^1.2.3", "@cornerstonejs/codec-charls": "^1.2.3",
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjpeg": "^1.2.4",
"@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^3.8.4", "@cornerstonejs/dicom-image-loader": "^3.8.5",
"@emotion/serialize": "^1.1.3", "@emotion/serialize": "^1.1.3",
"@ohif/core": "3.10.0-beta.144", "@ohif/core": "3.10.0-beta.147",
"@ohif/extension-cornerstone": "3.10.0-beta.144", "@ohif/extension-cornerstone": "3.10.0-beta.147",
"@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.144", "@ohif/extension-cornerstone-dicom-rt": "3.10.0-beta.147",
"@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.144", "@ohif/extension-cornerstone-dicom-seg": "3.10.0-beta.147",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.144", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.147",
"@ohif/extension-default": "3.10.0-beta.144", "@ohif/extension-default": "3.10.0-beta.147",
"@ohif/extension-dicom-microscopy": "3.10.0-beta.144", "@ohif/extension-dicom-microscopy": "3.10.0-beta.147",
"@ohif/extension-dicom-pdf": "3.10.0-beta.144", "@ohif/extension-dicom-pdf": "3.10.0-beta.147",
"@ohif/extension-dicom-video": "3.10.0-beta.144", "@ohif/extension-dicom-video": "3.10.0-beta.147",
"@ohif/extension-test": "3.10.0-beta.144", "@ohif/extension-test": "3.10.0-beta.147",
"@ohif/i18n": "3.10.0-beta.144", "@ohif/i18n": "3.10.0-beta.147",
"@ohif/mode-basic-dev-mode": "3.10.0-beta.144", "@ohif/mode-basic-dev-mode": "3.10.0-beta.147",
"@ohif/mode-longitudinal": "3.10.0-beta.144", "@ohif/mode-longitudinal": "3.10.0-beta.147",
"@ohif/mode-microscopy": "3.10.0-beta.144", "@ohif/mode-microscopy": "3.10.0-beta.147",
"@ohif/mode-test": "3.10.0-beta.144", "@ohif/mode-test": "3.10.0-beta.147",
"@ohif/ui": "3.10.0-beta.144", "@ohif/ui": "3.10.0-beta.147",
"@ohif/ui-next": "3.10.0-beta.144", "@ohif/ui-next": "3.10.0-beta.147",
"@svgr/webpack": "^8.1.0", "@svgr/webpack": "^8.1.0",
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"classnames": "^2.3.2", "classnames": "^2.3.2",
@ -646,7 +646,7 @@
}, },
"platform/cli": { "platform/cli": {
"name": "@ohif/cli", "name": "@ohif/cli",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"bin": { "bin": {
"ohif-cli": "src/index.js", "ohif-cli": "src/index.js",
}, },
@ -670,7 +670,7 @@
}, },
"platform/core": { "platform/core": {
"name": "@ohif/core", "name": "@ohif/core",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"dcmjs": "*", "dcmjs": "*",
@ -695,15 +695,15 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjpeg": "^1.2.4",
"@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^3.8.4", "@cornerstonejs/dicom-image-loader": "^3.8.5",
"@ohif/ui": "3.10.0-beta.144", "@ohif/ui": "3.10.0-beta.147",
"cornerstone-math": "0.1.9", "cornerstone-math": "0.1.9",
"dicom-parser": "^1.8.21", "dicom-parser": "^1.8.21",
}, },
}, },
"platform/i18n": { "platform/i18n": {
"name": "@ohif/i18n", "name": "@ohif/i18n",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"i18next-locize-backend": "^2.0.0", "i18next-locize-backend": "^2.0.0",
@ -728,7 +728,7 @@
}, },
"platform/ui": { "platform/ui": {
"name": "@ohif/ui", "name": "@ohif/ui",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@testing-library/react": "^13.1.0", "@testing-library/react": "^13.1.0",
"browser-detect": "^0.2.28", "browser-detect": "^0.2.28",
@ -788,7 +788,7 @@
}, },
"platform/ui-next": { "platform/ui-next": {
"name": "@ohif/ui-next", "name": "@ohif/ui-next",
"version": "3.10.0-beta.144", "version": "3.10.0-beta.147",
"dependencies": { "dependencies": {
"@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-accordion": "^1.2.0",
"@radix-ui/react-checkbox": "^1.1.1", "@radix-ui/react-checkbox": "^1.1.1",
@ -1099,9 +1099,9 @@
"@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="],
"@cornerstonejs/adapters": ["@cornerstonejs/adapters@3.8.4", "", { "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.4", "@cornerstonejs/tools": "^3.8.4" } }, "sha512-TFTvNZQBW54rEcyjDfyHZYYvIPHVGZoUCtjW3isHfpoXkjHz2cliwC55e0kcNJ0zbyI6H41c4VsYH8h2MTYOdA=="], "@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/ai": ["@cornerstonejs/ai@3.8.4", "", { "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.4", "@cornerstonejs/tools": "^3.8.4" } }, "sha512-scc2srdL1BqNTSFEro4y7UlNBsPtBVSF31eT4SC1psxZQcr/iyaCKuOQg/hglk1yobFkdIKvjRAvvqvYmGduQw=="], "@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/calculate-suv": ["@cornerstonejs/calculate-suv@1.1.0", "", {}, "sha512-Q9XraiDJif9aMFArD2iEuDO/HXbcRVCqB7KfaHgDrdTTjgDFovS91Psbdim7crypRSvE6dh/+HKeFNHdvNkA6w=="], "@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/codec-openjph": ["@cornerstonejs/codec-openjph@2.4.7", "", {}, "sha512-qvP4q4JDib7mi9r7LqKOwqz7YZ8gjtDX4ZCezeYf8+eb7MBXCz5uXAMeVF3yz9Axw4XiIMdB/pqXkm8tqCl13w=="],
"@cornerstonejs/core": ["@cornerstonejs/core@3.8.4", "", { "dependencies": { "@kitware/vtk.js": "32.12.1", "comlink": "^4.4.1", "gl-matrix": "^3.4.3", "loglevel": "^1.9.2" } }, "sha512-8spQvERZRn4I/0EhzTNZ5ruPBrVn5F4msb/q0ttBtiVEa9JaVwoWh3yEcO4q5NpK7t1BhpfSPMKwU98Dy02ugQ=="], "@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/dicom-image-loader": ["@cornerstonejs/dicom-image-loader@3.8.4", "", { "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.4" } }, "sha512-N2D4U8JDhen+dCY1HrLOoK8W3CD2AAf/Cd+GiJMEGjtrihIuQ+Ha+hZTVQzaDMc7v2Ruvx2DpJ7i9HUJXoyWHw=="], "@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/labelmap-interpolation": ["@cornerstonejs/labelmap-interpolation@3.8.4", "", { "dependencies": { "@itk-wasm/morphological-contour-interpolation": "1.1.0", "itk-wasm": "1.0.0-b.165" }, "peerDependencies": { "@cornerstonejs/core": "^3.8.4", "@cornerstonejs/tools": "^3.8.4", "@kitware/vtk.js": "32.12.1" } }, "sha512-KKDTeVJg1s0trplkaHglBm0foQ3XL9BhsTfatFCTzgIOCT0wolrKbr+xAKIeZuBQifiFazDWpYaeBHRbkWEEMA=="], "@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/polymorphic-segmentation": ["@cornerstonejs/polymorphic-segmentation@3.8.4", "", { "dependencies": { "@icr/polyseg-wasm": "0.4.0" }, "peerDependencies": { "@cornerstonejs/core": "^3.8.4", "@cornerstonejs/tools": "^3.8.4", "@kitware/vtk.js": "32.12.1" } }, "sha512-+3o280NOniUkG9GcWTeTi6x3qy8Rm7WpYFycWpxXIufJzVudJi0zAR+EIWDq/uvTQ3DH1SrBDe4wzYNqD+yirw=="], "@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/tools": ["@cornerstonejs/tools@3.8.4", "", { "dependencies": { "@types/offscreencanvas": "2019.7.3", "comlink": "^4.4.1", "lodash.get": "^4.4.2" }, "peerDependencies": { "@cornerstonejs/core": "^3.8.4", "@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-yr8RLtnxGh9BsPOFpX+zwT++UGJDqWMo7noWGzxkuISDriLr+HGZI8gL910Mw62obaF8r9qpeOSvSOzEHN3nSw=="], "@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=="],
"@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=="], "@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=="],

View File

@ -46,8 +46,8 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^3.8.4", "@cornerstonejs/adapters": "^3.8.5",
"@cornerstonejs/core": "^3.8.4", "@cornerstonejs/core": "^3.8.5",
"@kitware/vtk.js": "32.12.0", "@kitware/vtk.js": "32.12.0",
"react-color": "^2.19.3" "react-color": "^2.19.3"
} }

View File

@ -46,8 +46,8 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^3.8.4", "@cornerstonejs/adapters": "^3.8.5",
"@cornerstonejs/core": "^3.8.4", "@cornerstonejs/core": "^3.8.5",
"@kitware/vtk.js": "32.12.0", "@kitware/vtk.js": "32.12.0",
"react-color": "^2.19.3" "react-color": "^2.19.3"
} }

View File

@ -305,9 +305,6 @@ const commandsModule = ({
}; };
const definitions = { const definitions = {
loadSegmentationDisplaySetsForViewport: {
commandFn: actions.loadSegmentationDisplaySetsForViewport,
},
loadSegmentationsForViewport: { loadSegmentationsForViewport: {
commandFn: actions.loadSegmentationsForViewport, commandFn: actions.loadSegmentationsForViewport,
}, },

View File

@ -47,7 +47,7 @@ function OHIFCornerstoneSEGViewport(props: withAppTypes) {
const [viewportGrid, viewportGridService] = useViewportGrid(); const [viewportGrid, viewportGridService] = useViewportGrid();
// States // States
let selectedSegmentObjectIndex: number = 0; const selectedSegmentObjectIndex: number = 0;
const { setPositionPresentation } = usePositionPresentationStore(); const { setPositionPresentation } = usePositionPresentationStore();
// Hydration means that the SEG is opened and segments are loaded into the // Hydration means that the SEG is opened and segments are loaded into the
@ -160,7 +160,7 @@ function OHIFCornerstoneSEGViewport(props: withAppTypes) {
displaySetInstanceUID: referencedDisplaySet.displaySetInstanceUID, displaySetInstanceUID: referencedDisplaySet.displaySetInstanceUID,
}); });
viewportGridService.setDisplaySetsForViewport({ commandsManager.runCommand('loadSegmentationDisplaySetsForViewport', {
viewportId, viewportId,
displaySetInstanceUIDs: [referencedDisplaySet.displaySetInstanceUID], displaySetInstanceUIDs: [referencedDisplaySet.displaySetInstanceUID],
}); });

View File

@ -46,9 +46,9 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^3.8.4", "@cornerstonejs/adapters": "^3.8.5",
"@cornerstonejs/core": "^3.8.4", "@cornerstonejs/core": "^3.8.5",
"@cornerstonejs/tools": "^3.8.4", "@cornerstonejs/tools": "^3.8.5",
"classnames": "^2.3.2" "classnames": "^2.3.2"
} }
} }

View File

@ -42,8 +42,8 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/core": "^3.8.4", "@cornerstonejs/core": "^3.8.5",
"@cornerstonejs/tools": "^3.8.4", "@cornerstonejs/tools": "^3.8.5",
"classnames": "^2.3.2" "classnames": "^2.3.2"
} }
} }

View File

@ -38,7 +38,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjpeg": "^1.2.4",
"@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^3.8.4", "@cornerstonejs/dicom-image-loader": "^3.8.5",
"@ohif/core": "3.10.0-beta.148", "@ohif/core": "3.10.0-beta.148",
"@ohif/ui": "3.10.0-beta.148", "@ohif/ui": "3.10.0-beta.148",
"dcmjs": "*", "dcmjs": "*",
@ -51,12 +51,12 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^3.8.4", "@cornerstonejs/adapters": "^3.8.5",
"@cornerstonejs/ai": "^3.8.4", "@cornerstonejs/ai": "^3.8.5",
"@cornerstonejs/core": "^3.8.4", "@cornerstonejs/core": "^3.8.5",
"@cornerstonejs/labelmap-interpolation": "^3.8.4", "@cornerstonejs/labelmap-interpolation": "^3.8.5",
"@cornerstonejs/polymorphic-segmentation": "^3.8.4", "@cornerstonejs/polymorphic-segmentation": "^3.8.5",
"@cornerstonejs/tools": "^3.8.4", "@cornerstonejs/tools": "^3.8.5",
"@itk-wasm/morphological-contour-interpolation": "1.1.0", "@itk-wasm/morphological-contour-interpolation": "1.1.0",
"@kitware/vtk.js": "32.12.0", "@kitware/vtk.js": "32.12.0",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",

View File

@ -35,6 +35,7 @@ import { toolNames } from './initCornerstoneTools';
import CornerstoneViewportDownloadForm from './utils/CornerstoneViewportDownloadForm'; import CornerstoneViewportDownloadForm from './utils/CornerstoneViewportDownloadForm';
import { updateSegmentBidirectionalStats } from './utils/updateSegmentationStats'; import { updateSegmentBidirectionalStats } from './utils/updateSegmentationStats';
import { generateSegmentationCSVReport } from './utils/generateSegmentationCSVReport'; import { generateSegmentationCSVReport } from './utils/generateSegmentationCSVReport';
import { getUpdatedViewportsForSegmentation } from './utils/hydrationUtils';
const { DefaultHistoryMemo } = csUtils.HistoryMemo; const { DefaultHistoryMemo } = csUtils.HistoryMemo;
const toggleSyncFunctions = { const toggleSyncFunctions = {
@ -495,7 +496,6 @@ function commandsModule({
downloadCSVSegmentationReport: ({ segmentationId }) => { downloadCSVSegmentationReport: ({ segmentationId }) => {
const segmentation = segmentationService.getSegmentation(segmentationId); const segmentation = segmentationService.getSegmentation(segmentationId);
const cachedStats = segmentation.cachedStats;
const { representationData } = segmentation; const { representationData } = segmentation;
const { Labelmap } = representationData; const { Labelmap } = representationData;
@ -1021,6 +1021,10 @@ function commandsModule({
const toolGroup = toolGroupService.getToolGroupForViewport(viewportId); const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);
if (!toolGroup.hasTool(toolName)) {
return;
}
const prevConfig = toolGroup?.getToolConfiguration(toolName); const prevConfig = toolGroup?.getToolConfiguration(toolName);
toolGroup?.setToolConfiguration( toolGroup?.setToolConfiguration(
toolName, toolName,
@ -1539,7 +1543,8 @@ function commandsModule({
DefaultHistoryMemo.redo(); DefaultHistoryMemo.redo();
}, },
toggleSegmentPreviewEdit: ({ toggle }) => { toggleSegmentPreviewEdit: ({ toggle }) => {
const labelmapTools = getLabelmapTools({ toolGroupService }); let labelmapTools = getLabelmapTools({ toolGroupService });
labelmapTools = labelmapTools.filter(tool => !tool.toolName.includes('Eraser'));
labelmapTools.forEach(tool => { labelmapTools.forEach(tool => {
tool.configuration = { tool.configuration = {
...tool.configuration, ...tool.configuration,
@ -1562,7 +1567,8 @@ function commandsModule({
}); });
}, },
toggleUseCenterSegmentIndex: ({ toggle }) => { toggleUseCenterSegmentIndex: ({ toggle }) => {
const labelmapTools = getLabelmapTools({ toolGroupService }); let labelmapTools = getLabelmapTools({ toolGroupService });
labelmapTools = labelmapTools.filter(tool => !tool.toolName.includes('Eraser'));
labelmapTools.forEach(tool => { labelmapTools.forEach(tool => {
tool.configuration = { tool.configuration = {
...tool.configuration, ...tool.configuration,
@ -1707,6 +1713,20 @@ function commandsModule({
const activeSegmentation = segmentationService.getActiveSegmentation(activeViewportId); const activeSegmentation = segmentationService.getActiveSegmentation(activeViewportId);
segmentationService.addSegment(activeSegmentation.segmentationId); segmentationService.addSegment(activeSegmentation.segmentationId);
}, },
loadSegmentationDisplaySetsForViewport: ({ viewportId, displaySetInstanceUIDs }) => {
const updatedViewports = getUpdatedViewportsForSegmentation({
viewportId,
servicesManager,
displaySetInstanceUIDs,
});
updatedViewports.forEach(viewport => {
viewportGridService.setDisplaySetsForViewport({
viewportId: viewport.viewportId,
displaySetInstanceUIDs: viewport.displaySetInstanceUIDs,
});
});
},
}; };
const definitions = { const definitions = {
@ -1985,6 +2005,7 @@ function commandsModule({
increaseBrushSize: actions.increaseBrushSize, increaseBrushSize: actions.increaseBrushSize,
decreaseBrushSize: actions.decreaseBrushSize, decreaseBrushSize: actions.decreaseBrushSize,
addNewSegment: actions.addNewSegment, addNewSegment: actions.addNewSegment,
loadSegmentationDisplaySetsForViewport: actions.loadSegmentationDisplaySetsForViewport,
}; };
return { return {

View File

@ -303,7 +303,7 @@ function DicomUploadProgress({
<span <span
className={classNames( className={classNames(
NO_WRAP_ELLIPSIS_CLASS_NAMES, NO_WRAP_ELLIPSIS_CLASS_NAMES,
'text-primary-active hover:text-primary-light active:text-aqua-pale ml-auto cursor-pointer' 'text-primary hover:text-primary-light active:text-aqua-pale ml-auto cursor-pointer'
)} )}
onClick={cancelAllUploads} onClick={cancelAllUploads}
> >

View File

@ -89,7 +89,7 @@ const DicomUploadProgressItem = memo(
)} )}
<div className="ml-auto flex cursor-pointer"> <div className="ml-auto flex cursor-pointer">
<Icons.Close <Icons.Close
className="text-primary-active self-center" className="text-primary self-center"
onClick={cancelUpload} onClick={cancelUpload}
/> />
</div> </div>

View File

@ -82,6 +82,7 @@ const stackRetrieveOptions = {
}, },
}; };
const unsubscriptions = [];
/** /**
* *
*/ */
@ -142,6 +143,8 @@ const cornerstoneExtension: Types.Extensions.Extension = {
useToggleOneUpViewportGridStore.getState().clearToggleOneUpViewportGridStore(); useToggleOneUpViewportGridStore.getState().clearToggleOneUpViewportGridStore();
useSegmentationPresentationStore.getState().clearSegmentationPresentationStore(); useSegmentationPresentationStore.getState().clearSegmentationPresentationStore();
segmentationService.removeAllSegmentations(); segmentationService.removeAllSegmentations();
unsubscriptions.forEach(unsubscribe => unsubscribe());
}, },
/** /**
@ -149,7 +152,7 @@ const cornerstoneExtension: Types.Extensions.Extension = {
* *
* @param configuration.csToolsConfig - Passed directly to `initCornerstoneTools` * @param configuration.csToolsConfig - Passed directly to `initCornerstoneTools`
*/ */
preRegistration: function (props: Types.Extensions.ExtensionParams): Promise<void> { preRegistration: async function (props: Types.Extensions.ExtensionParams): Promise<void> {
const { servicesManager, serviceProvidersManager } = props; const { servicesManager, serviceProvidersManager } = props;
servicesManager.registerService(CornerstoneViewportService.REGISTRATION); servicesManager.registerService(CornerstoneViewportService.REGISTRATION);
servicesManager.registerService(ToolGroupService.REGISTRATION); servicesManager.registerService(ToolGroupService.REGISTRATION);
@ -167,7 +170,13 @@ const cornerstoneExtension: Types.Extensions.Extension = {
const { syncGroupService } = servicesManager.services; const { syncGroupService } = servicesManager.services;
syncGroupService.registerCustomSynchronizer('frameview', createFrameViewSynchronizer); syncGroupService.registerCustomSynchronizer('frameview', createFrameViewSynchronizer);
return init.call(this, props); const initResult = await init.call(this, props);
unsubscriptions.push(...initResult.unsubscriptions);
return {
...initResult,
};
}, },
getToolbarModule, getToolbarModule,
getHangingProtocolModule, getHangingProtocolModule,

View File

@ -193,13 +193,14 @@ export default async function init({
}); });
// Setup segmentation event handlers // Setup segmentation event handlers
const { unsubscribe: unsubscribeSegmentationDataModifiedHandler } =
setupSegmentationDataModifiedHandler({ setupSegmentationDataModifiedHandler({
segmentationService, segmentationService,
customizationService, customizationService,
commandsManager, commandsManager,
}); });
setupSegmentationModifiedHandler({ const { unsubscribe: unsubscribeSegmentationModifiedHandler } = setupSegmentationModifiedHandler({
segmentationService, segmentationService,
}); });
@ -299,6 +300,13 @@ export default async function init({
// Call this function when initializing // Call this function when initializing
initializeWebWorkerProgressHandler(servicesManager.services.uiNotificationService); initializeWebWorkerProgressHandler(servicesManager.services.uiNotificationService);
const unsubscriptions = [
unsubscribeSegmentationDataModifiedHandler,
unsubscribeSegmentationModifiedHandler,
];
return { unsubscriptions };
} }
function initializeWebWorkerProgressHandler(uiNotificationService) { function initializeWebWorkerProgressHandler(uiNotificationService) {

View File

@ -2,12 +2,10 @@ import React from 'react';
import { SegmentationTable } from '@ohif/ui-next'; import { SegmentationTable } from '@ohif/ui-next';
import { useActiveViewportSegmentationRepresentations } from '../hooks/useActiveViewportSegmentationRepresentations'; import { useActiveViewportSegmentationRepresentations } from '../hooks/useActiveViewportSegmentationRepresentations';
import { metaData } from '@cornerstonejs/core'; import { metaData } from '@cornerstonejs/core';
import { useSystem } from '@ohif/core/src';
export default function PanelSegmentation({ export default function PanelSegmentation({ children }: withAppTypes) {
servicesManager, const { commandsManager, servicesManager } = useSystem();
commandsManager,
children,
}: withAppTypes) {
const { customizationService, displaySetService } = servicesManager.services; const { customizationService, displaySetService } = servicesManager.services;
const { segmentationsWithRepresentations, disabled } = const { segmentationsWithRepresentations, disabled } =

View File

@ -427,6 +427,8 @@ class SegmentationService extends PubSubService {
...metaData.get('instance', image.referencedImageId), ...metaData.get('instance', image.referencedImageId),
})); }));
segDisplaySet.imageIds = derivedImageIds;
// We should parse the segmentation as separate slices to support overlapping segments. // We should parse the segmentation as separate slices to support overlapping segments.
// This parsing should occur in the CornerstoneJS library adapters. // This parsing should occur in the CornerstoneJS library adapters.
// For now, we use the volume returned from the library and chop it here. // For now, we use the volume returned from the library and chop it here.
@ -513,7 +515,7 @@ class SegmentationService extends PubSubService {
type: LABELMAP, type: LABELMAP,
data: { data: {
imageIds: derivedImageIds, imageIds: derivedImageIds,
referencedVolumeId: this._getVolumeIdForDisplaySet(referencedDisplaySet), // referencedVolumeId: this._getVolumeIdForDisplaySet(referencedDisplaySet),
referencedImageIds: imageIds as string[], referencedImageIds: imageIds as string[],
}, },
}, },
@ -566,9 +568,10 @@ class SegmentationService extends PubSubService {
const referencedImageIds = referencedDisplaySet.imageIds; const referencedImageIds = referencedDisplaySet.imageIds;
// find the first image id that contains a referenced SOP instance UID // find the first image id that contains a referenced SOP instance UID
const firstSegmentedSliceImageId = referencedImageIds.find(imageId => const firstSegmentedSliceImageId =
referencedImageIds?.find(imageId =>
referencedImageIdsWithGeometry.some(referencedId => imageId.includes(referencedId)) referencedImageIdsWithGeometry.some(referencedId => imageId.includes(referencedId))
); ) || null;
rtDisplaySet.firstSegmentedSliceImageId = firstSegmentedSliceImageId; rtDisplaySet.firstSegmentedSliceImageId = firstSegmentedSliceImageId;
// Map ROI contours to RT Struct Data // Map ROI contours to RT Struct Data

View File

@ -742,6 +742,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
// If you call loadStudyMetadata and it's not in the DicomMetadataStore cache, it should fire // If you call loadStudyMetadata and it's not in the DicomMetadataStore cache, it should fire
// a request through the data source? // a request through the data source?
// (This call may or may not create sub-requests for series metadata) // (This call may or may not create sub-requests for series metadata)
const { displaySetService } = this.servicesManager.services;
const volumeInputArray = []; const volumeInputArray = [];
const displaySetOptionsArray = viewportInfo.getDisplaySetOptions(); const displaySetOptionsArray = viewportInfo.getDisplaySetOptions();
const { hangingProtocolService } = this.servicesManager.services; const { hangingProtocolService } = this.servicesManager.services;
@ -750,7 +751,13 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
const displaySetInstanceUIDs = []; const displaySetInstanceUIDs = [];
for (const [index, data] of viewportData.data.entries()) { for (const [index, data] of viewportData.data.entries()) {
const { volume, imageIds, displaySetInstanceUID } = data; const { imageIds, displaySetInstanceUID } = data;
let volume = data.volume;
if (!volume) {
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
volume = csToolsUtils.getOrCreateImageVolume(displaySet.images.map(image => image.imageId));
}
displaySetInstanceUIDs.push(displaySetInstanceUID); displaySetInstanceUIDs.push(displaySetInstanceUID);

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import html2canvas from 'html2canvas'; import html2canvas from 'html2canvas';
import { getEnabledElement, StackViewport, BaseVolumeViewport } from '@cornerstonejs/core'; import { getEnabledElement, StackViewport, BaseVolumeViewport } from '@cornerstonejs/core';
import { ToolGroupManager } from '@cornerstonejs/tools'; import { ToolGroupManager, segmentation, Enums } from '@cornerstonejs/tools';
import { getEnabledElement as OHIFgetEnabledElement } from '../state'; import { getEnabledElement as OHIFgetEnabledElement } from '../state';
import { useSystem } from '@ohif/core/src'; import { useSystem } from '@ohif/core/src';
@ -103,6 +103,9 @@ const CornerstoneViewportDownloadForm = ({
return; return;
} }
const segmentationRepresentations =
segmentation.state.getViewportSegmentationRepresentations(activeViewportId);
const { viewport } = activeViewportEnabledElement; const { viewport } = activeViewportEnabledElement;
const downloadViewport = renderingEngine.getViewport(VIEWPORT_ID); const downloadViewport = renderingEngine.getViewport(VIEWPORT_ID);
@ -113,20 +116,48 @@ const CornerstoneViewportDownloadForm = ({
await downloadViewport.setStack([imageId]); await downloadViewport.setStack([imageId]);
downloadViewport.setProperties(properties); downloadViewport.setProperties(properties);
return {
width: Math.min(width || DEFAULT_SIZE, MAX_TEXTURE_SIZE),
height: Math.min(height || DEFAULT_SIZE, MAX_TEXTURE_SIZE),
};
} else if (downloadViewport instanceof BaseVolumeViewport) { } else if (downloadViewport instanceof BaseVolumeViewport) {
const volumeIds = viewport.getAllVolumeIds(); const volumeIds = viewport.getAllVolumeIds();
downloadViewport.setVolumes([{ volumeId: volumeIds[0] }]); downloadViewport.setVolumes([{ volumeId: volumeIds[0] }]);
}
if (segmentationRepresentations.length > 0) {
segmentationRepresentations.forEach(segRepresentation => {
const { segmentationId, colorLUTIndex, type } = segRepresentation;
if (type === Enums.SegmentationRepresentations.Labelmap) {
segmentation.addLabelmapRepresentationToViewportMap({
[downloadViewport.id]: [
{
segmentationId,
type: Enums.SegmentationRepresentations.Labelmap,
config: {
colorLUTOrIndex: colorLUTIndex,
},
},
],
});
}
if (type === Enums.SegmentationRepresentations.Contour) {
segmentation.addContourRepresentationToViewportMap({
[downloadViewport.id]: [
{
segmentationId,
type: Enums.SegmentationRepresentations.Contour,
config: {
colorLUTOrIndex: colorLUTIndex,
},
},
],
});
}
});
}
return { return {
width: Math.min(width || DEFAULT_SIZE, MAX_TEXTURE_SIZE), width: Math.min(width || DEFAULT_SIZE, MAX_TEXTURE_SIZE),
height: Math.min(height || DEFAULT_SIZE, MAX_TEXTURE_SIZE), height: Math.min(height || DEFAULT_SIZE, MAX_TEXTURE_SIZE),
}; };
}
} catch (error) { } catch (error) {
console.error('Error loading image:', error); console.error('Error loading image:', error);
} }
@ -167,6 +198,10 @@ const CornerstoneViewportDownloadForm = ({
setTimeout(() => { setTimeout(() => {
handleLoadImage(viewportDimensions.width, viewportDimensions.height); handleLoadImage(viewportDimensions.width, viewportDimensions.height);
handleToggleAnnotations(showAnnotations); handleToggleAnnotations(showAnnotations);
// we need a resize here to make suer annotations world to canvas
// are properly calculated
renderingEngine.resize();
renderingEngine.render();
}, 100); }, 100);
} }
}, [viewportDimensions, showAnnotations]); }, [viewportDimensions, showAnnotations]);

View File

@ -0,0 +1,31 @@
function getUpdatedViewportsForSegmentation({
viewportId,
servicesManager,
displaySetInstanceUIDs,
}: withAppTypes) {
const { hangingProtocolService, viewportGridService } = servicesManager.services;
const { isHangingProtocolLayout } = viewportGridService.getState();
const viewport = getTargetViewport({ viewportId, viewportGridService });
const targetViewportId = viewport.viewportOptions.viewportId;
const updatedViewports = hangingProtocolService.getViewportsRequireUpdate(
targetViewportId,
displaySetInstanceUIDs[0],
isHangingProtocolLayout
);
return updatedViewports.filter(v => v.viewportOptions?.viewportType !== 'volume3d');
}
const getTargetViewport = ({ viewportId, viewportGridService }) => {
const { viewports, activeViewportId } = viewportGridService.getState();
const targetViewportId = viewportId || activeViewportId;
const viewport = viewports.get(targetViewportId);
return viewport;
};
export { getUpdatedViewportsForSegmentation };

View File

@ -9,10 +9,15 @@ export function setupSegmentationDataModifiedHandler({
customizationService, customizationService,
commandsManager, commandsManager,
}) { }) {
segmentationService.subscribeDebounced( const { unsubscribe } = segmentationService.subscribeDebounced(
segmentationService.EVENTS.SEGMENTATION_DATA_MODIFIED, segmentationService.EVENTS.SEGMENTATION_DATA_MODIFIED,
async ({ segmentationId }) => { async ({ segmentationId }) => {
const segmentation = segmentationService.getSegmentation(segmentationId); const segmentation = segmentationService.getSegmentation(segmentationId);
if (!segmentation) {
return;
}
const readableText = customizationService.getCustomization('panelSegmentation.readableText'); const readableText = customizationService.getCustomization('panelSegmentation.readableText');
// Check for segments with bidirectional measurements and update them // Check for segments with bidirectional measurements and update them
@ -46,17 +51,23 @@ export function setupSegmentationDataModifiedHandler({
}, },
1000 1000
); );
return { unsubscribe };
} }
/** /**
* Sets up the handler for segmentation modification events * Sets up the handler for segmentation modification events
*/ */
export function setupSegmentationModifiedHandler({ segmentationService }) { export function setupSegmentationModifiedHandler({ segmentationService }) {
segmentationService.subscribe( const { unsubscribe } = segmentationService.subscribe(
segmentationService.EVENTS.SEGMENTATION_MODIFIED, segmentationService.EVENTS.SEGMENTATION_MODIFIED,
async ({ segmentationId }) => { async ({ segmentationId }) => {
const segmentation = segmentationService.getSegmentation(segmentationId); const segmentation = segmentationService.getSegmentation(segmentationId);
if (!segmentation) {
return;
}
const annotationState = cornerstoneTools.annotation.state.getAllAnnotations(); const annotationState = cornerstoneTools.annotation.state.getAllAnnotations();
const bidirectionalAnnotations = annotationState.filter( const bidirectionalAnnotations = annotationState.filter(
annotation => annotation =>
@ -90,4 +101,6 @@ export function setupSegmentationModifiedHandler({ segmentationService }) {
}); });
} }
); );
return { unsubscribe };
} }

View File

@ -113,7 +113,7 @@ function DataSourceConfigurationModalComponent({
: 'border border-dashed border-secondary-light'; : 'border border-dashed border-secondary-light';
const getSelectedItemTextClasses = itemIndex => const getSelectedItemTextClasses = itemIndex =>
itemIndex <= selectedItems.length ? 'text-primary-light' : 'text-primary-active'; itemIndex <= selectedItems.length ? 'text-primary-light' : 'text-primary';
const getErrorComponent = (): ReactElement => { const getErrorComponent = (): ReactElement => {
return ( return (

View File

@ -20,7 +20,7 @@ function PanelStudyBrowserHeader({
<div className={'flex h-[24px] w-full select-none justify-center self-center text-[14px]'}> <div className={'flex h-[24px] w-full select-none justify-center self-center text-[14px]'}>
<div className="flex w-full items-center gap-[10px]"> <div className="flex w-full items-center gap-[10px]">
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
<div className="text-primary-active flex items-center space-x-1"> <div className="text-primary flex items-center space-x-1">
{actionIcons.map((icon: actionIcon, index) => {actionIcons.map((icon: actionIcon, index) =>
React.createElement(Icons[icon.iconName] || Icons.MissingIcon, { React.createElement(Icons[icon.iconName] || Icons.MissingIcon, {
key: index, key: index,

View File

@ -44,9 +44,9 @@ function HeaderPatientInfo({ servicesManager, appConfig }: withAppTypes) {
onClick={handleOnClick} onClick={handleOnClick}
> >
{isMixedPatients ? ( {isMixedPatients ? (
<Icons.MultiplePatients className="text-primary-active" /> <Icons.MultiplePatients className="text-primary" />
) : ( ) : (
<Icons.Patient className="text-primary-active" /> <Icons.Patient className="text-primary" />
)} )}
<div className="flex flex-col justify-center"> <div className="flex flex-col justify-center">
{expanded ? ( {expanded ? (
@ -61,12 +61,12 @@ function HeaderPatientInfo({ servicesManager, appConfig }: withAppTypes) {
</div> </div>
</> </>
) : ( ) : (
<div className="text-primary-active self-center text-[13px]"> <div className="text-primary self-center text-[13px]">
{isMixedPatients ? 'Multiple Patients' : 'Patient'} {isMixedPatients ? 'Multiple Patients' : 'Patient'}
</div> </div>
)} )}
</div> </div>
<Icons.ArrowLeft className={`text-primary-active ${expanded ? 'rotate-180' : ''}`} /> <Icons.ArrowLeft className={`text-primary ${expanded ? 'rotate-180' : ''}`} />
</div> </div>
); );
} }

View File

@ -95,7 +95,7 @@ function ViewerHeader({ appConfig }: withAppTypes<{ appConfig: AppTypes.Config }
) )
} }
UndoRedo={ UndoRedo={
<div className="text-primary-active flex cursor-pointer items-center"> <div className="text-primary flex cursor-pointer items-center">
<Button <Button
variant="ghost" variant="ghost"
className="hover:bg-primary-dark" className="hover:bg-primary-dark"

View File

@ -85,7 +85,7 @@ export function Toolbox({ buttonSectionId, title }: { buttonSectionId: string; t
{CustomConfigComponent && ( {CustomConfigComponent && (
<div className="ml-auto mr-2"> <div className="ml-auto mr-2">
<Icons.Settings <Icons.Settings
className="text-primary-active h-4 w-4" className="text-primary h-4 w-4"
onClick={e => { onClick={e => {
e.stopPropagation(); e.stopPropagation();
setShowConfig(!showConfig); setShowConfig(!showConfig);

View File

@ -32,8 +32,8 @@
"start": "yarn run dev" "start": "yarn run dev"
}, },
"peerDependencies": { "peerDependencies": {
"@cornerstonejs/core": "^3.8.4", "@cornerstonejs/core": "^3.8.5",
"@cornerstonejs/tools": "^3.8.4", "@cornerstonejs/tools": "^3.8.5",
"@ohif/core": "3.10.0-beta.148", "@ohif/core": "3.10.0-beta.148",
"@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.148", "@ohif/extension-cornerstone-dicom-sr": "3.10.0-beta.148",
"@ohif/extension-default": "3.10.0-beta.148", "@ohif/extension-default": "3.10.0-beta.148",

View File

@ -2,7 +2,8 @@ import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { DicomMetadataStore } from '@ohif/core'; import { DicomMetadataStore } from '@ohif/core';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Button, Input, Label, PanelSection, Separator } from '@ohif/ui-next'; import { Button, Input, Label, PanelSection } from '@ohif/ui-next';
import { useSystem } from '@ohif/core/src';
const DEFAULT_MEATADATA = { const DEFAULT_MEATADATA = {
PatientWeight: null, PatientWeight: null,
@ -37,7 +38,10 @@ const InputRow = ({ children, className, ...props }) => {
// InputRow sub-components // InputRow sub-components
InputRow.Label = ({ children, unit, className, ...props }) => ( InputRow.Label = ({ children, unit, className, ...props }) => (
<Label className={`min-w-32 flex-shrink-0 ${className || ''}`} {...props}> <Label
className={`min-w-32 flex-shrink-0 ${className || ''}`}
{...props}
>
{children} {children}
{unit && <span className="text-muted-foreground"> {unit}</span>} {unit && <span className="text-muted-foreground"> {unit}</span>}
</Label> </Label>
@ -54,7 +58,8 @@ InputRow.Input = ({ className, ...props }) => (
InputRow.Label.displayName = 'InputRow.Label'; InputRow.Label.displayName = 'InputRow.Label';
InputRow.Input.displayName = 'InputRow.Input'; InputRow.Input.displayName = 'InputRow.Input';
export default function PanelPetSUV({ servicesManager, commandsManager }: withAppTypes) { export default function PanelPetSUV({ servicesManager }: withAppTypes) {
const { commandsManager } = useSystem();
const { t } = useTranslation('PanelSUV'); const { t } = useTranslation('PanelSUV');
const { displaySetService, toolGroupService, toolbarService, hangingProtocolService } = const { displaySetService, toolGroupService, toolbarService, hangingProtocolService } =
servicesManager.services; servicesManager.services;
@ -192,7 +197,9 @@ export default function PanelPetSUV({ servicesManager, commandsManager }: withAp
<InputRow> <InputRow>
<InputRow.Label unit="bq">{t('Total Dose')}</InputRow.Label> <InputRow.Label unit="bq">{t('Total Dose')}</InputRow.Label>
<InputRow.Input <InputRow.Input
value={metadata.RadiopharmaceuticalInformationSequence.RadionuclideTotalDose || ''} value={
metadata.RadiopharmaceuticalInformationSequence.RadionuclideTotalDose || ''
}
onChange={e => { onChange={e => {
handleMetadataChange({ handleMetadataChange({
RadiopharmaceuticalInformationSequence: { RadiopharmaceuticalInformationSequence: {
@ -206,7 +213,9 @@ export default function PanelPetSUV({ servicesManager, commandsManager }: withAp
<InputRow> <InputRow>
<InputRow.Label unit="s">{t('Half Life')}</InputRow.Label> <InputRow.Label unit="s">{t('Half Life')}</InputRow.Label>
<InputRow.Input <InputRow.Input
value={metadata.RadiopharmaceuticalInformationSequence.RadionuclideHalfLife || ''} value={
metadata.RadiopharmaceuticalInformationSequence.RadionuclideHalfLife || ''
}
onChange={e => { onChange={e => {
handleMetadataChange({ handleMetadataChange({
RadiopharmaceuticalInformationSequence: { RadiopharmaceuticalInformationSequence: {
@ -221,7 +230,8 @@ export default function PanelPetSUV({ servicesManager, commandsManager }: withAp
<InputRow.Label unit="s">{t('Injection Time')}</InputRow.Label> <InputRow.Label unit="s">{t('Injection Time')}</InputRow.Label>
<InputRow.Input <InputRow.Input
value={ value={
metadata.RadiopharmaceuticalInformationSequence.RadiopharmaceuticalStartTime || '' metadata.RadiopharmaceuticalInformationSequence
.RadiopharmaceuticalStartTime || ''
} }
onChange={e => { onChange={e => {
handleMetadataChange({ handleMetadataChange({

View File

@ -2,11 +2,10 @@ import React, { useEffect } from 'react';
import { useActiveViewportSegmentationRepresentations } from '@ohif/extension-cornerstone'; import { useActiveViewportSegmentationRepresentations } from '@ohif/extension-cornerstone';
import { handleROIThresholding } from '../../utils/handleROIThresholding'; import { handleROIThresholding } from '../../utils/handleROIThresholding';
import { debounce } from '@ohif/core/src/utils'; import { debounce } from '@ohif/core/src/utils';
import { useSystem } from '@ohif/core/src';
export default function PanelRoiThresholdSegmentation({ export default function PanelRoiThresholdSegmentation() {
servicesManager, const { commandsManager, servicesManager } = useSystem();
commandsManager,
}: withAppTypes) {
const { segmentationService } = servicesManager.services; const { segmentationService } = servicesManager.services;
const { segmentationsWithRepresentations: segmentationsInfo } = const { segmentationsWithRepresentations: segmentationsInfo } =
useActiveViewportSegmentationRepresentations({ servicesManager }); useActiveViewportSegmentationRepresentations({ servicesManager });

View File

@ -1,62 +1,13 @@
import React from 'react'; import React from 'react';
import { import { PanelSegmentation } from '@ohif/extension-cornerstone';
PanelSegmentation, import PanelROIThresholdExport from './PanelROIThresholdSegmentation/PanelROIThresholdExport';
useActiveViewportSegmentationRepresentations,
} from '@ohif/extension-cornerstone';
import { Button, Icons } from '@ohif/ui-next';
export default function PanelTMTV({ export default function PanelTMTV({ configuration }: withAppTypes) {
servicesManager,
commandsManager,
extensionManager,
configuration,
}: withAppTypes) {
return ( return (
<> <>
<PanelSegmentation <PanelSegmentation configuration={configuration}>
servicesManager={servicesManager} <PanelROIThresholdExport />
commandsManager={commandsManager}
extensionManager={extensionManager}
configuration={configuration}
>
<ExportCSV
servicesManager={servicesManager}
commandsManager={commandsManager}
/>
</PanelSegmentation> </PanelSegmentation>
</> </>
); );
} }
const ExportCSV = ({ servicesManager, commandsManager }: withAppTypes) => {
const { segmentationsWithRepresentations: representations } =
useActiveViewportSegmentationRepresentations({ servicesManager });
const tmtv = representations[0]?.segmentation.cachedStats?.tmtv;
const segmentations = representations.map(representation => representation.segmentation);
if (!segmentations.length) {
return null;
}
return (
<div className="flex h-8 w-full items-center rounded pr-0.5">
<Button
size="sm"
variant="ghost"
className="pl-1.5"
onClick={() => {
commandsManager.runCommand('exportTMTVReportCSV', {
segmentations,
tmtv,
config: {},
});
}}
>
<Icons.Download />
<span className="pl-1">CSV</span>
</Button>
</div>
);
};

View File

@ -8,7 +8,6 @@ import createAndDownloadTMTVReport from './utils/createAndDownloadTMTVReport';
import dicomRTAnnotationExport from './utils/dicomRTAnnotationExport/RTStructureSet'; import dicomRTAnnotationExport from './utils/dicomRTAnnotationExport/RTStructureSet';
import { getWebWorkerManager } from '@cornerstonejs/core';
import { Enums } from '@cornerstonejs/tools'; import { Enums } from '@cornerstonejs/tools';
import { utils } from '@ohif/core'; import { utils } from '@ohif/core';
@ -22,32 +21,6 @@ const ROI_THRESHOLD_MANUAL_TOOL_IDS = [
'CircleROIStartEndThreshold', 'CircleROIStartEndThreshold',
]; ];
const workerManager = getWebWorkerManager();
// Register the task
function getVolumesFromSegmentation(segmentationId) {
const csSegmentation = csTools.segmentation.state.getSegmentation(segmentationId);
const labelmapData = csSegmentation.representationData[
SegmentationRepresentations.Labelmap
] as csTools.Types.LabelmapToolOperationDataVolume;
const { volumeId, referencedVolumeId } = labelmapData;
const labelmapVolume = cs.cache.getVolume(volumeId);
const referencedVolume = cs.cache.getVolume(referencedVolumeId);
return { labelmapVolume, referencedVolume };
}
function getLabelmapVolumeFromSegmentation(segmentation) {
const { representationData } = segmentation;
const { volumeId } = representationData[
SegmentationRepresentations.Labelmap
] as csTools.Types.LabelmapToolOperationDataVolume;
return cs.cache.getVolume(volumeId);
}
const commandsModule = ({ servicesManager, commandsManager, extensionManager }: withAppTypes) => { const commandsModule = ({ servicesManager, commandsManager, extensionManager }: withAppTypes) => {
const { const {
viewportGridService, viewportGridService,
@ -265,8 +238,14 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
segmentations, segmentations,
}); });
let total_tlg = 0;
for (const segmentationId in segReport) {
const report = segReport[segmentationId];
const tlg = report['namedStats_lesionGlycolysis'];
total_tlg += tlg.value;
}
const additionalReportRows = [ const additionalReportRows = [
{ key: 'Total Lesion Glycolysis', value: { tlg: tlg.toFixed(4) } }, { key: 'Total Lesion Glycolysis', value: { tlg: total_tlg.toFixed(4) } },
{ key: 'Threshold Configuration', value: { ...config } }, { key: 'Threshold Configuration', value: { ...config } },
]; ];
@ -382,9 +361,8 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
continue; continue;
} }
const referencedVolumeId = labelmapVolume.referencedVolumeId; const referencedVolume =
csTools.utilities.segmentation.getReferenceVolumeForSegmentationVolume(segmentationId);
const referencedVolume = cs.cache.getVolume(referencedVolumeId);
if (!referencedVolume) { if (!referencedVolume) {
report[id] = segReport; report[id] = segReport;
@ -476,9 +454,6 @@ const commandsModule = ({ servicesManager, commandsManager, extensionManager }:
thresholdSegmentationByRectangleROITool: { thresholdSegmentationByRectangleROITool: {
commandFn: actions.thresholdSegmentationByRectangleROITool, commandFn: actions.thresholdSegmentationByRectangleROITool,
}, },
getTotalLesionGlycolysis: {
commandFn: actions.getTotalLesionGlycolysis,
},
calculateTMTV: { calculateTMTV: {
commandFn: actions.calculateTMTV, commandFn: actions.calculateTMTV,
}, },

View File

@ -5,13 +5,7 @@ import PanelTMTV from './Panels/PanelTMTV';
function getPanelModule({ commandsManager, extensionManager, servicesManager }) { function getPanelModule({ commandsManager, extensionManager, servicesManager }) {
const wrappedPanelPetSuv = () => { const wrappedPanelPetSuv = () => {
return ( return <PanelPetSUV />;
<PanelPetSUV
commandsManager={commandsManager}
servicesManager={servicesManager}
extensionManager={extensionManager}
/>
);
}; };
const wrappedROIThresholdToolbox = () => { const wrappedROIThresholdToolbox = () => {
@ -24,12 +18,7 @@ function getPanelModule({ commandsManager, extensionManager, servicesManager })
}; };
const wrappedROIThresholdExport = () => { const wrappedROIThresholdExport = () => {
return ( return <PanelROIThresholdExport />;
<PanelROIThresholdExport
commandsManager={commandsManager}
servicesManager={servicesManager}
/>
);
}; };
const wrappedPanelTMTV = () => { const wrappedPanelTMTV = () => {
@ -43,10 +32,6 @@ function getPanelModule({ commandsManager, extensionManager, servicesManager })
commandsManager={commandsManager} commandsManager={commandsManager}
servicesManager={servicesManager} servicesManager={servicesManager}
/> />
<PanelROIThresholdExport
commandsManager={commandsManager}
servicesManager={servicesManager}
/>
</> </>
); );
}; };

View File

@ -3,10 +3,12 @@ import type { Button } from '@ohif/core/types';
import { EVENTS } from '@cornerstonejs/core'; import { EVENTS } from '@cornerstonejs/core';
import { ViewportGridService } from '@ohif/core'; import { ViewportGridService } from '@ohif/core';
const ReferenceLinesListeners = [ const callbacks = (toolName: string) => [
{ {
commandName: 'setSourceViewportForReferenceLinesTool', commandName: 'setViewportForToolConfiguration',
context: 'CORNERSTONE', commandOptions: {
toolName,
},
}, },
]; ];
@ -118,8 +120,8 @@ const toolbarButtons: Button[] = [
tooltip: 'Show Reference Lines', tooltip: 'Show Reference Lines',
commands: 'toggleEnabledDisabledToolbar', commands: 'toggleEnabledDisabledToolbar',
listeners: { listeners: {
[ViewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED]: ReferenceLinesListeners, [ViewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED]: callbacks('ReferenceLinesTool'),
[ViewportGridService.EVENTS.VIEWPORTS_READY]: ReferenceLinesListeners, [ViewportGridService.EVENTS.VIEWPORTS_READY]: callbacks('ReferenceLinesTool'),
}, },
evaluate: [ evaluate: [
'evaluate.cornerstoneTool.toggle', 'evaluate.cornerstoneTool.toggle',

View File

@ -54,7 +54,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjpeg": "^1.2.4",
"@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^3.8.4", "@cornerstonejs/dicom-image-loader": "^3.8.5",
"@emotion/serialize": "^1.1.3", "@emotion/serialize": "^1.1.3",
"@ohif/core": "3.10.0-beta.148", "@ohif/core": "3.10.0-beta.148",
"@ohif/extension-cornerstone": "3.10.0-beta.148", "@ohif/extension-cornerstone": "3.10.0-beta.148",

View File

@ -15,7 +15,7 @@ function Debug() {
/> />
<div className="space-y-2 pt-4 text-center"> <div className="space-y-2 pt-4 text-center">
<div className="flex flex-col items-center justify-center"> <div className="flex flex-col items-center justify-center">
<p className="text-primary-active mt-4 text-xl font-semibold">Debug Information</p> <p className="text-primary mt-4 text-xl font-semibold">Debug Information</p>
<div className="mt-4 flex items-center space-x-2"> <div className="mt-4 flex items-center space-x-2">
<p className="text-md text-white">Cross Origin Isolated (COOP/COEP)</p> <p className="text-md text-white">Cross Origin Isolated (COOP/COEP)</p>
<Icons.ByName <Icons.ByName

View File

@ -343,7 +343,7 @@ function WorkList({
<> <>
<Icons.GroupLayers <Icons.GroupLayers
className={classnames('mr-2 inline-flex w-4', { className={classnames('mr-2 inline-flex w-4', {
'text-primary-active': isExpanded, 'text-primary': isExpanded,
'text-secondary-light': !isExpanded, 'text-secondary-light': !isExpanded,
})} })}
/> />

View File

@ -37,7 +37,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjpeg": "^1.2.4",
"@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^3.8.4", "@cornerstonejs/dicom-image-loader": "^3.8.5",
"@ohif/ui": "3.10.0-beta.148", "@ohif/ui": "3.10.0-beta.148",
"cornerstone-math": "0.1.9", "cornerstone-math": "0.1.9",
"dicom-parser": "^1.8.21" "dicom-parser": "^1.8.21"

View File

@ -0,0 +1,503 @@
'use client';
import React, { useState } from 'react';
import { DataRow } from '../../../../ui-next/src/components/DataRow';
import { Button } from '../../../../ui-next/src/components/Button';
import {
Select,
SelectValue,
SelectTrigger,
SelectContent,
SelectItem,
} from '../../../../ui-next/src/components/Select';
import { Icons } from '../../../../ui-next/src/components/Icons';
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuLabel,
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuSubContent,
DropdownMenuPortal,
} from '../../../../ui-next/src/components/DropdownMenu';
import {
Accordion,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from '../../../../ui-next/src/components/Accordion';
import { Slider } from '../../../../ui-next/src/components/Slider';
import { Switch } from '../../../../ui-next/src/components/Switch';
import { Label } from '../../../../ui-next/src/components/Label';
import { Input } from '../../../../ui-next/src/components/Input';
import { Tabs, TabsList, TabsTrigger } from '../../../../ui-next/src/components/Tabs';
import { actionOptionsMap, dataList } from '../../../../ui-next/assets/data';
import { TooltipProvider } from '../../../../ui-next/src/components/Tooltip';
import {
HoverCard,
HoverCardTrigger,
HoverCardContent,
} from '../../../../ui-next/src/components/HoverCard';
import { DataItem, ListGroup } from '../../../../ui-next/assets/data';
export default function SegmentationPanel() {
const [selectedRowId, setSelectedRowId] = useState<string | null>(null);
const [selectedTab, setSelectedTab] = useState<string>('Fill & Outline');
const handleAction = (id: string, action: string) => {
console.log(`Action "${action}" triggered for item with id: ${id}`);
// Implement actual action logic here
};
// Handle row selection
const handleRowSelect = (id: string) => {
setSelectedRowId(prevSelectedId => (prevSelectedId === id ? null : id));
};
const organSegmentationGroup = dataList.find(
(listGroup: any) => listGroup.type === 'Organ Segmentation'
) as unknown as ListGroup;
if (!organSegmentationGroup) {
return <div className="text-red-500">Organ Segmentation data not found.</div>;
}
// Create a state to track which item's statistics to show
// Function to render statistics panel
const renderStatisticsPanel = (item: DataItem) => {
if (!item.statistics) {
return null;
}
const stats = item.statistics;
return (
<div className="w-full">
<div className="mb-4 flex items-center space-x-2">
<div
className="h-2.5 w-2.5 flex-shrink-0 rounded-full"
style={{ backgroundColor: item.colorHex }}
></div>
<h3 className="text-muted-foreground break-words text-lg font-semibold">{item.title}</h3>
</div>
<div className="space-y-1">
<div className="flex justify-between">
<div className="">Centroid X</div>
<div>
<span className="text-white">{stats.centroidX.value}</span>{' '}
<span className="">{stats.centroidX.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Centroid Y</div>
<div>
<span className="text-white">{stats.centroidY.value}</span>{' '}
<span className="">{stats.centroidY.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Centroid Z</div>
<div>
<span className="text-white">{stats.centroidZ.value}</span>{' '}
<span className="">{stats.centroidZ.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Frame Duration</div>
<div>
<span className="text-white">{stats.frameDuration.value}</span>{' '}
<span className="">{stats.frameDuration.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Kurtosis</div>
<div>
<span className="text-white">{stats.kurtosis.value}</span>{' '}
<span className="">{stats.kurtosis.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Max</div>
<div>
<span className="text-white">{stats.max.value}</span>{' '}
<span className="">{stats.max.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Max Slice</div>
<div>
<span className="text-white">{stats.maxSlice.value}</span>{' '}
<span className="">{stats.maxSlice.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Mean</div>
<div>
<span className="text-white">{stats.mean.value}</span>{' '}
<span className="">{stats.mean.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Median</div>
<div>
<span className="text-white">{stats.median.value}</span>{' '}
<span className="">{stats.median.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Min</div>
<div>
<span className="text-white">{stats.min.value}</span>{' '}
<span className="">{stats.min.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Regions</div>
<div>
<span className="text-white">{stats.regions.value}</span>{' '}
<span className="">{stats.regions.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Skewness</div>
<div>
<span className="text-white">{stats.skewness.value}</span>{' '}
<span className="">{stats.skewness.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Sphere Diameter</div>
<div>
<span className="text-white">{stats.sphereDiameter.value}</span>{' '}
<span className="">{stats.sphereDiameter.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Standard Deviation</div>
<div>
<span className="text-white">{stats.standardDeviation.value}</span>{' '}
<span className="">{stats.standardDeviation.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">SUV Peak</div>
<div>
<span className="text-white">{stats.suvPeak.value}</span>{' '}
<span className="">{stats.suvPeak.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Total</div>
<div>
<span className="text-white">{stats.total.value}</span>{' '}
<span className="">{stats.total.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Glycolysis</div>
<div>
<span className="text-white">{stats.glycolysis.value}</span>{' '}
<span className="">{stats.glycolysis.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Volume</div>
<div>
<span className="text-white">{stats.volume.value}</span>{' '}
<span className="">{stats.volume.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Voxel Count</div>
<div>
<span className="text-white">{stats.voxelCount.value}</span>{' '}
<span className="">{stats.voxelCount.unit}</span>
</div>
</div>
</div>
</div>
);
};
return (
<div className="px-auto flex min-h-screen w-full justify-center bg-black py-12">
<div className="w-64 space-y-0">
<TooltipProvider>
<Accordion
type="multiple"
defaultValue={['segmentation-tools', 'segmentation-list']}
>
{/* Segmentation Tools */}
<AccordionItem value="segmentation-tools">
<AccordionTrigger className="bg-popover hover:bg-accent text-muted-foreground my-0.5 flex h-7 w-full items-center justify-between rounded py-2 pr-1 pl-2 font-normal">
<span>Segmentation Tools</span>
</AccordionTrigger>
<AccordionContent>
<div className="bg-muted mb-0.5 h-32 rounded-b pb-3"></div>
</AccordionContent>
</AccordionItem>
{/* Segmentation List */}
<AccordionItem value="segmentation-list">
<AccordionTrigger className="bg-popover hover:bg-accent text-muted-foreground my-0.5 flex h-7 w-full items-center justify-between rounded py-2 pr-1 pl-2 font-normal">
<span>Segmentation List</span>
</AccordionTrigger>
<AccordionContent>
<div className="mb-0">
{/* Header Controls */}
<div className="bg-muted flex h-10 w-full items-center space-x-1 rounded-t px-1.5">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="icon"
>
<Icons.More className="h-6 w-6" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuItem>
<Icons.Add className="text-foreground" />
<span className="pl-2">Create New Segmentation</span>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuLabel>Manage Current Segmentation</DropdownMenuLabel>
<DropdownMenuItem>
<Icons.Series className="text-foreground" />
<span className="pl-2">Remove from Viewport</span>
</DropdownMenuItem>
<DropdownMenuItem>
<Icons.Rename className="text-foreground" />
<span className="pl-2">Rename</span>
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<Icons.Export className="text-foreground" />
<span className="pl-2">Export & Download</span>
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuItem>Export DICOM SEG</DropdownMenuItem>
<DropdownMenuItem>Download DICOM SEG</DropdownMenuItem>
<DropdownMenuItem>Download DICOM RTSTRUCT</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem>
<Icons.Delete className="text-red-600" />
<span className="pl-2 text-red-600">Delete</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<Select>
<SelectTrigger className="w-full overflow-hidden">
<SelectValue placeholder="Segmentation 1" />
</SelectTrigger>
<SelectContent>
<SelectItem value="seg1">Segmentation 1</SelectItem>
<SelectItem value="seg2">Segmentation 2</SelectItem>
<SelectItem value="seg3">Segmentation Long Name 123</SelectItem>
</SelectContent>
</Select>
<Button
variant="ghost"
size="icon"
>
<Icons.Info className="h-6 w-6" />
</Button>
</div>
{/* Appearance Settings */}
<AccordionItem value="segmentation-display">
<AccordionTrigger className="bg-muted hover:bg-accent mt-0.5 flex h-7 w-full items-center justify-between rounded-b pr-1 pl-2 font-normal text-white">
<div className="flex space-x-2">
<Icons.Controls className="text-primary" />
<span className="text-primary pr-1">Appearance Settings</span>
</div>
</AccordionTrigger>
<AccordionContent>
<div className="bg-muted mb-0.5 space-y-2 rounded-b px-1.5 pt-0.5 pb-3">
<div className="mx-1 mb-2.5 mt-1 flex items-center justify-between space-x-4">
{/* Display Label with Selected Tab */}
<div className="text-muted-foreground text-xs">Show: {selectedTab}</div>
{/* Tabs Controls */}
<Tabs
value={selectedTab}
onValueChange={setSelectedTab}
>
<TabsList>
<TabsTrigger value="Fill & Outline">
<Icons.DisplayFillAndOutline className="text-primary" />
</TabsTrigger>
<TabsTrigger value="Outline Only">
<Icons.DisplayOutlineOnly className="text-primary" />
</TabsTrigger>
<TabsTrigger value="Fill Only">
<Icons.DisplayFillOnly className="text-primary" />
</TabsTrigger>
</TabsList>
</Tabs>
</div>
{/* Opacity Slider */}
<div className="my-2 flex items-center">
<Label className="text-muted-foreground mx-1 w-14 flex-none whitespace-nowrap text-xs">
Opacity
</Label>
<Slider
className="mx-1 flex-1"
defaultValue={[85]}
max={100}
step={1}
/>
<Input
className="mx-1 w-10 flex-none"
placeholder="85"
/>
</div>
{/* Border Slider */}
<div className="my-2 flex items-center">
<Label className="text-muted-foreground mx-1 w-14 flex-none whitespace-nowrap text-xs">
Border
</Label>
<Slider
className="mx-1 flex-1"
defaultValue={[10]}
max={100}
step={1}
/>
<Input
className="mx-1 w-10 flex-none"
placeholder="2"
/>
</div>
{/* Sync Changes Switch */}
<div className="my-2 flex items-center pl-1 pb-1">
<Switch defaultChecked />
<Label className="text-muted-foreground mx-2 w-14 flex-none whitespace-nowrap text-xs">
Sync changes in all viewports
</Label>
</div>
<div className="border-input w-full border"></div>
{/* Display Inactive Segmentations Switch */}
<div className="my-2 flex items-center pl-1">
<Switch defaultChecked />
<Label className="text-muted-foreground mx-2 w-14 flex-none whitespace-nowrap text-xs">
Display inactive segmentations
</Label>
</div>
{/* Additional Opacity Slider */}
<div className="my-2 flex items-center">
<Label className="text-muted-foreground mx-1 w-14 flex-none whitespace-nowrap text-xs">
Opacity
</Label>
<Slider
className="mx-1 flex-1"
defaultValue={[65]}
max={100}
step={1}
/>
<Input
className="mx-1 w-10 flex-none"
placeholder="65"
/>
</div>
</div>
</AccordionContent>
</AccordionItem>
{/* Action Buttons */}
<div className="my-px flex h-9 w-full items-center justify-between rounded pl-0.5 pr-7">
<Button
size="sm"
variant="ghost"
className="pr pl-0.5"
>
<Icons.Add />
Add Segment
</Button>
<Button
size="icon"
variant="ghost"
>
<Icons.Hide className="h-6 w-6" />
</Button>
</div>
</div>
{/* Data Rows */}
<div className="space-y-px">
{organSegmentationGroup.items.map((item, index) => {
const compositeId = `${organSegmentationGroup.type}-${item.id}-panel`; // Ensure unique composite ID
return (
<HoverCard
key={`hover-${compositeId}`}
openDelay={300}
closeDelay={200}
// open={true}
>
<HoverCardTrigger asChild>
<div>
<DataRow
key={`panel-${compositeId}`} // Prefix to ensure uniqueness
number={index + 1}
title={item.title}
description={item.description}
colorHex={item.colorHex}
details={item.details || { primary: [], secondary: [] }}
actionOptions={
actionOptionsMap[organSegmentationGroup.type] || ['Action']
}
onAction={(action: string) => handleAction(compositeId, action)}
isSelected={selectedRowId === compositeId}
onSelect={() => handleRowSelect(compositeId)}
isVisible={true}
isLocked={false}
onToggleVisibility={() => console.debug('Toggle visibility')}
onToggleLocked={() => console.debug('Toggle locked')}
onRename={() => console.debug('Rename')}
onDelete={() => console.debug('Delete')}
onColor={() => console.debug('Color')}
disableEditing={false}
/>
</div>
</HoverCardTrigger>
<HoverCardContent
side="left"
align="start"
className="w-72 border"
>
{renderStatisticsPanel(item)}
</HoverCardContent>
</HoverCard>
);
})}
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
</TooltipProvider>
</div>
</div>
);
}

View File

@ -2,538 +2,72 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { DataRow } from '../../../../ui-next/src/components/DataRow'; import { panelSegmentationData } from '../../../../ui-next/assets/data';
import { Button } from '../../../../ui-next/src/components/Button'; import { SegmentationTable } from '../../../../ui-next/src/components/SegmentationTable';
import {
Select,
SelectValue,
SelectTrigger,
SelectContent,
SelectItem,
} from '../../../../ui-next/src/components/Select';
import { Icons } from '../../../../ui-next/src/components/Icons';
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuLabel,
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuSubContent,
DropdownMenuPortal,
} from '../../../../ui-next/src/components/DropdownMenu';
import {
Accordion,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from '../../../../ui-next/src/components/Accordion';
import { Slider } from '../../../../ui-next/src/components/Slider';
import { Switch } from '../../../../ui-next/src/components/Switch';
import { Label } from '../../../../ui-next/src/components/Label';
import { Input } from '../../../../ui-next/src/components/Input';
import { Tabs, TabsList, TabsTrigger } from '../../../../ui-next/src/components/Tabs';
import { actionOptionsMap, dataList } from '../../../../ui-next/assets/data';
import { TooltipProvider } from '../../../../ui-next/src/components/Tooltip'; import { TooltipProvider } from '../../../../ui-next/src/components/Tooltip';
import {
HoverCard,
HoverCardTrigger,
HoverCardContent,
} from '../../../../ui-next/src/components/HoverCard';
interface DataItem {
id: number;
title: string;
description: string;
optionalField?: string;
colorHex?: string;
details?: { primary: string[]; secondary: string[] };
series?: string;
statistics?: {
centroidX: string;
centroidY: string;
centroidZ: string;
frameDuration: string;
kurtosis: string;
max: string;
maxSlice: string;
mean: string;
median: string;
min: string;
regions: string;
skewness: string;
sphereDiameter: string;
standardDeviation: string;
suvPeak: string;
total: string;
glycolysis: string;
volume: string;
voxelCount: string;
};
}
interface ListGroup {
type: string;
items: DataItem[];
}
export default function SegmentationPanel() { export default function SegmentationPanel() {
const [selectedRowId, setSelectedRowId] = useState<string | null>(null); const tableProps = panelSegmentationData;
const [selectedTab, setSelectedTab] = useState<string>('Fill & Outline'); tableProps.mode = 'expanded';
const handleAction = (id: string, action: string) => {
console.log(`Action "${action}" triggered for item with id: ${id}`);
// Implement actual action logic here
};
// Handle row selection const renderSegments = () => {
const handleRowSelect = (id: string) => {
setSelectedRowId(prevSelectedId => (prevSelectedId === id ? null : id));
};
const organSegmentationGroup = dataList.find(
(listGroup: any) => listGroup.type === 'Organ Segmentation'
) as unknown as ListGroup;
if (!organSegmentationGroup) {
return <div className="text-red-500">Organ Segmentation data not found.</div>;
}
// Create a state to track which item's statistics to show
// Function to render statistics panel
const renderStatisticsPanel = (item: DataItem) => {
if (!item.statistics) {
return null;
}
const stats = item.statistics;
return ( return (
<div className="w-full"> <SegmentationTable.Segments>
<div className="mb-4 flex items-center space-x-2"> <SegmentationTable.SegmentStatistics.Header></SegmentationTable.SegmentStatistics.Header>
<div <SegmentationTable.SegmentStatistics.Body />
className="h-2.5 w-2.5 flex-shrink-0 rounded-full" </SegmentationTable.Segments>
style={{ backgroundColor: item.colorHex }} );
></div> };
<h3 className="text-muted-foreground break-words text-lg font-semibold">{item.title}</h3>
</div>
<div className="space-y-1"> // Render content based on mode
<div className="flex justify-between"> const renderModeContent = () => {
<div className="">Centroid X</div> if (tableProps.mode === 'collapsed') {
<div> return (
<span className="text-white">{stats.centroidX.value}</span>{' '} <SegmentationTable.Collapsed>
<span className="">{stats.centroidX.unit}</span> <SegmentationTable.Collapsed.Header>
</div> <SegmentationTable.Collapsed.DropdownMenu>
</div> {/* <CustomDropdownMenuContent /> */}
</SegmentationTable.Collapsed.DropdownMenu>
<SegmentationTable.Collapsed.Selector />
<SegmentationTable.Collapsed.Info />
</SegmentationTable.Collapsed.Header>
<SegmentationTable.Collapsed.Content>
<SegmentationTable.AddSegmentRow />
{renderSegments()}
</SegmentationTable.Collapsed.Content>
</SegmentationTable.Collapsed>
);
}
<div className="flex justify-between"> return (
<div className="">Centroid Y</div> <>
<div> <SegmentationTable.Expanded>
<span className="text-white">{stats.centroidY.value}</span>{' '} <SegmentationTable.Expanded.Header>
<span className="">{stats.centroidY.unit}</span> <SegmentationTable.Expanded.DropdownMenu>
</div> {/* <CustomDropdownMenuContent /> */}
</div> </SegmentationTable.Expanded.DropdownMenu>
<SegmentationTable.Expanded.Label />
<SegmentationTable.Expanded.Info />
</SegmentationTable.Expanded.Header>
<div className="flex justify-between"> <SegmentationTable.Expanded.Content>
<div className="">Centroid Z</div> <SegmentationTable.AddSegmentRow />
<div> {renderSegments()}
<span className="text-white">{stats.centroidZ.value}</span>{' '} </SegmentationTable.Expanded.Content>
<span className="">{stats.centroidZ.unit}</span> </SegmentationTable.Expanded>
</div> </>
</div>
<div className="flex justify-between">
<div className="">Frame Duration</div>
<div>
<span className="text-white">{stats.frameDuration.value}</span>{' '}
<span className="">{stats.frameDuration.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Kurtosis</div>
<div>
<span className="text-white">{stats.kurtosis.value}</span>{' '}
<span className="">{stats.kurtosis.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Max</div>
<div>
<span className="text-white">{stats.max.value}</span>{' '}
<span className="">{stats.max.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Max Slice</div>
<div>
<span className="text-white">{stats.maxSlice.value}</span>{' '}
<span className="">{stats.maxSlice.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Mean</div>
<div>
<span className="text-white">{stats.mean.value}</span>{' '}
<span className="">{stats.mean.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Median</div>
<div>
<span className="text-white">{stats.median.value}</span>{' '}
<span className="">{stats.median.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Min</div>
<div>
<span className="text-white">{stats.min.value}</span>{' '}
<span className="">{stats.min.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Regions</div>
<div>
<span className="text-white">{stats.regions.value}</span>{' '}
<span className="">{stats.regions.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Skewness</div>
<div>
<span className="text-white">{stats.skewness.value}</span>{' '}
<span className="">{stats.skewness.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Sphere Diameter</div>
<div>
<span className="text-white">{stats.sphereDiameter.value}</span>{' '}
<span className="">{stats.sphereDiameter.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Standard Deviation</div>
<div>
<span className="text-white">{stats.standardDeviation.value}</span>{' '}
<span className="">{stats.standardDeviation.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">SUV Peak</div>
<div>
<span className="text-white">{stats.suvPeak.value}</span>{' '}
<span className="">{stats.suvPeak.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Total</div>
<div>
<span className="text-white">{stats.total.value}</span>{' '}
<span className="">{stats.total.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Glycolysis</div>
<div>
<span className="text-white">{stats.glycolysis.value}</span>{' '}
<span className="">{stats.glycolysis.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Volume</div>
<div>
<span className="text-white">{stats.volume.value}</span>{' '}
<span className="">{stats.volume.unit}</span>
</div>
</div>
<div className="flex justify-between">
<div className="">Voxel Count</div>
<div>
<span className="text-white">{stats.voxelCount.value}</span>{' '}
<span className="">{stats.voxelCount.unit}</span>
</div>
</div>
</div>
</div>
); );
}; };
return ( return (
<div className="px-auto flex min-h-screen w-full justify-center bg-black py-12"> <div className="px-auto flex min-h-screen w-full justify-center border-2 bg-black py-64">
<div className="w-64 space-y-0">
<TooltipProvider> <TooltipProvider>
<Accordion <SegmentationTable {...tableProps}>
type="multiple" <SegmentationTable.Config />
defaultValue={['segmentation-tools', 'segmentation-list']} <SegmentationTable.AddSegmentationRow />
> {renderModeContent()}
{/* Segmentation Tools */} </SegmentationTable>
<AccordionItem value="segmentation-tools">
<AccordionTrigger className="bg-popover hover:bg-accent text-muted-foreground my-0.5 flex h-7 w-full items-center justify-between rounded py-2 pr-1 pl-2 font-normal">
<span>Segmentation Tools</span>
</AccordionTrigger>
<AccordionContent>
<div className="bg-muted mb-0.5 h-32 rounded-b pb-3"></div>
</AccordionContent>
</AccordionItem>
{/* Segmentation List */}
<AccordionItem value="segmentation-list">
<AccordionTrigger className="bg-popover hover:bg-accent text-muted-foreground my-0.5 flex h-7 w-full items-center justify-between rounded py-2 pr-1 pl-2 font-normal">
<span>Segmentation List</span>
</AccordionTrigger>
<AccordionContent>
<div className="mb-0">
{/* Header Controls */}
<div className="bg-muted flex h-10 w-full items-center space-x-1 rounded-t px-1.5">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="icon"
>
<Icons.More className="h-6 w-6" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuItem>
<Icons.Add className="text-foreground" />
<span className="pl-2">Create New Segmentation</span>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuLabel>Manage Current Segmentation</DropdownMenuLabel>
<DropdownMenuItem>
<Icons.Series className="text-foreground" />
<span className="pl-2">Remove from Viewport</span>
</DropdownMenuItem>
<DropdownMenuItem>
<Icons.Rename className="text-foreground" />
<span className="pl-2">Rename</span>
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<Icons.Export className="text-foreground" />
<span className="pl-2">Export & Download</span>
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuItem>Export DICOM SEG</DropdownMenuItem>
<DropdownMenuItem>Download DICOM SEG</DropdownMenuItem>
<DropdownMenuItem>Download DICOM RTSTRUCT</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem>
<Icons.Delete className="text-red-600" />
<span className="pl-2 text-red-600">Delete</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<Select>
<SelectTrigger className="w-full overflow-hidden">
<SelectValue placeholder="Segmentation 1" />
</SelectTrigger>
<SelectContent>
<SelectItem value="seg1">Segmentation 1</SelectItem>
<SelectItem value="seg2">Segmentation 2</SelectItem>
<SelectItem value="seg3">Segmentation Long Name 123</SelectItem>
</SelectContent>
</Select>
<Button
variant="ghost"
size="icon"
>
<Icons.Info className="h-6 w-6" />
</Button>
</div>
{/* Appearance Settings */}
<AccordionItem value="segmentation-display">
<AccordionTrigger className="bg-muted hover:bg-accent mt-0.5 flex h-7 w-full items-center justify-between rounded-b pr-1 pl-2 font-normal text-white">
<div className="flex space-x-2">
<Icons.Controls className="text-primary" />
<span className="text-primary pr-1">Appearance Settings</span>
</div>
</AccordionTrigger>
<AccordionContent>
<div className="bg-muted mb-0.5 space-y-2 rounded-b px-1.5 pt-0.5 pb-3">
<div className="mx-1 mb-2.5 mt-1 flex items-center justify-between space-x-4">
{/* Display Label with Selected Tab */}
<div className="text-muted-foreground text-xs">Show: {selectedTab}</div>
{/* Tabs Controls */}
<Tabs
value={selectedTab}
onValueChange={setSelectedTab}
>
<TabsList>
<TabsTrigger value="Fill & Outline">
<Icons.DisplayFillAndOutline className="text-primary" />
</TabsTrigger>
<TabsTrigger value="Outline Only">
<Icons.DisplayOutlineOnly className="text-primary" />
</TabsTrigger>
<TabsTrigger value="Fill Only">
<Icons.DisplayFillOnly className="text-primary" />
</TabsTrigger>
</TabsList>
</Tabs>
</div>
{/* Opacity Slider */}
<div className="my-2 flex items-center">
<Label className="text-muted-foreground mx-1 w-14 flex-none whitespace-nowrap text-xs">
Opacity
</Label>
<Slider
className="mx-1 flex-1"
defaultValue={[85]}
max={100}
step={1}
/>
<Input
className="mx-1 w-10 flex-none"
placeholder="85"
/>
</div>
{/* Border Slider */}
<div className="my-2 flex items-center">
<Label className="text-muted-foreground mx-1 w-14 flex-none whitespace-nowrap text-xs">
Border
</Label>
<Slider
className="mx-1 flex-1"
defaultValue={[10]}
max={100}
step={1}
/>
<Input
className="mx-1 w-10 flex-none"
placeholder="2"
/>
</div>
{/* Sync Changes Switch */}
<div className="my-2 flex items-center pl-1 pb-1">
<Switch defaultChecked />
<Label className="text-muted-foreground mx-2 w-14 flex-none whitespace-nowrap text-xs">
Sync changes in all viewports
</Label>
</div>
<div className="border-input w-full border"></div>
{/* Display Inactive Segmentations Switch */}
<div className="my-2 flex items-center pl-1">
<Switch defaultChecked />
<Label className="text-muted-foreground mx-2 w-14 flex-none whitespace-nowrap text-xs">
Display inactive segmentations
</Label>
</div>
{/* Additional Opacity Slider */}
<div className="my-2 flex items-center">
<Label className="text-muted-foreground mx-1 w-14 flex-none whitespace-nowrap text-xs">
Opacity
</Label>
<Slider
className="mx-1 flex-1"
defaultValue={[65]}
max={100}
step={1}
/>
<Input
className="mx-1 w-10 flex-none"
placeholder="65"
/>
</div>
</div>
</AccordionContent>
</AccordionItem>
{/* Action Buttons */}
<div className="my-px flex h-9 w-full items-center justify-between rounded pl-0.5 pr-7">
<Button
size="sm"
variant="ghost"
className="pr pl-0.5"
>
<Icons.Add />
Add Segment
</Button>
<Button
size="icon"
variant="ghost"
>
<Icons.Hide className="h-6 w-6" />
</Button>
</div>
</div>
{/* Data Rows */}
<div className="space-y-px">
{organSegmentationGroup.items.map((item, index) => {
const compositeId = `${organSegmentationGroup.type}-${item.id}-panel`; // Ensure unique composite ID
return (
<HoverCard
key={`hover-${compositeId}`}
openDelay={300}
closeDelay={200}
// open={true}
>
<HoverCardTrigger asChild>
<div>
<DataRow
key={`panel-${compositeId}`} // Prefix to ensure uniqueness
number={index + 1}
title={item.title}
description={item.description}
colorHex={item.colorHex}
details={item.details || { primary: [], secondary: [] }}
actionOptions={
actionOptionsMap[organSegmentationGroup.type] || ['Action']
}
onAction={(action: string) => handleAction(compositeId, action)}
isSelected={selectedRowId === compositeId}
onSelect={() => handleRowSelect(compositeId)}
isVisible={true}
isLocked={false}
onToggleVisibility={() => console.debug('Toggle visibility')}
onToggleLocked={() => console.debug('Toggle locked')}
onRename={() => console.debug('Rename')}
onDelete={() => console.debug('Delete')}
onColor={() => console.debug('Color')}
disableEditing={false}
/>
</div>
</HoverCardTrigger>
<HoverCardContent
side="left"
align="start"
className="w-72 border"
>
{renderStatisticsPanel(item)}
</HoverCardContent>
</HoverCard>
);
})}
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
</TooltipProvider> </TooltipProvider>
</div> </div>
</div>
); );
} }

View File

@ -1,3 +1,39 @@
interface DataItem {
id: number;
title: string;
description: string;
optionalField?: string;
colorHex?: string;
details?: { primary: string[]; secondary: string[] };
series?: string;
statistics?: {
centroidX: { value: number; unit: string };
centroidY: { value: number; unit: string };
centroidZ: { value: number; unit: string };
frameDuration: { value: number; unit: string };
kurtosis: { value: number; unit: string };
max: { value: number; unit: string };
maxSlice: { value: number; unit: string };
mean: { value: number; unit: string };
median: { value: number; unit: string };
min: { value: number; unit: string };
regions: { value: number; unit: string };
skewness: { value: number; unit: string };
sphereDiameter: { value: number; unit: string };
standardDeviation: { value: number; unit: string };
suvPeak: { value: number; unit: string };
total: { value: number; unit: string };
glycolysis: { value: number; unit: string };
volume: { value: number; unit: string };
voxelCount: { value: number; unit: string };
};
}
interface ListGroup {
type: string;
items: DataItem[];
}
const actionOptionsMap: { [key: string]: string[] } = { const actionOptionsMap: { [key: string]: string[] } = {
Measurement: ['Rename', 'Lock', 'Delete'], Measurement: ['Rename', 'Lock', 'Delete'],
Segmentation: ['Rename', 'Lock', 'Export', 'Delete'], Segmentation: ['Rename', 'Lock', 'Export', 'Delete'],
@ -547,4 +583,146 @@ const dataList = [
}, },
]; ];
export { actionOptionsMap, dataList }; const segmentationData = {
representation: {
id: '791aaa59-1df6-60f8-3c28-6d870e6a4585-Labelmap-default',
segmentationId: '791aaa59-1df6-60f8-3c28-6d870e6a4585',
label: 'Segmentation',
active: true,
type: 'Labelmap',
visible: true,
segments: {
'1': {
color: [255, 0, 0, 255],
segmentIndex: 1,
opacity: 255,
visible: true,
},
'2': {
color: [0, 255, 0, 255],
segmentIndex: 2,
opacity: 255,
visible: true,
},
'3': {
color: [255, 255, 0, 255],
segmentIndex: 3,
opacity: 255,
visible: true,
},
'4': {
color: [0, 255, 255, 255],
segmentIndex: 4,
opacity: 255,
visible: true,
},
},
viewportId: 'default',
colorLUTIndex: 0,
config: {},
},
segmentation: {
segmentationId: '791aaa59-1df6-60f8-3c28-6d870e6a4585',
label: 'Segmentation',
cachedStats: {},
segments: {
'1': {
segmentIndex: 1,
label: 'Liver',
locked: false,
cachedStats: {
category: 'Anatomical Structure',
type: 'Liver',
algorithmType: 'SEMIAUTOMATIC',
algorithmName: 'Amira',
},
active: true,
},
'2': {
segmentIndex: 2,
label: 'Mass',
locked: false,
cachedStats: {
category: 'Morphologically Altered Structure',
type: 'Mass',
algorithmType: 'SEMIAUTOMATIC',
algorithmName: 'Amira',
},
active: false,
},
'3': {
segmentIndex: 3,
label: 'Portal vein',
locked: false,
cachedStats: {
category: 'Anatomical Structure',
type: 'Portal vein',
algorithmType: 'SEMIAUTOMATIC',
algorithmName: 'Amira',
},
active: false,
},
'4': {
segmentIndex: 4,
label: 'Abdominal aorta',
locked: false,
cachedStats: {
category: 'Anatomical Structure',
type: 'Abdominal aorta',
algorithmType: 'SEMIAUTOMATIC',
algorithmName: 'Amira',
},
active: false,
},
},
representationData: {
Labelmap: {
imageIds: [],
referencedImageIds: [],
},
},
},
};
const getSegmentationData = ({
active = false,
segmentationId = '791aaa59-1df6-60f8-3c28-6d870e6a4585',
}) => {
return {
segmentation: {
...segmentationData.segmentation,
active,
segmentationId,
},
representation: {
...segmentationData.representation,
active,
},
};
};
const panelSegmentationData = {
disabled: false,
data: [
getSegmentationData({ active: true }),
getSegmentationData({ active: false, segmentationId: 'babas' }),
],
mode: 'collapsed',
title: 'Segmentations',
exportOptions: [
{
segmentationId: '791aaa59-1df6-60f8-3c28-6d870e6a4585',
isExportable: true,
},
{
segmentationId: '791aaa59-1df6-60f8-3c28-6d870e6a4585',
isExportable: true,
},
],
disableEditing: false,
showAddSegment: true,
renderInactiveSegmentations: true,
};
export { actionOptionsMap, dataList, panelSegmentationData };
export type { DataItem, ListGroup };

View File

@ -65,7 +65,7 @@ function Header({
onClick={onClickReturn} onClick={onClickReturn}
data-cy="return-to-work-list" data-cy="return-to-work-list"
> >
{isReturnEnabled && <Icons.ArrowLeft className="text-primary-active w-8" />} {isReturnEnabled && <Icons.ArrowLeft className="text-primary w-8" />}
<div className="ml-1"> <div className="ml-1">
{WhiteLabeling?.createLogoComponentFn?.(React, props) || <Icons.OHIFLogo />} {WhiteLabeling?.createLogoComponentFn?.(React, props) || <Icons.OHIFLogo />}
</div> </div>
@ -86,7 +86,7 @@ function Header({
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
className="text-primary-active hover:bg-primary-dark mt-2 h-full w-full" className="text-primary hover:bg-primary-dark mt-2 h-full w-full"
> >
<Icons.GearSettings /> <Icons.GearSettings />
</Button> </Button>

View File

@ -27,7 +27,7 @@ export const AddSegmentationRow: React.FC<{ children?: React.ReactNode }> = ({
onClick={() => !disabled && onSegmentationAdd('')} onClick={() => !disabled && onSegmentationAdd('')}
> >
{children} {children}
<div className="text-primary-active group-hover:bg-secondary-dark flex items-center rounded-[4px] pl-1 group-hover:cursor-pointer"> <div className="text-primary group-hover:bg-secondary-dark flex items-center rounded-[4px] pl-1 group-hover:cursor-pointer">
<div className="grid h-[28px] w-[28px] place-items-center"> <div className="grid h-[28px] w-[28px] place-items-center">
{disabled ? <Icons.Info /> : <Icons.Add />} {disabled ? <Icons.Info /> : <Icons.Add />}
</div> </div>

View File

@ -17,7 +17,7 @@ const SegmentationExpandedHeader = ({ children }: { children: React.ReactNode })
return ( return (
<PanelSection.Header <PanelSection.Header
className={`border-input border-t-2 bg-transparent pl-1 ${isActive ? 'border-primary' : ''} py-0`} className={`bg-muted my-0 rounded-none border-l-[2px] pl-0 ${isActive ? 'border-primary/70' : 'border-primary/35'}`}
onClick={e => { onClick={e => {
e.stopPropagation(); e.stopPropagation();
onSegmentationClick(segmentation.segmentationId); onSegmentationClick(segmentation.segmentationId);
@ -59,7 +59,7 @@ const SegmentationExpandedInfo = () => {
const { segmentation } = useSegmentationExpanded('SegmentationExpandedInfo'); const { segmentation } = useSegmentationExpanded('SegmentationExpandedInfo');
return ( return (
<div className="ml-auto mr-1"> <div className="ml-auto mr-2">
<Tooltip> <Tooltip>
<TooltipTrigger asChild> <TooltipTrigger asChild>
<Button <Button
@ -79,8 +79,11 @@ const SegmentationExpandedInfo = () => {
// Content component // Content component
const SegmentationExpandedContent = ({ children }: { children: React.ReactNode }) => { const SegmentationExpandedContent = ({ children }: { children: React.ReactNode }) => {
const { isActive } = useSegmentationExpanded('SegmentationExpandedContent');
return ( return (
<PanelSection.Content className="py-0"> <PanelSection.Content
className={`border-l-[2px] py-0 pb-6 pl-[8px] ${isActive ? 'border-primary/70' : 'border-primary/35'}`}
>
<div className="segmentation-expanded-section">{children}</div> <div className="segmentation-expanded-section">{children}</div>
</PanelSection.Content> </PanelSection.Content>
); );
@ -97,14 +100,14 @@ const SegmentationExpandedRoot = ({ children }) => {
} }
return ( return (
<div className="space-y-0"> <div className={`space-y-0 pl-0.5`}>
{data.map(segmentationInfo => { {data.map(segmentationInfo => {
const isActive = segmentationInfo.segmentation.segmentationId === activeSegmentationId; const isActive = segmentationInfo.segmentation.segmentationId === activeSegmentationId;
return ( return (
<PanelSection <PanelSection
key={segmentationInfo.segmentation.segmentationId} key={segmentationInfo.segmentation.segmentationId}
className="mb-0" className=""
> >
<SegmentationExpandedProvider <SegmentationExpandedProvider
segmentation={segmentationInfo.segmentation} segmentation={segmentationInfo.segmentation}

View File

@ -65,14 +65,8 @@ export const SegmentationSegments = ({ children = null }: { children?: React.Rea
const { locked, active, label, displayText } = segmentFromSegmentation; const { locked, active, label, displayText } = segmentFromSegmentation;
const cssColor = `rgb(${color[0]},${color[1]},${color[2]})`; const cssColor = `rgb(${color[0]},${color[1]},${color[2]})`;
return ( const hasStats = segmentFromSegmentation.cachedStats?.namedStats;
<HoverCard const DataRowComponent = (
key={`hover-${segmentIndex}`}
openDelay={300}
>
<HoverCardTrigger asChild>
{/* The div here is not random, it is needed for making it work with the hover card */}
<div>
<DataRow <DataRow
key={segmentIndex} key={segmentIndex}
number={segmentIndex} number={segmentIndex}
@ -93,14 +87,20 @@ export const SegmentationSegments = ({ children = null }: { children?: React.Rea
representation.type representation.type
) )
} }
onToggleLocked={() => onToggleLocked={() => onToggleSegmentLock(segmentation.segmentationId, segmentIndex)}
onToggleSegmentLock(segmentation.segmentationId, segmentIndex)
}
onSelect={() => onSegmentClick(segmentation.segmentationId, segmentIndex)} onSelect={() => onSegmentClick(segmentation.segmentationId, segmentIndex)}
onRename={() => onSegmentEdit(segmentation.segmentationId, segmentIndex)} onRename={() => onSegmentEdit(segmentation.segmentationId, segmentIndex)}
onDelete={() => onSegmentDelete(segmentation.segmentationId, segmentIndex)} onDelete={() => onSegmentDelete(segmentation.segmentationId, segmentIndex)}
/> />
</div> );
return hasStats ? (
<HoverCard
key={`hover-${segmentIndex}`}
openDelay={300}
>
<HoverCardTrigger asChild>
<div>{DataRowComponent}</div>
</HoverCardTrigger> </HoverCardTrigger>
<HoverCardContent <HoverCardContent
side="left" side="left"
@ -126,6 +126,8 @@ export const SegmentationSegments = ({ children = null }: { children?: React.Rea
</SegmentStatistics> </SegmentStatistics>
</HoverCardContent> </HoverCardContent>
</HoverCard> </HoverCard>
) : (
DataRowComponent
); );
})} })}
</ScrollArea> </ScrollArea>

View File

@ -112,7 +112,7 @@ export const SegmentationTableRoot = (props: SegmentationTableProps) => {
{hasConfigComponent && ( {hasConfigComponent && (
<div className="ml-auto mr-2"> <div className="ml-auto mr-2">
<Icons.Settings <Icons.Settings
className="text-primary-active h-4 w-4" className="text-primary h-4 w-4"
onClick={e => { onClick={e => {
e.stopPropagation(); e.stopPropagation();
toggleShowConfig(); toggleShowConfig();

View File

@ -61,13 +61,13 @@ export const SegmentationTableConfig: React.FC<{ children?: React.ReactNode }> =
> >
<TabsList> <TabsList>
<TabsTrigger value="fill-and-outline"> <TabsTrigger value="fill-and-outline">
<Icons.FillAndOutline className="text-primary-active" /> <Icons.FillAndOutline className="text-primary" />
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="outline"> <TabsTrigger value="outline">
<Icons.OutlineOnly className="text-primary-active" /> <Icons.OutlineOnly className="text-primary" />
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="fill"> <TabsTrigger value="fill">
<Icons.FillOnly className="text-primary-active" /> <Icons.FillOnly className="text-primary" />
</TabsTrigger> </TabsTrigger>
</TabsList> </TabsList>
</Tabs> </Tabs>

View File

@ -112,7 +112,7 @@ const getTabClassNames = (
isTabDisabled: boolean isTabDisabled: boolean
) => ) =>
classnames('h-[28px] mb-[2px] cursor-pointer text-white bg-black', { classnames('h-[28px] mb-[2px] cursor-pointer text-white bg-black', {
'hover:text-primary-active': !isActiveTab && !isTabDisabled, 'hover:text-primary': !isActiveTab && !isTabDisabled,
'rounded-l': tabIndex % numColumns === 0, 'rounded-l': tabIndex % numColumns === 0,
'rounded-r': (tabIndex + 1) % numColumns === 0 || tabIndex === numTabs - 1, 'rounded-r': (tabIndex + 1) % numColumns === 0 || tabIndex === numTabs - 1,
}); });
@ -294,7 +294,7 @@ const SidePanel = ({
data-cy={`side-panel-header-${side}`} data-cy={`side-panel-header-${side}`}
> >
<Icons.NavigationPanelReveal <Icons.NavigationPanelReveal
className={classnames('text-primary-active', side === 'left' && 'rotate-180 transform')} className={classnames('text-primary', side === 'left' && 'rotate-180 transform')}
/> />
</div> </div>
<div className={classnames('mt-3 flex flex-col space-y-3')}> <div className={classnames('mt-3 flex flex-col space-y-3')}>
@ -304,14 +304,14 @@ const SidePanel = ({
<div <div
id={`${childComponent.name}-btn`} id={`${childComponent.name}-btn`}
data-cy={`${childComponent.name}-btn`} data-cy={`${childComponent.name}-btn`}
className="text-primary-active hover:cursor-pointer" className="text-primary hover:cursor-pointer"
onClick={() => { onClick={() => {
return childComponent.disabled ? null : updateActiveTabIndex(index, true); return childComponent.disabled ? null : updateActiveTabIndex(index, true);
}} }}
> >
{React.createElement(Icons[childComponent.iconName] || Icons.MissingIcon, { {React.createElement(Icons[childComponent.iconName] || Icons.MissingIcon, {
className: classnames({ className: classnames({
'text-primary-active': true, 'text-primary': true,
'ohif-disabled': childComponent.disabled, 'ohif-disabled': childComponent.disabled,
}), }),
style: { style: {
@ -352,7 +352,7 @@ const SidePanel = ({
data-cy={`side-panel-header-${side}`} data-cy={`side-panel-header-${side}`}
> >
{React.createElement(Icons[openStateIconName[side]] || Icons.MissingIcon, { {React.createElement(Icons[openStateIconName[side]] || Icons.MissingIcon, {
className: 'text-primary-active', className: 'text-primary',
})} })}
</div> </div>
); );
@ -365,7 +365,7 @@ const SidePanel = ({
<> <>
{getCloseIcon()} {getCloseIcon()}
<div className={classnames('flex grow justify-center')}> <div className={classnames('flex grow justify-center')}>
<div className={classnames('bg-primary-dark text-primary-active flex flex-wrap')}> <div className={classnames('bg-primary-dark text-primary flex flex-wrap')}>
{tabs.map((tab, tabIndex) => { {tabs.map((tab, tabIndex) => {
const { disabled } = tab; const { disabled } = tab;
return ( return (
@ -401,7 +401,7 @@ const SidePanel = ({
> >
{React.createElement(Icons[tab.iconName] || Icons.MissingIcon, { {React.createElement(Icons[tab.iconName] || Icons.MissingIcon, {
className: classnames({ className: classnames({
'text-primary-active': true, 'text-primary': true,
'ohif-disabled': disabled, 'ohif-disabled': disabled,
}), }),
style: { style: {
@ -429,7 +429,7 @@ const SidePanel = ({
return ( return (
<div <div
className={classnames( className={classnames(
'text-primary-active flex grow cursor-pointer select-none justify-center self-center text-[13px]' 'text-primary flex grow cursor-pointer select-none justify-center self-center text-[13px]'
)} )}
data-cy={`${tabs[0].name}-btn`} data-cy={`${tabs[0].name}-btn`}
onClick={() => updatePanelOpen(!panelOpen)} onClick={() => updatePanelOpen(!panelOpen)}

View File

@ -111,7 +111,7 @@ const Thumbnail = ({
<TooltipContent side="right"> <TooltipContent side="right">
<div className="flex flex-1 flex-row"> <div className="flex flex-1 flex-row">
<div className="flex-2 flex items-center justify-center pr-4"> <div className="flex-2 flex items-center justify-center pr-4">
<Icons.InfoLink className="text-primary-active" /> <Icons.InfoLink className="text-primary" />
</div> </div>
<div className="flex flex-1 flex-col"> <div className="flex flex-1 flex-col">
<span> <span>
@ -226,7 +226,7 @@ const Thumbnail = ({
<TooltipContent side="right"> <TooltipContent side="right">
<div className="flex flex-1 flex-row"> <div className="flex flex-1 flex-row">
<div className="flex-2 flex items-center justify-center pr-4"> <div className="flex-2 flex items-center justify-center pr-4">
<Icons.InfoLink className="text-primary-active" /> <Icons.InfoLink className="text-primary" />
</div> </div>
<div className="flex flex-1 flex-col"> <div className="flex flex-1 flex-col">
<span> <span>

View File

@ -1,6 +1,6 @@
const getToggledClassName = isToggled => { const getToggledClassName = isToggled => {
return isToggled return isToggled
? '!text-primary-active' ? '!text-primary'
: '!text-common-bright hover:!bg-primary-dark hover:text-primary-light'; : '!text-common-bright hover:!bg-primary-dark hover:text-primary-light';
}; };

View File

@ -0,0 +1,42 @@
import { test } from '@playwright/test';
import { visitStudy, checkForScreenshot, screenShotPaths } from './utils';
test.beforeEach(async ({ page }) => {
const studyInstanceUID = '1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046';
const mode = 'viewer';
await visitStudy(page, studyInstanceUID, mode, 2000);
});
test('should properly display MPR for MR', async ({ page }) => {
await page.getByTestId('side-panel-header-right').click();
await page.getByTestId('Layout').click();
await page.getByTestId('MPR').click();
await page.waitForTimeout(5000);
await checkForScreenshot(page, page, screenShotPaths.segHydrationFromMPR.mprBeforeSEG);
await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
await page.waitForTimeout(5000);
await checkForScreenshot(page, page, screenShotPaths.segHydrationFromMPR.mprAfterSEG);
await page.getByTestId('yes-hydrate-btn').click();
await page.waitForTimeout(5000);
await checkForScreenshot(page, page, screenShotPaths.segHydrationFromMPR.mprAfterSegHydrated);
await page.getByTestId('Layout').click();
await page.getByTestId('Axial Primary').click();
await page.waitForTimeout(5000);
await checkForScreenshot(
page,
page,
screenShotPaths.segHydrationFromMPR.mprAfterSegHydratedAfterLayoutChange
);
});

View File

@ -12,7 +12,7 @@ test('should properly display MPR for MR', async ({ page }) => {
await page.getByTestId('study-browser-thumbnail-no-image').dblclick(); await page.getByTestId('study-browser-thumbnail-no-image').dblclick();
await page.getByTestId('yes-hydrate-btn').click(); await page.getByTestId('yes-hydrate-btn').click();
await checkForScreenshot(page, page, screenShotPaths.segHydrationMPR.segPostHydration); await checkForScreenshot(page, page, screenShotPaths.segHydrationThenMPR.segPostHydration);
await page.getByTestId('Layout').click(); await page.getByTestId('Layout').click();
await page.getByTestId('Axial Primary').click(); await page.getByTestId('Axial Primary').click();
@ -20,6 +20,6 @@ test('should properly display MPR for MR', async ({ page }) => {
await checkForScreenshot( await checkForScreenshot(
page, page,
page, page,
screenShotPaths.segHydrationMPR.segPostHydrationMPRAxialPrimary screenShotPaths.segHydrationThenMPR.segPostHydrationMPRAxialPrimary
); );
}); });

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

View File

@ -79,10 +79,16 @@ const screenShotPaths = {
segPreHydration: 'segPreHydration.png', segPreHydration: 'segPreHydration.png',
segJumpToSegment: 'segJumpToSegment.png', segJumpToSegment: 'segJumpToSegment.png',
}, },
segHydrationMPR: { segHydrationThenMPR: {
segPostHydration: 'segPostHydration.png', segPostHydration: 'segPostHydration.png',
segPostHydrationMPRAxialPrimary: 'segPostHydrationMPRAxialPrimary.png', segPostHydrationMPRAxialPrimary: 'segPostHydrationMPRAxialPrimary.png',
}, },
segHydrationFromMPR: {
mprBeforeSEG: 'mprBeforeSEG.png',
mprAfterSEG: 'mprAfterSEG.png',
mprAfterSegHydrated: 'mprAfterSegHydrated.png',
mprAfterSegHydratedAfterLayoutChange: 'mprAfterSegHydratedAfterLayoutChange.png',
},
rtHydration: { rtHydration: {
rtPostHydration: 'rtPostHydration.png', rtPostHydration: 'rtPostHydration.png',
rtPreHydration: 'rtPreHydration.png', rtPreHydration: 'rtPreHydration.png',

View File

@ -1393,10 +1393,10 @@
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
"@cornerstonejs/adapters@^3.8.4": "@cornerstonejs/adapters@^3.8.5":
version "3.8.4" version "3.8.5"
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-3.8.4.tgz#14e22bef3abaf14cde52ecf8b05b43a687b0dece" resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-3.8.5.tgz#d516a8fba29d200b47d77fe0ef586ed8962506de"
integrity sha512-TFTvNZQBW54rEcyjDfyHZYYvIPHVGZoUCtjW3isHfpoXkjHz2cliwC55e0kcNJ0zbyI6H41c4VsYH8h2MTYOdA== integrity sha512-dQlKKSCbV6V3QpivDdZZiI7N792l1VqsOj8H+e8iiarpy6MvwiEvck2u50/GBhto9D/U9QvRkZVs9TH0ewUs5w==
dependencies: dependencies:
"@babel/runtime-corejs2" "^7.17.8" "@babel/runtime-corejs2" "^7.17.8"
buffer "^6.0.3" buffer "^6.0.3"
@ -1404,10 +1404,10 @@
gl-matrix "^3.4.3" gl-matrix "^3.4.3"
ndarray "^1.0.19" ndarray "^1.0.19"
"@cornerstonejs/ai@^3.8.4": "@cornerstonejs/ai@^3.8.5":
version "3.8.4" version "3.8.5"
resolved "https://registry.yarnpkg.com/@cornerstonejs/ai/-/ai-3.8.4.tgz#c998cdfbd1cae01e3ea9ed61810c657d91112f75" resolved "https://registry.yarnpkg.com/@cornerstonejs/ai/-/ai-3.8.5.tgz#8f6be57b7bc660afacd52b34ce56a71c696419ed"
integrity sha512-scc2srdL1BqNTSFEro4y7UlNBsPtBVSF31eT4SC1psxZQcr/iyaCKuOQg/hglk1yobFkdIKvjRAvvqvYmGduQw== integrity sha512-9QR7PmTtkeXZOjDFh9WulLJGnraWLaM/g/qNB0ZaPKDMo1PLT7/tHn1F6wsyT2cmpEb3/G5towdxtEvhvlpm/w==
dependencies: dependencies:
"@babel/runtime-corejs2" "^7.17.8" "@babel/runtime-corejs2" "^7.17.8"
buffer "^6.0.3" buffer "^6.0.3"
@ -1443,20 +1443,20 @@
resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.5.tgz#8690b61a86fa53ef38a70eee9d665a79229517c0" resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.5.tgz#8690b61a86fa53ef38a70eee9d665a79229517c0"
integrity sha512-MZCUy8VG0VG5Nl1l58+g+kH3LujAzLYTfJqkwpWI2gjSrGXnP6lgwyy4GmPRZWVoS40/B1LDNALK905cNWm+sg== integrity sha512-MZCUy8VG0VG5Nl1l58+g+kH3LujAzLYTfJqkwpWI2gjSrGXnP6lgwyy4GmPRZWVoS40/B1LDNALK905cNWm+sg==
"@cornerstonejs/core@^3.8.4": "@cornerstonejs/core@^3.8.5":
version "3.8.4" version "3.8.5"
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-3.8.4.tgz#bbc6863cb3f2e78f5f4c7a1a5a9287c091287228" resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-3.8.5.tgz#577bd32f0a3da36f895bf89c821b02a4cf97e225"
integrity sha512-8spQvERZRn4I/0EhzTNZ5ruPBrVn5F4msb/q0ttBtiVEa9JaVwoWh3yEcO4q5NpK7t1BhpfSPMKwU98Dy02ugQ== integrity sha512-x3LZwZUqhVldChpwtLqNwUWx8eXq9q1ndwrx5lVpnX4ZUT9qQIAro01Ih8DPiXlLb1NXbN3sG4e/x/TxuQ+5bw==
dependencies: dependencies:
"@kitware/vtk.js" "32.12.1" "@kitware/vtk.js" "32.12.1"
comlink "^4.4.1" comlink "^4.4.1"
gl-matrix "^3.4.3" gl-matrix "^3.4.3"
loglevel "^1.9.2" loglevel "^1.9.2"
"@cornerstonejs/dicom-image-loader@^3.8.4": "@cornerstonejs/dicom-image-loader@^3.8.5":
version "3.8.4" version "3.8.5"
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-3.8.4.tgz#c4f7af80a40a1f70deff37ddfc50447cc42422e7" resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-3.8.5.tgz#963a3174af3603e4beb096d448671442a0d5f10a"
integrity sha512-N2D4U8JDhen+dCY1HrLOoK8W3CD2AAf/Cd+GiJMEGjtrihIuQ+Ha+hZTVQzaDMc7v2Ruvx2DpJ7i9HUJXoyWHw== integrity sha512-yuLLU2sbtFWueNKVbeYBddPoJnfhrUQ+rRnXJb+y9iczwZMQLy4tYyk3Q5INo+/nIdwCVeZg7P9qORZERsBivw==
dependencies: dependencies:
"@cornerstonejs/codec-charls" "^1.2.3" "@cornerstonejs/codec-charls" "^1.2.3"
"@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2" "@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2"
@ -1468,25 +1468,25 @@
pako "^2.0.4" pako "^2.0.4"
uuid "^9.0.0" uuid "^9.0.0"
"@cornerstonejs/labelmap-interpolation@^3.8.4": "@cornerstonejs/labelmap-interpolation@^3.8.5":
version "3.8.4" version "3.8.5"
resolved "https://registry.yarnpkg.com/@cornerstonejs/labelmap-interpolation/-/labelmap-interpolation-3.8.4.tgz#5c18761a7bbb8e3e76bfbf22b2205c1c5e8bee6e" resolved "https://registry.yarnpkg.com/@cornerstonejs/labelmap-interpolation/-/labelmap-interpolation-3.8.5.tgz#19e8142362d5b83540bcb764306cd6bdf277c9ce"
integrity sha512-KKDTeVJg1s0trplkaHglBm0foQ3XL9BhsTfatFCTzgIOCT0wolrKbr+xAKIeZuBQifiFazDWpYaeBHRbkWEEMA== integrity sha512-u80OTJE8eju+tZ+S/N1b/HTIw2mPjEE2o5u3T/7/w90FX7OaxJJiMYjPPfnSZWXjE2HhRu0gEAKHOU3dr8pL4w==
dependencies: dependencies:
"@itk-wasm/morphological-contour-interpolation" "1.1.0" "@itk-wasm/morphological-contour-interpolation" "1.1.0"
itk-wasm "1.0.0-b.165" itk-wasm "1.0.0-b.165"
"@cornerstonejs/polymorphic-segmentation@^3.8.4": "@cornerstonejs/polymorphic-segmentation@^3.8.5":
version "3.8.4" version "3.8.5"
resolved "https://registry.yarnpkg.com/@cornerstonejs/polymorphic-segmentation/-/polymorphic-segmentation-3.8.4.tgz#5c7578eedd4e7ac78250f06ccecb3950ddf5ba28" resolved "https://registry.yarnpkg.com/@cornerstonejs/polymorphic-segmentation/-/polymorphic-segmentation-3.8.5.tgz#5289f1b9d7f8fdbf3164330c4d30dd03fffa16be"
integrity sha512-+3o280NOniUkG9GcWTeTi6x3qy8Rm7WpYFycWpxXIufJzVudJi0zAR+EIWDq/uvTQ3DH1SrBDe4wzYNqD+yirw== integrity sha512-6L9a9f36CnUIuGsydA8kkkC0z1Gjid4KfclCQoYYaxcsLWLDpba5usFERmxCLIm9VyBsA3POqesIGDqWTgJmFg==
dependencies: dependencies:
"@icr/polyseg-wasm" "0.4.0" "@icr/polyseg-wasm" "0.4.0"
"@cornerstonejs/tools@^3.8.4": "@cornerstonejs/tools@^3.8.5":
version "3.8.4" version "3.8.5"
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-3.8.4.tgz#4676ba9d7fcae22f236bab2314118b5d06cc973e" resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-3.8.5.tgz#15fe20fa051dc12084141515c2a715a4f0a9a858"
integrity sha512-yr8RLtnxGh9BsPOFpX+zwT++UGJDqWMo7noWGzxkuISDriLr+HGZI8gL910Mw62obaF8r9qpeOSvSOzEHN3nSw== integrity sha512-aTaziRHJakCCxvbHhbrSkEuiamURGakcK83KXGJPjSdStWC/2cVpkCzPxc8V7FZBIstsvo5pgciXSpNc6Yt7Og==
dependencies: dependencies:
"@types/offscreencanvas" "2019.7.3" "@types/offscreencanvas" "2019.7.3"
comlink "^4.4.1" comlink "^4.4.1"