Compare commits
167
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
419366bd25 | ||
|
|
b59eb30b0f | ||
|
|
57d03fc722 | ||
|
|
17e12d53e5 | ||
|
|
ffd7884ed1 | ||
|
|
0dd6571505 | ||
|
|
6e2d53f280 | ||
|
|
6acbbc0271 | ||
|
|
780d172201 | ||
|
|
256b8347e7 | ||
|
|
da9fd9057d | ||
|
|
5cb2fb41f8 | ||
|
|
a219822ad1 | ||
|
|
e391e6de5f | ||
|
|
a64fceb009 | ||
|
|
f1cc2ee13a | ||
|
|
571c2b4ff0 | ||
|
|
6dd150d401 | ||
|
|
a27f779f0b | ||
|
|
99c6154343 | ||
|
|
0885468bb9 | ||
|
|
9396e01107 | ||
|
|
1aaae125ea | ||
|
|
ff3e855809 | ||
|
|
550dec742d | ||
|
|
daae4c144e | ||
|
|
9e7a3586ce | ||
|
|
bdcafc12de | ||
|
|
5ea22fc34f | ||
|
|
0c1ca6b04a | ||
|
|
9a2d2c3d13 | ||
|
|
5762095cfa | ||
|
|
becd208924 | ||
|
|
2258c7957a | ||
|
|
d186749c5a | ||
|
|
09093b3f0a | ||
|
|
ef8bb5559a | ||
|
|
95251ab670 | ||
|
|
1e91285c60 | ||
|
|
27af6821b5 | ||
|
|
6f92234111 | ||
|
|
527cfb0ae8 | ||
|
|
64fa240dfa | ||
|
|
77cd9394d2 | ||
|
|
8e8f574174 | ||
|
|
fe16e80cf3 | ||
|
|
cb0cbe702c | ||
|
|
55b46f39c6 | ||
|
|
01b5c86826 | ||
|
|
f231eff598 | ||
|
|
b058ec7c72 | ||
|
|
397aa4d0e3 | ||
|
|
8cd8ccc163 | ||
|
|
37e19f734a | ||
|
|
13305de99c | ||
|
|
9cf3149d2a | ||
|
|
fbea158473 | ||
|
|
5e624f1387 | ||
|
|
d792bf7f80 | ||
|
|
979d619f7c | ||
|
|
5bccf0a753 | ||
|
|
691e26731f | ||
|
|
e6816f6de4 | ||
|
|
468e5734a9 | ||
|
|
90abd00936 | ||
|
|
62620afb9b | ||
|
|
03860030bd | ||
|
|
f8ccf9ff2e | ||
|
|
c9c4f11b82 | ||
|
|
f3cca21e49 | ||
|
|
5ba8339037 | ||
|
|
1fc97fea43 | ||
|
|
7008029cdc | ||
|
|
8fc0dc16e9 | ||
|
|
8a2fee4d8a | ||
|
|
eede569a88 | ||
|
|
51e6b35dbb | ||
|
|
792f78e35f | ||
|
|
cc5dc20164 | ||
|
|
31727c0668 | ||
|
|
760adc50d6 | ||
|
|
6e4ef68a83 | ||
|
|
f5a66b9eea | ||
|
|
3069d33c99 | ||
|
|
f6bbd5c779 | ||
|
|
66c8e0c195 | ||
|
|
961eea1c39 | ||
|
|
0ddf32eef2 | ||
|
|
d219171e25 | ||
|
|
6cbad4fab7 | ||
|
|
0e933c256e | ||
|
|
74e656b174 | ||
|
|
68b10d365a | ||
|
|
91a8715795 | ||
|
|
fdf26aa8b9 | ||
|
|
84ddf78c87 | ||
|
|
d7ab507f5b | ||
|
|
5358a3985a | ||
|
|
d670fb168c | ||
|
|
b9029ef6f8 | ||
|
|
a875d7de1f | ||
|
|
7929f0898f | ||
|
|
f999f3eab5 | ||
|
|
e66fb5a2b8 | ||
|
|
efac34dfe5 | ||
|
|
2a728b244c | ||
|
|
485f0d75d9 | ||
|
|
d7dd12ad67 | ||
|
|
9718ecc407 | ||
|
|
fe762b68e8 | ||
|
|
87eeefdf1b | ||
|
|
1d4802c2a3 | ||
|
|
69d8ad63f3 | ||
|
|
1df671e9ab | ||
|
|
15ef4c2e0f | ||
|
|
7a38903b19 | ||
|
|
40a472a9b1 | ||
|
|
d8d376edaf | ||
|
|
d0bab783c7 | ||
|
|
fe1ecfe0cc | ||
|
|
54d9ea39bf | ||
|
|
7b5d0ce40e | ||
|
|
15f14e34e4 | ||
|
|
d015b2e32a | ||
|
|
197b80eefd | ||
|
|
b83e978df8 | ||
|
|
4c2bd8d5ed | ||
|
|
889026f8a9 | ||
|
|
1aaf569825 | ||
|
|
6f773f9972 | ||
|
|
0f822aaf48 | ||
|
|
61a1fccd7d | ||
|
|
c842642341 | ||
|
|
70f76aeba1 | ||
|
|
30bb5d0652 | ||
|
|
2358a73c3c | ||
|
|
df22109013 | ||
|
|
7e10830d58 | ||
|
|
6db0bc2d4c | ||
|
|
be8e266a80 | ||
|
|
b3e5f64694 | ||
|
|
f2ed4c9e6f | ||
|
|
b6d362f375 | ||
|
|
92011c587f | ||
|
|
c9dea4e6cc | ||
|
|
6a3caa1ac9 | ||
|
|
2b486f16ed | ||
|
|
5370b9382e | ||
|
|
67f9de4ab6 | ||
|
|
d11d6d401b | ||
|
|
a8f709982f | ||
|
|
9e4c0bb7a2 | ||
|
|
eeca1f7a7b | ||
|
|
279ae0dfe0 | ||
|
|
928d592333 | ||
|
|
3330d2b52b | ||
|
|
b5573caaa6 | ||
|
|
cb4397fe31 | ||
|
|
d359a3b784 | ||
|
|
ce9f159c21 | ||
|
|
27229609cd | ||
|
|
83e687fb02 | ||
|
|
b35354120a | ||
|
|
c75cbc2a89 | ||
|
|
53c67f3612 | ||
|
|
c85ca0e177 | ||
|
|
3d59c0d9d3 |
No files matched your search
+110
-63
@@ -1,26 +1,30 @@
|
||||
version: 2.1
|
||||
|
||||
# ci: re-trigger pipeline
|
||||
|
||||
orbs:
|
||||
codecov: codecov/codecov@1.0.5
|
||||
cypress: cypress-io/cypress@3.4.2
|
||||
|
||||
defaults: &defaults
|
||||
docker:
|
||||
- image: cimg/node:20.18.1
|
||||
- image: cimg/node:24.0.0
|
||||
environment:
|
||||
TERM: xterm
|
||||
QUICK_BUILD: true
|
||||
working_directory: ~/repo
|
||||
|
||||
commands:
|
||||
install_bun:
|
||||
install_pnpm:
|
||||
steps:
|
||||
- run:
|
||||
name: Install Bun
|
||||
name: Install pnpm
|
||||
command: |
|
||||
curl -fsSL https://bun.sh/install | bash -s "bun-v1.2.23"
|
||||
echo 'export BUN_INSTALL="$HOME/.bun"' >> $BASH_ENV
|
||||
echo 'export PATH="$BUN_INSTALL/bin:$PATH"' >> $BASH_ENV
|
||||
# The cimg/node global modules dir (/usr/local/lib/node_modules) is
|
||||
# root-owned, so a plain `npm install -g` fails with EACCES. Install
|
||||
# with sudo so the global pnpm binary lands in the shared prefix.
|
||||
sudo npm install -g pnpm@11.5.2
|
||||
echo 'export PATH="$(pnpm store path)/../.bin:$PATH"' >> $BASH_ENV
|
||||
source $BASH_ENV
|
||||
|
||||
jobs:
|
||||
@@ -28,16 +32,16 @@ jobs:
|
||||
<<: *defaults
|
||||
resource_class: large
|
||||
steps:
|
||||
- install_bun
|
||||
- install_pnpm
|
||||
- run: node --version
|
||||
- checkout
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: bun install --no-save
|
||||
command: pnpm install --frozen-lockfile
|
||||
# RUN TESTS
|
||||
- run:
|
||||
name: 'JavaScript Test Suite'
|
||||
command: bun run test:unit:ci
|
||||
command: pnpm run test:unit:ci
|
||||
# platform/app
|
||||
- run:
|
||||
name: 'VIEWER: Combine report output'
|
||||
@@ -71,17 +75,17 @@ jobs:
|
||||
steps:
|
||||
# Checkout code and ALL Git Tags
|
||||
- checkout
|
||||
- install_bun
|
||||
- install_pnpm
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: bun install --no-save
|
||||
command: pnpm install --frozen-lockfile
|
||||
# Build & Test
|
||||
- run:
|
||||
name: 'Perform the versioning before build'
|
||||
command: bun ./version.mjs
|
||||
command: node ./version.mjs
|
||||
- run:
|
||||
name: 'Build the OHIF Viewer'
|
||||
command: bun run build
|
||||
command: pnpm run build
|
||||
no_output_timeout: 45m
|
||||
- run:
|
||||
name: 'Upload SourceMaps, Send Deploy Notification'
|
||||
@@ -107,58 +111,55 @@ jobs:
|
||||
<<: *defaults
|
||||
resource_class: large
|
||||
steps:
|
||||
- install_bun
|
||||
- install_pnpm
|
||||
# Checkout code and ALL Git Tags
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: ~/repo
|
||||
# SECURITY AUDIT
|
||||
# SECURITY AUDIT - only when pnpm-lock.yaml has changed
|
||||
- run:
|
||||
name: 'Security Audit - High Risk Vulnerabilities'
|
||||
command: |
|
||||
echo "🔍 Running bun audit for security vulnerabilities..."
|
||||
git fetch origin master 2>/dev/null || true
|
||||
BASE_REF=$(git merge-base HEAD origin/master 2>/dev/null)
|
||||
if [[ -z "$BASE_REF" ]]; then
|
||||
echo "Could not determine base ref (e.g. shallow clone or no origin/master), skipping security audit."
|
||||
exit 0
|
||||
fi
|
||||
CHANGED_FILES=$(git diff --name-only origin/master...HEAD 2>/dev/null || echo "")
|
||||
if ! echo "$CHANGED_FILES" | grep -qx 'pnpm-lock.yaml'; then
|
||||
echo "pnpm-lock.yaml unchanged - skipping security audit."
|
||||
exit 0
|
||||
fi
|
||||
echo "pnpm-lock.yaml changed - running pnpm audit for security vulnerabilities..."
|
||||
echo "Checking for HIGH-RISK vulnerabilities..."
|
||||
|
||||
# Define ignored vulnerabilities with comments
|
||||
IGNORED_VULNS=(
|
||||
"GHSA-5j98-mcp5-4vw2" # CVE-2025-64756 - glob is not used on the command line
|
||||
"GHSA-8qq5-rm4j-mr97" # CVE-2026-23745 - limited to build/dev environments
|
||||
"GHSA-r6q2-hw4h-h46w" # CVE-2026-23950 - limited to build/dev environments
|
||||
"GHSA-34x7-hfp2-rc4v" # CVE-2026-24842 - limited to build/dev environments
|
||||
)
|
||||
|
||||
# Build ignore flags
|
||||
IGNORE_FLAGS=""
|
||||
for vuln in "${IGNORED_VULNS[@]}"; do
|
||||
IGNORE_FLAGS="$IGNORE_FLAGS --ignore=$vuln"
|
||||
done
|
||||
|
||||
if bun audit $IGNORE_FLAGS --audit-level high; then
|
||||
echo "✅ No high-risk vulnerabilities found"
|
||||
echo "🎉 Security audit passed!"
|
||||
if pnpm audit --audit-level high; then
|
||||
echo "No high-risk vulnerabilities found"
|
||||
echo "Security audit passed!"
|
||||
else
|
||||
echo ""
|
||||
echo "❌ HIGH-RISK VULNERABILITIES DETECTED!"
|
||||
echo "HIGH-RISK VULNERABILITIES DETECTED!"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
echo "🔧 To fix these issues:"
|
||||
echo " 1. Run: bun audit"
|
||||
echo "To fix these issues:"
|
||||
echo " 1. Run: pnpm audit"
|
||||
echo " 2. Review the vulnerability details"
|
||||
echo " 3. Update affected packages to secure versions"
|
||||
echo " 4. Test your changes"
|
||||
echo " 5. Re-run: bun audit --audit-level high"
|
||||
echo " 5. Re-run: pnpm audit --audit-level high"
|
||||
echo ""
|
||||
echo "📋 Full audit report:"
|
||||
echo "Full audit report:"
|
||||
|
||||
bun audit $IGNORE_FLAGS --audit-level low || true
|
||||
pnpm audit || true
|
||||
|
||||
echo ""
|
||||
echo "❌ This build cannot proceed until high-risk vulnerabilities are resolved."
|
||||
echo "This build cannot proceed until high-risk vulnerabilities are resolved."
|
||||
exit 1
|
||||
fi
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: bun install --frozen-lockfile
|
||||
command: pnpm install
|
||||
- run:
|
||||
name: Avoid hosts unknown for github
|
||||
command: |
|
||||
@@ -169,28 +170,34 @@ jobs:
|
||||
git config --global user.name "ohif-bot"
|
||||
- run:
|
||||
name: Authenticate with NPM registry
|
||||
command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/repo/.npmrc
|
||||
# Write the auth token to npm's per-user config (~/.npmrc), not the
|
||||
# repo root. publish-package.mjs chdir's into each package dir to run
|
||||
# `npm publish`, and npm only reads the project .npmrc from that dir
|
||||
# plus the user .npmrc from $HOME -- it never sees ~/repo/.npmrc, so a
|
||||
# root-level token yields ENEEDAUTH. Using ~/.npmrc also avoids
|
||||
# clobbering the committed workspace-config .npmrc (node-linker=hoisted).
|
||||
command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
|
||||
- run:
|
||||
name: build half of the packages (to avoid out of memory in circleci)
|
||||
command: |
|
||||
bun run build:package-all
|
||||
pnpm run build:package-all
|
||||
- run:
|
||||
name: build the other half of the packages
|
||||
command: |
|
||||
bun run build:package-all-1
|
||||
pnpm run build:package-all-1
|
||||
|
||||
NPM_PUBLISH:
|
||||
<<: *defaults
|
||||
resource_class: large
|
||||
steps:
|
||||
- install_bun
|
||||
- install_pnpm
|
||||
# Checkout code and ALL Git Tags
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: ~/repo
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: bun install --no-save
|
||||
command: pnpm install --frozen-lockfile
|
||||
- run:
|
||||
name: Avoid hosts unknown for github
|
||||
command: |
|
||||
@@ -201,15 +208,21 @@ jobs:
|
||||
git config --global user.name "ohif-bot"
|
||||
- run:
|
||||
name: Authenticate with NPM registry
|
||||
command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/repo/.npmrc
|
||||
# Write the auth token to npm's per-user config (~/.npmrc), not the
|
||||
# repo root. publish-package.mjs chdir's into each package dir to run
|
||||
# `npm publish`, and npm only reads the project .npmrc from that dir
|
||||
# plus the user .npmrc from $HOME -- it never sees ~/repo/.npmrc, so a
|
||||
# root-level token yields ENEEDAUTH. Using ~/.npmrc also avoids
|
||||
# clobbering the committed workspace-config .npmrc (node-linker=hoisted).
|
||||
command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
|
||||
- run:
|
||||
name: build half of the packages (to avoid out of memory in circleci)
|
||||
command: |
|
||||
bun run build:package-all
|
||||
pnpm run build:package-all
|
||||
- run:
|
||||
name: build the other half of the packages
|
||||
command: |
|
||||
bun run build:package-all-1
|
||||
pnpm run build:package-all-1
|
||||
- run:
|
||||
name: increase min time out
|
||||
command: |
|
||||
@@ -221,14 +234,20 @@ jobs:
|
||||
- run:
|
||||
name: publish package versions
|
||||
command: |
|
||||
bun ./publish-version.mjs
|
||||
node ./publish-version.mjs
|
||||
- run:
|
||||
name: Again set the NPM registry (was deleted in the version script)
|
||||
command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/repo/.npmrc
|
||||
name: Re-assert the NPM auth token before publishing
|
||||
# Write the auth token to npm's per-user config (~/.npmrc), not the
|
||||
# repo root. publish-package.mjs chdir's into each package dir to run
|
||||
# `npm publish`, and npm only reads the project .npmrc from that dir
|
||||
# plus the user .npmrc from $HOME -- it never sees ~/repo/.npmrc, so a
|
||||
# root-level token yields ENEEDAUTH. Using ~/.npmrc also avoids
|
||||
# clobbering the committed workspace-config .npmrc (node-linker=hoisted).
|
||||
command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
|
||||
- run:
|
||||
name: publish package dist
|
||||
command: |
|
||||
bun ./publish-package.mjs
|
||||
node ./publish-package.mjs
|
||||
- persist_to_workspace:
|
||||
root: ~/repo
|
||||
paths:
|
||||
@@ -250,8 +269,11 @@ jobs:
|
||||
if [[ ! -e version.txt ]]; then
|
||||
exit 0
|
||||
else
|
||||
# Remove npm config
|
||||
rm -f ./.npmrc
|
||||
# Restore the committed .npmrc (pnpm workspace config such as
|
||||
# node-linker=hoisted). NPM_PUBLISH overwrote it with a publish
|
||||
# auth token, but the Dockerfile COPYs .npmrc for the in-image
|
||||
# pnpm install, so it needs the config file present and token-free.
|
||||
git checkout -- .npmrc
|
||||
# Set our version number using vars
|
||||
export IMAGE_VERSION=$(cat version.txt)
|
||||
export IMAGE_VERSION_FULL=v$IMAGE_VERSION
|
||||
@@ -284,8 +306,11 @@ jobs:
|
||||
if [[ ! -e version.txt ]]; then
|
||||
exit 0
|
||||
else
|
||||
# Remove npm config
|
||||
rm -f ./.npmrc
|
||||
# Restore the committed .npmrc (pnpm workspace config such as
|
||||
# node-linker=hoisted). NPM_PUBLISH overwrote it with a publish
|
||||
# auth token, but the Dockerfile COPYs .npmrc for the in-image
|
||||
# pnpm install, so it needs the config file present and token-free.
|
||||
git checkout -- .npmrc
|
||||
# Set our version number using vars
|
||||
export IMAGE_VERSION=$(cat version.txt)
|
||||
export IMAGE_VERSION_FULL=v$IMAGE_VERSION
|
||||
@@ -322,7 +347,11 @@ jobs:
|
||||
exit 0
|
||||
else
|
||||
echo "Building and pushing Docker image from the master branch (beta releases)"
|
||||
rm -f ./.npmrc
|
||||
# Restore the committed .npmrc (pnpm workspace config such as
|
||||
# node-linker=hoisted). NPM_PUBLISH overwrote it with a publish
|
||||
# auth token, but the Dockerfile COPYs .npmrc for the in-image
|
||||
# pnpm install, so it needs the config file present and token-free.
|
||||
git checkout -- .npmrc
|
||||
|
||||
# Set our version number using vars
|
||||
export IMAGE_VERSION=$(cat version.txt)
|
||||
@@ -356,7 +385,11 @@ jobs:
|
||||
exit 0
|
||||
else
|
||||
echo "Building and pushing ARM64 Docker image from the master branch (beta releases)"
|
||||
rm -f ./.npmrc
|
||||
# Restore the committed .npmrc (pnpm workspace config such as
|
||||
# node-linker=hoisted). NPM_PUBLISH overwrote it with a publish
|
||||
# auth token, but the Dockerfile COPYs .npmrc for the in-image
|
||||
# pnpm install, so it needs the config file present and token-free.
|
||||
git checkout -- .npmrc
|
||||
# Set our version number using vars
|
||||
export IMAGE_VERSION=$(cat version.txt)
|
||||
export IMAGE_VERSION_FULL=v$IMAGE_VERSION
|
||||
@@ -374,10 +407,20 @@ jobs:
|
||||
resource_class: large
|
||||
parallelism: 8
|
||||
steps:
|
||||
- install_pnpm
|
||||
- run:
|
||||
name: Install System Dependencies
|
||||
command: |
|
||||
sudo apt-get update
|
||||
# CircleCI's base image registers third-party apt sources (git-lfs via
|
||||
# packagecloud, git-core PPA via launchpad) that periodically hang
|
||||
# `apt-get update`. The Cypress libs below all come from the Ubuntu
|
||||
# archive, so drop those sources and bound the update with timeouts +
|
||||
# retries so a slow mirror can't stall the job indefinitely.
|
||||
sudo rm -f /etc/apt/sources.list.d/*git* || true
|
||||
sudo apt-get update \
|
||||
-o Acquire::Retries=3 \
|
||||
-o Acquire::http::Timeout=20 \
|
||||
-o Acquire::https::Timeout=20
|
||||
sudo apt-get install -y xvfb libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6
|
||||
- run:
|
||||
name: Start Xvfb
|
||||
@@ -387,11 +430,15 @@ jobs:
|
||||
name: Export Display Variable
|
||||
command: export DISPLAY=:99
|
||||
- cypress/install:
|
||||
install-command: yarn install --frozen-lockfile --no-save
|
||||
install-command: pnpm install
|
||||
- cypress/run-tests:
|
||||
# CI runs headless under Xvfb with no GPU, so Electron uses software
|
||||
# WebGL. Newer Chromium deprecated that implicit fallback (canvas
|
||||
# rendering degrades and races with element clicks). ELECTRON_EXTRA_LAUNCH_ARGS
|
||||
# is the reliable way to pass the opt-in flag to Cypress's Electron browser.
|
||||
cypress-command: |
|
||||
npx wait-on@latest http://localhost:3000 && cd platform/app && npx cypress run --record --parallel
|
||||
start-command: yarn run test:data && yarn run test:e2e:serve
|
||||
npx wait-on@latest http://localhost:3000 && cd platform/app && ELECTRON_EXTRA_LAUNCH_ARGS="--enable-unsafe-swiftshader" npx cypress run --record --parallel
|
||||
start-command: pnpm run test:data && pnpm run test:e2e:serve
|
||||
|
||||
DOCKER_MULTIARCH_MANIFEST:
|
||||
<<: *defaults
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
version: 2
|
||||
enable-beta-ecosystems: true
|
||||
updates:
|
||||
- package-ecosystem: 'bun'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'daily'
|
||||
labels: ['dependencies']
|
||||
commit-message:
|
||||
prefix: 'chore'
|
||||
include: 'scope'
|
||||
- package-ecosystem: 'npm'
|
||||
# Disable all pull requests for npm/pnpm version updates.
|
||||
open-pull-requests-limit: 0
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'daily'
|
||||
|
||||
@@ -21,16 +21,29 @@ jobs:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
bun-version: 1.2.23
|
||||
- uses: actions/setup-node@v4
|
||||
persist-credentials: false
|
||||
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: 20 # Or your desired Node version
|
||||
node-version: 24
|
||||
cache: pnpm
|
||||
|
||||
- name: Install root dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
- name: Configure git for private repos
|
||||
run: git config --global url."https://${GITHUB_TOKEN}:x-oauth-basic@github.com/".insteadOf ssh://git@github.com/
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install dependencies
|
||||
# Internal @ohif/* deps are workspace:* in the committed manifests and the
|
||||
# lockfile records them as links, so pnpm-lock.yaml stays in sync across
|
||||
# version bumps and a frozen install passes. Frozen is the right choice
|
||||
# for a deploy job: it fails fast if a PR ever changed a real dependency
|
||||
# without committing the lockfile update, instead of silently reconciling.
|
||||
# (Exact versions appear only in published tarballs, where pnpm publish
|
||||
# rewrites workspace:* at pack time -- not publish-version.mjs.)
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
# Removed Playwright tests and coverage generation steps
|
||||
|
||||
@@ -44,47 +57,44 @@ jobs:
|
||||
# Note: This relies on the merge commit being directly pushed to main
|
||||
PR_DATA=$(gh pr list --state merged --search "$MERGE_COMMIT_SHA" --json number,headRefOid --jq '.[0]')
|
||||
if [ -z "$PR_DATA" ]; then
|
||||
echo "Could not find merged PR for commit $MERGE_COMMIT_SHA."
|
||||
# Decide how to handle - fail, or maybe generate coverage now?
|
||||
# For now, let's fail.
|
||||
exit 1
|
||||
echo "::warning::Could not find merged PR for commit $MERGE_COMMIT_SHA. Skipping coverage embedding."
|
||||
echo "coverage_found=false" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
PR_HEAD_SHA=$(echo "$PR_DATA" | jq -r '.headRefOid')
|
||||
PR_NUMBER=$(echo "$PR_DATA" | jq -r '.number')
|
||||
echo "Found PR Number: $PR_NUMBER"
|
||||
echo "Found PR Head SHA: $PR_HEAD_SHA"
|
||||
|
||||
# Find the latest workflow run ID for the playwright workflow on the PR head commit
|
||||
# Uses the workflow file name 'playwright.yml'
|
||||
# Remove the --status success flag to find any run
|
||||
RUN_ID=$(gh run list --workflow playwright.yml --commit "$PR_HEAD_SHA" --event pull_request --json databaseId --jq '.[0].databaseId')
|
||||
# Find the latest *successful* playwright.yml run for the PR head commit so we
|
||||
# never embed coverage from a failed/incomplete run.
|
||||
RUN_ID=$(gh run list --workflow playwright.yml --commit "$PR_HEAD_SHA" --event pull_request --status success --json databaseId --jq '.[0].databaseId')
|
||||
|
||||
if [ -z "$RUN_ID" ]; then
|
||||
echo "Could not find any 'playwright.yml' run for PR $PR_NUMBER (Head SHA: $PR_HEAD_SHA)."
|
||||
# Decide how to handle - maybe try finding the artifact from the merge commit run if that exists?
|
||||
# For now, let's fail.
|
||||
exit 1
|
||||
echo "::warning::Could not find a successful 'playwright.yml' run for PR $PR_NUMBER (Head SHA: $PR_HEAD_SHA). Skipping coverage embedding."
|
||||
echo "coverage_found=false" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
echo "Found Run ID: $RUN_ID"
|
||||
echo "run_id=$RUN_ID" >> $GITHUB_OUTPUT
|
||||
echo "coverage_found=true" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Download coverage artifact from PR run
|
||||
if: steps.find_pr_run.outputs.coverage_found == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
mkdir -p ./coverage-artifact
|
||||
gh run download ${{ steps.find_pr_run.outputs.run_id }} -n coverage-report-pr --dir ./coverage-artifact
|
||||
# Check if download was successful (e.g., check if files exist)
|
||||
if [ ! -f ./coverage-artifact/base.css ]; then
|
||||
echo "Failed to download or find expected files in artifact 'coverage-report-pr' from run ${{ steps.find_pr_run.outputs.run_id }}."
|
||||
# Verify the artifact contains an HTML coverage report rather than checking a single asset
|
||||
if [ -z "$(ls -A ./coverage-artifact)" ] || ! ls ./coverage-artifact/*.html >/dev/null 2>&1; then
|
||||
echo "Failed to download or find an HTML coverage report in artifact 'coverage-report-pr' from run ${{ steps.find_pr_run.outputs.run_id }}."
|
||||
exit 1
|
||||
fi
|
||||
echo "Artifact downloaded successfully."
|
||||
|
||||
- name: Install docs dependencies
|
||||
run: cd platform/docs && bun install
|
||||
|
||||
- name: Copy coverage to docs static directory
|
||||
if: steps.find_pr_run.outputs.coverage_found == 'true'
|
||||
run: |
|
||||
# Copy files from the downloaded artifact directory
|
||||
mkdir -p platform/docs/static/coverage
|
||||
@@ -99,12 +109,16 @@ jobs:
|
||||
cp ./coverage-artifact/sorter.js platform/docs/static/
|
||||
|
||||
- name: Build docs
|
||||
run: cd platform/docs && bun run build
|
||||
run: pnpm --filter ohif-docs run build
|
||||
|
||||
- name: Deploy to Netlify
|
||||
run: |
|
||||
cd platform/docs
|
||||
npx netlify-cli deploy --dir=./build --prod
|
||||
# The docs are already built by the "Build docs" step above, so pass
|
||||
# --no-build: `netlify deploy` runs the build command by default, which
|
||||
# would otherwise pick up the repo-root netlify.toml (configured for the
|
||||
# main viewer app) and build the wrong project. --dir is resolved
|
||||
# relative to the repo root (the netlify.toml base), not the cwd, so it
|
||||
# must be the full path to the prebuilt docs output.
|
||||
run: npx netlify-cli deploy --dir=platform/docs/build --prod --no-build
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
||||
@@ -55,7 +55,9 @@ jobs:
|
||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
# Add any setup steps before running the `github/codeql-action/init` action.
|
||||
# This includes steps like installing compilers or runtimes (`actions/setup-node`
|
||||
@@ -65,7 +67,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
uses: github/codeql-action/init@dd903d2e4f5405488e5ef1422510ee31c8b32357 # v3.36.2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
@@ -93,6 +95,6 @@ jobs:
|
||||
exit 1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@dd903d2e4f5405488e5ef1422510ee31c8b32357 # v3.36.2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
@@ -2,6 +2,19 @@ name: Playwright Tests
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master, release/*]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
cs3d_ref:
|
||||
description: >-
|
||||
CS3D branch (e.g. main, origin:feat/foo) or version (e.g. 4.18.2, 4.19+, 4.x). Only used
|
||||
when ohif-integration label is present or via workflow_dispatch.
|
||||
required: false
|
||||
default: '4.19+'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
issues: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -9,50 +22,210 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
playwright-tests:
|
||||
timeout-minutes: 60
|
||||
runs-on: self-hosted
|
||||
timeout-minutes: 120
|
||||
runs-on: [self-hosted, nashua]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [20]
|
||||
node-version: [24]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
bun-version: 1.2.23
|
||||
- uses: actions/setup-node@v4
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install Yarn
|
||||
run: npm install -g yarn@1.22.22
|
||||
# No `cache: pnpm`: this is a self-hosted runner with a persistent
|
||||
# pnpm store on local disk. The Actions cache doesn't preserve the
|
||||
# pnpm self-install's links faithfully, dropping pnpm/dist/worker.js
|
||||
# and breaking `pnpm install` with MODULE_NOT_FOUND.
|
||||
# Install pnpm via Corepack instead of pnpm/action-setup. The action's
|
||||
# self-installer is a JS action run under the runner's bundled
|
||||
# externals/node{version} and derives the `npm` path from that runtime — which
|
||||
# on this self-hosted runner is corrupted (Cannot find module
|
||||
# '../lib/cli.js'), so it dies regardless of `standalone:true`. Corepack
|
||||
# ships inside the Node that setup-node just installed, reads the pinned
|
||||
# `packageManager` (pnpm@11.5.2) from package.json, and fetches pnpm via
|
||||
# Node's own https — it never invokes the npm CLI.
|
||||
- name: Enable Corepack (pnpm)
|
||||
shell: bash
|
||||
run: |
|
||||
corepack enable
|
||||
corepack prepare --activate
|
||||
|
||||
# ── CS3D integration: detect label and ref type ──────────────────────
|
||||
- name: Check for CS3D integration label
|
||||
id: cs3d-check
|
||||
run: bash .scripts/ci/cs3d-check-integration.sh
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
CS3D_REF_INPUT: ${{ github.event.inputs.cs3d_ref || '4.19+' }}
|
||||
REPO: ${{ github.repository }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
|
||||
- name: Detect CS3D ref type
|
||||
id: cs3d-ref
|
||||
if: steps.cs3d-check.outputs.enabled == 'true'
|
||||
run: |
|
||||
REF="${CS3D_REF}"
|
||||
if [[ "$REF" =~ ^[0-9]+\.[0-9x]+\+?(\.[0-9x]+)?(-[a-zA-Z0-9._]+)?$ ]]; then
|
||||
echo "type=version" >> "$GITHUB_OUTPUT"
|
||||
RESOLVED=$(node .scripts/cs3d-resolve-version.mjs "$REF")
|
||||
echo "version=$RESOLVED" >> "$GITHUB_OUTPUT"
|
||||
echo "::notice::CS3D version: $REF -> $RESOLVED"
|
||||
else
|
||||
echo "type=branch" >> "$GITHUB_OUTPUT"
|
||||
echo "::notice::CS3D branch: $REF"
|
||||
fi
|
||||
env:
|
||||
CS3D_REF: ${{ steps.cs3d-check.outputs.cs3d_ref }}
|
||||
|
||||
# ── CS3D branch path: clone and build before OHIF install ───────────
|
||||
- name: Clone CS3D
|
||||
if: steps.cs3d-check.outputs.enabled == 'true' && steps.cs3d-ref.outputs.type == 'branch'
|
||||
run: |
|
||||
REF="${CS3D_REF}"
|
||||
if [[ "$REF" == *:* ]]; then
|
||||
REPO="https://github.com/${REF%%:*}/cornerstone3D.git"
|
||||
BRANCH="${REF#*:}"
|
||||
else
|
||||
REPO="https://github.com/cornerstonejs/cornerstone3D.git"
|
||||
BRANCH="$REF"
|
||||
fi
|
||||
echo "::notice::Cloning CS3D from $REPO branch $BRANCH"
|
||||
git clone --depth 1 --branch "$BRANCH" "$REPO" libs/@cornerstonejs
|
||||
env:
|
||||
CS3D_REF: ${{ steps.cs3d-check.outputs.cs3d_ref }}
|
||||
|
||||
- name: Install & Build CS3D
|
||||
if: steps.cs3d-check.outputs.enabled == 'true' && steps.cs3d-ref.outputs.type == 'branch'
|
||||
working-directory: libs/@cornerstonejs
|
||||
run: pnpm install --frozen-lockfile && pnpm run build:esm
|
||||
|
||||
# ── Common: install OHIF dependencies ───────────────────────────────
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
# ── CS3D branch path: link packages after OHIF install ──────────────
|
||||
- name: Link CS3D packages
|
||||
if: steps.cs3d-check.outputs.enabled == 'true' && steps.cs3d-ref.outputs.type == 'branch'
|
||||
working-directory: libs/@cornerstonejs
|
||||
run: node scripts/link-ohif-cornerstone-node-modules.mjs "$GITHUB_WORKSPACE"
|
||||
|
||||
# ── CS3D version path: update versions after OHIF install ───────────
|
||||
- name: Set CS3D version
|
||||
if: steps.cs3d-check.outputs.enabled == 'true' && steps.cs3d-ref.outputs.type == 'version'
|
||||
run: |
|
||||
node .scripts/cs3d-set-version.mjs "${CS3D_VERSION}"
|
||||
pnpm install --no-frozen-lockfile
|
||||
env:
|
||||
CS3D_VERSION: ${{ steps.cs3d-ref.outputs.version }}
|
||||
|
||||
# ── Common: run tests ───────────────────────────────────────────────
|
||||
- name: Install Playwright browsers
|
||||
run: npx playwright install
|
||||
# Only chromium is used (see playwright.config.ts and tests/globalSetup.ts);
|
||||
# firefox/webkit projects are commented out. Scoping the install to chromium
|
||||
# avoids downloading + dep-validating browsers we never launch (the WebKit
|
||||
# validation is what surfaces the "missing libwoff1/libflite1/..." error on
|
||||
# hosts without those libs).
|
||||
run: npx playwright install chromium
|
||||
- name: Run Playwright tests
|
||||
run: |
|
||||
export NODE_OPTIONS="--max_old_space_size=10192"
|
||||
bun run test:e2e:coverage
|
||||
pnpm run test:e2e:coverage
|
||||
|
||||
# ── Common: collect test results and coverage ───────────────────────
|
||||
- name: Create directory of test results
|
||||
if: ${{ !cancelled() }}
|
||||
run: |
|
||||
mkdir -p packaged-test-results
|
||||
cp -r ./tests/test-results packaged-test-results/ || true
|
||||
cp ./tests/playwright-report.json packaged-test-results/ || true
|
||||
cp -r ./tests/playwright-report packaged-test-results/ || true
|
||||
- name: Upload directory of test results artifact
|
||||
if: ${{ !cancelled() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: playwright-results
|
||||
path: packaged-test-results/
|
||||
retention-days: 5
|
||||
- name: create the coverage report
|
||||
run: |
|
||||
bun nyc report --reporter=lcov --reporter=text
|
||||
pnpm exec nyc report --reporter=lcov --reporter=text
|
||||
- name: Upload the coverage report to GitHub Actions Artifacts
|
||||
if: ${{ !cancelled() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: coverage-report-pr
|
||||
path: coverage
|
||||
retention-days: 3
|
||||
|
||||
# ── CS3D: build and deploy preview to Netlify ───────────────────────
|
||||
- name: Log build context (OHIF/CS3D branch and version for build diagnosis)
|
||||
if: steps.cs3d-check.outputs.enabled == 'true'
|
||||
run: |
|
||||
if [[ "$CS3D_REF_TYPE" == "branch" ]]; then
|
||||
echo "::notice::Build type: ohif-downstream | OHIF: ${{ github.repository }}@${{ github.ref }} (${{ github.sha }}) | CS3D: branch ${{ steps.cs3d-check.outputs.cs3d_ref }}"
|
||||
else
|
||||
echo "::notice::Build type: ohif-upstream | OHIF: ${{ github.repository }}@${{ github.ref }} (${{ github.sha }}) | CS3D: version ${{ steps.cs3d-ref.outputs.version }}"
|
||||
fi
|
||||
node .scripts/log-build-context.mjs
|
||||
env:
|
||||
BUILD_TYPE:
|
||||
${{ steps.cs3d-ref.outputs.type == 'branch' && 'ohif-downstream' || 'ohif-upstream' }}
|
||||
CS3D_REF_TYPE: ${{ steps.cs3d-ref.outputs.type }}
|
||||
|
||||
- name: Build OHIF viewer (CS3D preview)
|
||||
if: steps.cs3d-check.outputs.enabled == 'true'
|
||||
run: pnpm run build:ci
|
||||
|
||||
- name: Deploy CS3D preview to Netlify
|
||||
if: steps.cs3d-check.outputs.enabled == 'true'
|
||||
run: |
|
||||
RESULT=$(npx netlify-cli deploy --dir=platform/app/dist --alias="cs3d-pr-${PR_NUM}" --json --filter=@ohif/app) || {
|
||||
echo "::error::Netlify deploy command failed"
|
||||
exit 1
|
||||
}
|
||||
URL=$(echo "$RESULT" | jq -r '.deploy_url')
|
||||
if [[ -z "$URL" || "$URL" == "null" ]]; then
|
||||
echo "::error::Netlify deploy did not return a valid URL"
|
||||
echo "$RESULT"
|
||||
exit 1
|
||||
fi
|
||||
echo "::notice::CS3D preview deployed: $URL"
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
||||
PR_NUM: ${{ github.event.pull_request.number || 'manual' }}
|
||||
|
||||
# ── CS3D: log results ───────────────────────────────────────────────
|
||||
- name: Log CS3D build used
|
||||
if: steps.cs3d-check.outputs.enabled == 'true'
|
||||
run: |
|
||||
if [[ "$CS3D_REF_TYPE" == "branch" ]]; then
|
||||
echo "::notice::CS3D integration PASSED with branch ${CS3D_REF} (linked from libs/@cornerstonejs)"
|
||||
else
|
||||
echo "::notice::CS3D integration PASSED with @cornerstonejs/*@${CS3D_VERSION}"
|
||||
fi
|
||||
env:
|
||||
CS3D_REF_TYPE: ${{ steps.cs3d-ref.outputs.type }}
|
||||
CS3D_REF: ${{ steps.cs3d-check.outputs.cs3d_ref }}
|
||||
CS3D_VERSION: ${{ steps.cs3d-ref.outputs.version }}
|
||||
|
||||
# ── Separate job: block merge when using a CS3D branch ─────────────
|
||||
cs3d-branch-merge-guard:
|
||||
name: 'CS3D Branch Merge Guard'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for CS3D branch usage
|
||||
run: bash .scripts/ci/cs3d-branch-merge-guard.sh
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
CS3D_REF_INPUT: ${{ github.event.inputs.cs3d_ref || '4.19+' }}
|
||||
REPO: ${{ github.repository }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
+11
@@ -1,6 +1,7 @@
|
||||
# Packages
|
||||
node_modules
|
||||
.cursor/
|
||||
.claude/
|
||||
.nyc_output/
|
||||
# Output
|
||||
build
|
||||
@@ -44,6 +45,7 @@ videos/
|
||||
|
||||
# autogenerated files
|
||||
platform/app/src/pluginImports.js
|
||||
CLAUDE.md
|
||||
/Viewers.iml
|
||||
platform/app/.recipes/Nginx-Dcm4Chee/logs/*
|
||||
platform/app/.recipes/OpenResty-Orthanc/logs/*
|
||||
@@ -61,5 +63,14 @@ tests/playwright-report/
|
||||
|
||||
**/.claude/settings.local.json
|
||||
|
||||
# cornerstone3D local linking
|
||||
libs/
|
||||
|
||||
# Backup files
|
||||
*~
|
||||
|
||||
# cornerstone3D local linking
|
||||
libs/
|
||||
link-cs3d.js
|
||||
unlink-cs3d.js
|
||||
auth.json
|
||||
@@ -6,27 +6,21 @@ cd "$(dirname "$0")"
|
||||
cd .. # Up to project root
|
||||
|
||||
# Helpful to verify which versions we're using
|
||||
echo 'My yarn version is... '
|
||||
echo 'My pnpm version is... '
|
||||
|
||||
yarn -v
|
||||
pnpm -v
|
||||
node -v
|
||||
|
||||
# Build && Move PWA Output
|
||||
yarn run build:ci
|
||||
pnpm run build:ci
|
||||
mkdir -p ./.netlify/www/pwa
|
||||
mv platform/app/dist/* .netlify/www/pwa -v
|
||||
echo 'Web application built and copied'
|
||||
|
||||
# Build && Move Docusaurus Output (for the docs themselves)
|
||||
cd platform/docs
|
||||
yarn install --frozen-lockfile
|
||||
yarn run build
|
||||
cd ../..
|
||||
pnpm --filter ohif-docs run build
|
||||
mkdir -p ./.netlify/www/docs
|
||||
mv platform/docs/build/* .netlify/www/docs -v
|
||||
echo 'Docs built (docusaurus) and copied'
|
||||
|
||||
# Cache all of the node_module dependencies in
|
||||
# extensions, modules, and platform packages
|
||||
yarn run lerna:cache
|
||||
echo 'Nothing left to see here. Go home, folks.'
|
||||
@@ -2,9 +2,8 @@
|
||||
"name": "root",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=14",
|
||||
"npm": ">=6",
|
||||
"yarn": ">=1.16.0"
|
||||
"node": ">=24",
|
||||
"pnpm": ">=11"
|
||||
},
|
||||
"scripts": {
|
||||
"deploy": "netlify deploy --prod --dir ./../platform/app/dist"
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
20.9.0
|
||||
24
|
||||
@@ -0,0 +1,5 @@
|
||||
node-linker=hoisted
|
||||
strict-peer-dependencies=false
|
||||
link-workspace-packages=true
|
||||
prefer-workspace-packages=true
|
||||
manage-package-manager-versions=false
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env bash
|
||||
# CS3D branch merge guard: blocks merge when tests ran against a CS3D branch (not a version).
|
||||
# Exits 0 when merge is allowed or guard is skipped; exits 1 when merge must be blocked.
|
||||
#
|
||||
# Required env: GH_TOKEN, EVENT_NAME, REPO, PR_NUMBER
|
||||
# Optional env: CS3D_REF_INPUT (for workflow_dispatch, default 4.19+)
|
||||
|
||||
set -e
|
||||
|
||||
if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then
|
||||
echo "::notice::workflow_dispatch — no merge to block, skipping guard."
|
||||
exit 0
|
||||
elif [[ "$EVENT_NAME" == "pull_request" ]]; then
|
||||
LABELS=$(gh api "repos/${REPO}/issues/${PR_NUMBER}/labels" --jq '.[].name')
|
||||
if echo "$LABELS" | grep -q "ohif-integration"; then
|
||||
ENABLED=true
|
||||
CS3D_REF=$(gh api "repos/${REPO}/pulls/${PR_NUMBER}" --jq '.body' \
|
||||
| sed -n 's/^[[:space:]]*CS3D_REF:[[:space:]]*\([^[:space:]]*\).*/\1/p' | head -1)
|
||||
if [[ -z "$CS3D_REF" ]]; then
|
||||
CS3D_REF="4.19+"
|
||||
fi
|
||||
else
|
||||
ENABLED=false
|
||||
fi
|
||||
else
|
||||
ENABLED=false
|
||||
fi
|
||||
|
||||
if [[ "$ENABLED" != "true" ]]; then
|
||||
echo "::notice::No ohif-integration label — skipping merge guard."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if the ref is a branch (not a version)
|
||||
if [[ "$CS3D_REF" =~ ^[0-9]+\.[0-9x]+\+?(\.[0-9x]+)?(-[a-zA-Z0-9._]+)?$ ]]; then
|
||||
echo "::notice::CS3D ref '$CS3D_REF' is a version — merge allowed."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "::error::Tests ran against CS3D branch '${CS3D_REF}' — this build cannot be merged."
|
||||
echo "::error::Re-run with a published CS3D version (e.g. 4.19+) before merging."
|
||||
exit 1
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
# CS3D integration check: detects ohif-integration label and parses CS3D_REF.
|
||||
# Writes to GITHUB_OUTPUT: enabled (true|false), cs3d_ref (when enabled).
|
||||
#
|
||||
# Required env: GH_TOKEN, EVENT_NAME, REPO, PR_NUMBER, GITHUB_OUTPUT
|
||||
# Optional env: CS3D_REF_INPUT (for workflow_dispatch, default 4.19+)
|
||||
|
||||
set -e
|
||||
|
||||
if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then
|
||||
echo "enabled=true" >> "$GITHUB_OUTPUT"
|
||||
echo "cs3d_ref=${CS3D_REF_INPUT:-4.19+}" >> "$GITHUB_OUTPUT"
|
||||
elif [[ "$EVENT_NAME" == "pull_request" ]]; then
|
||||
LABELS=$(gh api "repos/${REPO}/issues/${PR_NUMBER}/labels" --jq '.[].name')
|
||||
if echo "$LABELS" | grep -q "ohif-integration"; then
|
||||
echo "enabled=true" >> "$GITHUB_OUTPUT"
|
||||
REF=$(gh api "repos/${REPO}/pulls/${PR_NUMBER}" --jq '.body' \
|
||||
| sed -n 's/^[[:space:]]*CS3D_REF:[[:space:]]*\([^[:space:]]*\).*/\1/p' | head -1)
|
||||
if [[ -z "$REF" ]]; then
|
||||
REF="4.19+"
|
||||
fi
|
||||
echo "cs3d_ref=${REF}" >> "$GITHUB_OUTPUT"
|
||||
echo "::notice::CS3D ref from PR body: ${REF}"
|
||||
else
|
||||
echo "enabled=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
else
|
||||
echo "enabled=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
@@ -0,0 +1,55 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { execSync } from 'node:child_process';
|
||||
|
||||
const workflowPath = path.resolve(
|
||||
process.cwd(),
|
||||
'libs',
|
||||
'@cornerstonejs',
|
||||
'.github',
|
||||
'workflows',
|
||||
'ohif-downstream.yml'
|
||||
);
|
||||
|
||||
if (!fs.existsSync(workflowPath)) {
|
||||
console.error(`[cs3d:check] Workflow file not found: ${workflowPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const workflowText = fs.readFileSync(workflowPath, 'utf8');
|
||||
const ohifRefMatch = workflowText.match(/^\s*OHIF_REF:\s*["']?([^"'\r\n]+)["']?\s*$/m);
|
||||
|
||||
if (!ohifRefMatch) {
|
||||
console.error('[cs3d:check] Could not find OHIF_REF in ohif-downstream workflow.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const expectedBranch = ohifRefMatch[1].trim();
|
||||
let currentBranch = '';
|
||||
|
||||
try {
|
||||
currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {
|
||||
cwd: process.cwd(),
|
||||
encoding: 'utf8',
|
||||
}).trim();
|
||||
} catch (error) {
|
||||
console.error('[cs3d:check] Failed to determine current git branch.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (currentBranch !== expectedBranch) {
|
||||
console.error(
|
||||
`[cs3d:check] Branch mismatch: current='${currentBranch}', expected='${expectedBranch}' from ${path.relative(
|
||||
process.cwd(),
|
||||
workflowPath
|
||||
)}`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[cs3d:check] OK: current branch '${currentBranch}' matches OHIF_REF in ${path.relative(
|
||||
process.cwd(),
|
||||
workflowPath
|
||||
)}`
|
||||
);
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Resolves a version pattern to a concrete npm version of @cornerstonejs/core.
|
||||
*
|
||||
* Patterns:
|
||||
* 4.18.2 -> 4.18.2 (exact, returned as-is)
|
||||
* 4.18.2-beta.3 -> 4.18.2-beta.3 (exact prerelease)
|
||||
* 4.x -> latest 4.* from npm
|
||||
* 4.17.x -> latest 4.17.* from npm
|
||||
* 4.19+ -> latest >=4.19.0 <5.0.0-0 from npm (4.19 and later, same major)
|
||||
*
|
||||
* Prints the resolved version to stdout.
|
||||
*/
|
||||
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
const pattern = process.argv[2];
|
||||
if (!pattern) {
|
||||
console.error('Usage: cs3d-resolve-version.mjs <pattern>');
|
||||
console.error(' e.g. 4.x, 4.17.x, 4.19+, 4.18.2, 4.18.2-beta.3');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Exact version (no wildcard or range) — pass through unchanged
|
||||
if (!pattern.includes('x') && !pattern.endsWith('+')) {
|
||||
console.log(pattern);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Convert "M.m+" to npm semver range ">=M.m.0 <(M+1).0.0-0"
|
||||
let npmRange = pattern;
|
||||
const plusMatch = pattern.match(/^(\d+)\.(\d+)\+$/);
|
||||
if (plusMatch) {
|
||||
const major = Number(plusMatch[1]);
|
||||
const minor = Number(plusMatch[2]);
|
||||
npmRange = `>=${major}.${minor}.0 <${major + 1}.0.0-0`;
|
||||
}
|
||||
|
||||
try {
|
||||
// Let npm resolve the range: @package@<range> → concrete version
|
||||
const raw = execSync(`npm view @cornerstonejs/core@"${npmRange}" version --json`, {
|
||||
encoding: 'utf8',
|
||||
timeout: 30_000,
|
||||
});
|
||||
|
||||
const resolved = JSON.parse(raw);
|
||||
if (!resolved) {
|
||||
console.error(`npm returned no version when resolving @cornerstonejs/core@${npmRange}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// npm may return an array of versions for ranges; pick the latest (last) one
|
||||
const version = Array.isArray(resolved) ? resolved[resolved.length - 1] : resolved;
|
||||
console.log(version);
|
||||
} catch (err) {
|
||||
const message =
|
||||
(err && (err.stderr?.toString() || err.message || String(err))) ||
|
||||
`Unknown error resolving @cornerstonejs/core@${pattern}`;
|
||||
console.error(`Failed to resolve @cornerstonejs/core version for pattern "${pattern}":`);
|
||||
console.error(message);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Updates all @cornerstonejs/* package versions across the OHIF workspace.
|
||||
*
|
||||
* Usage: node .scripts/cs3d-set-version.mjs <version>
|
||||
*
|
||||
* Only updates the 8 main CS3D packages (not codec packages):
|
||||
* adapters, ai, core, dicom-image-loader, labelmap-interpolation,
|
||||
* nifti-volume-loader, polymorphic-segmentation, tools
|
||||
*/
|
||||
|
||||
import { readFileSync, writeFileSync, existsSync, readdirSync } from 'fs';
|
||||
import { resolve, dirname, join } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = resolve(__dirname, '..');
|
||||
|
||||
const version = process.argv[2];
|
||||
if (!version) {
|
||||
console.error('Usage: cs3d-set-version.mjs <version>');
|
||||
console.error(' e.g. 4.18.2, 4.19.0-beta.1');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// The 8 CS3D packages that are built from source (not codecs)
|
||||
const CS3D_PACKAGES = [
|
||||
'@cornerstonejs/adapters',
|
||||
'@cornerstonejs/ai',
|
||||
'@cornerstonejs/core',
|
||||
'@cornerstonejs/dicom-image-loader',
|
||||
'@cornerstonejs/labelmap-interpolation',
|
||||
'@cornerstonejs/nifti-volume-loader',
|
||||
'@cornerstonejs/polymorphic-segmentation',
|
||||
'@cornerstonejs/tools',
|
||||
];
|
||||
|
||||
// Read root package.json to get workspace globs
|
||||
const rootPkgPath = resolve(rootDir, 'package.json');
|
||||
const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf8'));
|
||||
const workspaceGlobs = rootPkg.workspaces?.packages || rootPkg.workspaces || [];
|
||||
|
||||
// Collect all package.json paths from workspace globs
|
||||
function findWorkspacePackageJsons() {
|
||||
const paths = [rootPkgPath]; // include root
|
||||
|
||||
for (const pattern of workspaceGlobs) {
|
||||
const parts = pattern.split('/');
|
||||
let searchDir = rootDir;
|
||||
let hasWildcard = false;
|
||||
|
||||
for (const part of parts) {
|
||||
if (part === '*') {
|
||||
hasWildcard = true;
|
||||
break;
|
||||
}
|
||||
searchDir = join(searchDir, part);
|
||||
}
|
||||
|
||||
if (hasWildcard) {
|
||||
try {
|
||||
const entries = readdirSync(searchDir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (entry.isDirectory()) {
|
||||
const pkgJson = join(searchDir, entry.name, 'package.json');
|
||||
if (existsSync(pkgJson)) {
|
||||
paths.push(pkgJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// directory doesn't exist, skip
|
||||
}
|
||||
} else {
|
||||
const pkgJson = join(rootDir, pattern, 'package.json');
|
||||
if (existsSync(pkgJson)) {
|
||||
paths.push(pkgJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
// Update a dependencies object, returning count of changes
|
||||
function updateDeps(deps, targetVersion) {
|
||||
let count = 0;
|
||||
if (!deps) return count;
|
||||
for (const pkg of CS3D_PACKAGES) {
|
||||
if (pkg in deps && deps[pkg] !== targetVersion) {
|
||||
deps[pkg] = targetVersion;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
const pkgPaths = findWorkspacePackageJsons();
|
||||
let totalChanges = 0;
|
||||
|
||||
for (const pkgPath of pkgPaths) {
|
||||
const content = readFileSync(pkgPath, 'utf8');
|
||||
const pkg = JSON.parse(content);
|
||||
let changes = 0;
|
||||
|
||||
changes += updateDeps(pkg.dependencies, version);
|
||||
changes += updateDeps(pkg.devDependencies, version);
|
||||
changes += updateDeps(pkg.peerDependencies, version);
|
||||
changes += updateDeps(pkg.resolutions, version);
|
||||
|
||||
if (changes > 0) {
|
||||
// Preserve original formatting (detect indent — restrict to spaces/tabs so
|
||||
// we don't accidentally capture a CRLF newline as part of the indent string)
|
||||
const indent = content.match(/^([ \t]+)/m)?.[1] || ' ';
|
||||
writeFileSync(pkgPath, JSON.stringify(pkg, null, indent) + '\n');
|
||||
const rel = pkgPath.replace(rootDir + '/', '').replace(rootDir + '\\', '');
|
||||
console.log(` Updated ${rel} (${changes} packages)`);
|
||||
totalChanges += changes;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
`\nDone: ${totalChanges} version(s) updated to ${version} across ${pkgPaths.length} package files.`
|
||||
);
|
||||
console.log(
|
||||
'This step changes package.json; the following install must not use a frozen Bun lockfile ' +
|
||||
'(OHIF+CS3D combined “version” CI does: `bun install --config=./bunfig.update-lockfile.toml`). ' +
|
||||
'Other installs stay frozen. Locally after this script, use that bun command and/or ' +
|
||||
'`bun run install:update-lockfile` when you intend to commit lockfile updates.\n'
|
||||
);
|
||||
+2
-2
@@ -6,9 +6,9 @@ PROJECT=$1
|
||||
if [ -z "$PROJECT" ]
|
||||
then
|
||||
# Default
|
||||
npx lerna run dev:viewer
|
||||
pnpm --filter @ohif/app run dev:viewer
|
||||
else
|
||||
eval "npx lerna run dev:$PROJECT"
|
||||
pnpm --filter @ohif/app run "dev:$PROJECT"
|
||||
fi
|
||||
|
||||
read -p 'Press [Enter] key to continue...'
|
||||
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Logs build context (OHIF branch/version, CS3D source) for diagnosing build issues on GitHub.
|
||||
* Run from repo root. Used by version.mjs and can be invoked from CI workflows.
|
||||
*/
|
||||
import { execa } from 'execa';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const REPO_ROOT = path.resolve(__dirname, '..');
|
||||
|
||||
function log(msg) {
|
||||
console.log(`[build-context] ${msg}`);
|
||||
}
|
||||
|
||||
async function detectCs3dSource() {
|
||||
const libsCs3d = path.join(REPO_ROOT, 'libs/@cornerstonejs');
|
||||
const coreInNodeModules = path.join(REPO_ROOT, 'node_modules/@cornerstonejs/core');
|
||||
|
||||
try {
|
||||
const libsExists = await fs.access(libsCs3d).then(() => true).catch(() => false);
|
||||
if (!libsExists) {
|
||||
return { source: 'npm', detail: 'published @cornerstonejs packages (no libs/@cornerstonejs)' };
|
||||
}
|
||||
|
||||
const coreStat = await fs.lstat(coreInNodeModules).catch(() => null);
|
||||
const isSymlink = coreStat?.isSymbolicLink();
|
||||
if (isSymlink) {
|
||||
const target = await fs.readlink(coreInNodeModules);
|
||||
return { source: 'integrated', detail: `linked from libs/@cornerstonejs (→ ${target})` };
|
||||
}
|
||||
|
||||
return { source: 'npm', detail: 'published @cornerstonejs packages (libs exists but not linked)' };
|
||||
} catch {
|
||||
return { source: 'unknown', detail: 'could not detect' };
|
||||
}
|
||||
}
|
||||
|
||||
async function getCs3dVersion() {
|
||||
try {
|
||||
const corePkg = path.join(REPO_ROOT, 'node_modules/@cornerstonejs/core/package.json');
|
||||
const pkg = JSON.parse(await fs.readFile(corePkg, 'utf-8'));
|
||||
return pkg.version || 'unknown';
|
||||
} catch {
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
async function getCs3dBranchFromLibs() {
|
||||
try {
|
||||
const libsCs3d = path.join(REPO_ROOT, 'libs/@cornerstonejs');
|
||||
const { stdout } = await execa('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
||||
cwd: libsCs3d,
|
||||
});
|
||||
return stdout;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function run() {
|
||||
const inCI = process.env.GITHUB_ACTIONS === 'true';
|
||||
const buildType = inCI ? (process.env.BUILD_TYPE || 'ohif-upstream') : 'local';
|
||||
|
||||
log('═══════════════════════════════════════════════════════════════');
|
||||
log('Build context (for diagnosing GitHub build issues)');
|
||||
log('═══════════════════════════════════════════════════════════════');
|
||||
|
||||
if (inCI) {
|
||||
log(`Build type: ${process.env.BUILD_TYPE || 'ohif-upstream'}`);
|
||||
log(`GitHub repo: ${process.env.GITHUB_REPOSITORY || 'unknown'}`);
|
||||
log(`GitHub ref: ${process.env.GITHUB_REF || 'unknown'}`);
|
||||
log(`GitHub SHA: ${process.env.GITHUB_SHA || 'unknown'}`);
|
||||
log(`Workflow: ${process.env.GITHUB_WORKFLOW || 'unknown'}`);
|
||||
}
|
||||
|
||||
try {
|
||||
const { stdout: branch } = await execa('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
||||
cwd: REPO_ROOT,
|
||||
});
|
||||
const { stdout: sha } = await execa('git', ['rev-parse', '--short', 'HEAD'], {
|
||||
cwd: REPO_ROOT,
|
||||
});
|
||||
log(`OHIF branch: ${branch} (${sha})`);
|
||||
} catch {
|
||||
log('OHIF branch: (not a git repo or error)');
|
||||
}
|
||||
|
||||
const cs3d = await detectCs3dSource();
|
||||
log(`CS3D source: ${cs3d.source} — ${cs3d.detail}`);
|
||||
|
||||
if (cs3d.source === 'integrated') {
|
||||
const branch = await getCs3dBranchFromLibs();
|
||||
if (branch) log(`CS3D branch (libs/@cornerstonejs): ${branch}`);
|
||||
} else {
|
||||
const ver = await getCs3dVersion();
|
||||
log(`CS3D version (@cornerstonejs/core): ${ver}`);
|
||||
}
|
||||
|
||||
log('═══════════════════════════════════════════════════════════════');
|
||||
}
|
||||
|
||||
run().catch((err) => {
|
||||
console.error('[build-context] Error:', err.message);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
const path = require('path');
|
||||
|
||||
// Shared module-resolution rules (alias + module search paths) used by BOTH
|
||||
// build pipelines so they cannot drift apart:
|
||||
// - the webpack/rspack build: webpack.base.js -> webpack.pwa.js, plus every
|
||||
// per-package webpack.prod.js / webpack.dev.js that merges webpack.base.js
|
||||
// - the rsbuild build: rsbuild.config.ts (dev:fast)
|
||||
//
|
||||
// Plugin aliases (writePluginImportsFile.getPluginResolveAliases) are NOT
|
||||
// included here: they depend on pluginConfig.json and are merged in separately
|
||||
// by each config.
|
||||
//
|
||||
// All paths are anchored to this file's location (the repo-root `.webpack/`
|
||||
// directory), so the values are identical regardless of which package's build
|
||||
// is doing the resolving.
|
||||
|
||||
const alias = {
|
||||
// Some extensions import app-level utilities (e.g. history,
|
||||
// preserveQueryParameters) from '@ohif/app'. pnpm's isolated layout does not
|
||||
// expose the top-level app package to those extensions, and adding it as a
|
||||
// workspace dependency would create an app<->default cycle, so we resolve the
|
||||
// bare specifier to the app source here ($ = exact match).
|
||||
'@ohif/app$': path.resolve(__dirname, '../platform/app/src/index.js'),
|
||||
'@': path.resolve(__dirname, '../platform/app/src'),
|
||||
'@components': path.resolve(__dirname, '../platform/app/src/components'),
|
||||
'@hooks': path.resolve(__dirname, '../platform/app/src/hooks'),
|
||||
'@routes': path.resolve(__dirname, '../platform/app/src/routes'),
|
||||
'@state': path.resolve(__dirname, '../platform/app/src/state'),
|
||||
};
|
||||
|
||||
// Directories to search when resolving modules. The leading bare 'node_modules'
|
||||
// preserves the default importer-relative walk-up, which pnpm's isolated layout
|
||||
// requires so that transitive deps (e.g. react-remove-scroll -> tslib 2.x)
|
||||
// resolve to the sibling copy inside .pnpm/<pkg>/node_modules rather than a
|
||||
// hoisted older version.
|
||||
const moduleSearchPaths = [
|
||||
'node_modules',
|
||||
path.resolve(__dirname, '../node_modules'),
|
||||
path.resolve(__dirname, '../../../node_modules'),
|
||||
path.resolve(__dirname, '../platform/app/node_modules'),
|
||||
path.resolve(__dirname, '../platform/ui/node_modules'),
|
||||
];
|
||||
|
||||
// Build the resolve.modules array for a build. `srcDir` is the building
|
||||
// package's source root; it is appended last (matching the previous inline
|
||||
// behavior in webpack.base.js). Pass nothing to get just the shared paths.
|
||||
function getModules(srcDir) {
|
||||
return srcDir ? [...moduleSearchPaths, srcDir] : [...moduleSearchPaths];
|
||||
}
|
||||
|
||||
module.exports = { alias, moduleSearchPaths, getModules };
|
||||
@@ -2,14 +2,14 @@ const autoprefixer = require('autoprefixer');
|
||||
const path = require('path');
|
||||
const tailwindcss = require('tailwindcss');
|
||||
const tailwindConfigPath = path.resolve('../../platform/app/tailwind.config.js');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const rspack = require('@rspack/core');
|
||||
const devMode = process.env.NODE_ENV !== 'production';
|
||||
|
||||
const cssToJavaScript = {
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
//'style-loader',
|
||||
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
|
||||
devMode ? 'style-loader' : rspack.CssExtractRspackPlugin.loader,
|
||||
{ loader: 'css-loader', options: { importLoaders: 1 } },
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
|
||||
@@ -4,6 +4,8 @@ function transpileJavaScript(mode) {
|
||||
const exclude =
|
||||
mode === 'production'
|
||||
? excludeNodeModulesExcept([
|
||||
// Workspace packages (needed for pnpm shamefully-hoist where they resolve through node_modules)
|
||||
'@ohif',
|
||||
// 'dicomweb-client',
|
||||
// https://github.com/react-dnd/react-dnd/blob/master/babel.config.js
|
||||
'react-dnd',
|
||||
|
||||
+38
-33
@@ -4,11 +4,10 @@ const dotenv = require('dotenv');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const webpack = require('webpack');
|
||||
const webpack = require('@rspack/core');
|
||||
|
||||
// ~~ PLUGINS
|
||||
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
const TerserJSPlugin = require('terser-webpack-plugin');
|
||||
|
||||
// ~~ PackageJSON
|
||||
// const vtkRules = require('vtk.js/Utilities/config/dependency.js').webpack.core
|
||||
@@ -18,9 +17,15 @@ const TerserJSPlugin = require('terser-webpack-plugin');
|
||||
const loadWebWorkersRule = require('./rules/loadWebWorkers.js');
|
||||
const transpileJavaScriptRule = require('./rules/transpileJavaScript.js');
|
||||
const cssToJavaScript = require('./rules/cssToJavaScript.js');
|
||||
// Module-resolution rules shared with the rsbuild build (see rsbuild.config.ts).
|
||||
const resolveConfig = require('./resolveConfig');
|
||||
// Only uncomment for old v2 stylus
|
||||
// const stylusToJavaScript = require('./rules/stylusToJavaScript.js');
|
||||
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
||||
let ReactRefreshWebpackPlugin;
|
||||
try {
|
||||
const mod = require('@rspack/plugin-react-refresh');
|
||||
ReactRefreshWebpackPlugin = mod.ReactRefreshRspackPlugin || mod.default || mod;
|
||||
} catch { ReactRefreshWebpackPlugin = null; }
|
||||
|
||||
// ~~ ENV VARS
|
||||
const NODE_ENV = process.env.NODE_ENV;
|
||||
@@ -66,6 +71,12 @@ module.exports = (env, argv, { SRC_DIR, ENTRY }) => {
|
||||
const config = {
|
||||
mode: isProdBuild ? 'production' : 'development',
|
||||
devtool: isProdBuild ? 'source-map' : 'cheap-module-source-map',
|
||||
// `rspack serve` (@rspack/cli) auto-enables lazyCompilation for web-only
|
||||
// apps unless the config defines it explicitly. The on-demand proxy chunks
|
||||
// it produces fail to load in the headless cypress/electron e2e run
|
||||
// (ChunkLoadError on cornerstone vendor chunks), so disable it here to match
|
||||
// the rsbuild build (see rsbuild.config.ts `dev.lazyCompilation: false`).
|
||||
lazyCompilation: false,
|
||||
entry: ENTRY,
|
||||
optimization: {
|
||||
// splitChunks: {
|
||||
@@ -92,9 +103,7 @@ module.exports = (env, argv, { SRC_DIR, ENTRY }) => {
|
||||
children: false,
|
||||
warnings: true,
|
||||
},
|
||||
cache: {
|
||||
type: 'filesystem',
|
||||
},
|
||||
cache: isProdBuild ? false : { type: 'filesystem' },
|
||||
module: {
|
||||
noParse: [/(dicomicc)/],
|
||||
rules: [
|
||||
@@ -168,9 +177,6 @@ module.exports = (env, argv, { SRC_DIR, ENTRY }) => {
|
||||
},
|
||||
},
|
||||
cssToJavaScript,
|
||||
// Note: Only uncomment the following if you are using the old style of stylus in v2
|
||||
// Also you need to uncomment this platform/app/.webpack/rules/extractStyleChunks.js
|
||||
// stylusToJavaScript,
|
||||
{
|
||||
test: /\.wasm/,
|
||||
type: 'asset/resource',
|
||||
@@ -194,27 +200,16 @@ module.exports = (env, argv, { SRC_DIR, ENTRY }) => {
|
||||
},
|
||||
resolve: {
|
||||
mainFields: ['module', 'browser', 'main'],
|
||||
// alias and modules are shared with the rsbuild build via ./resolveConfig
|
||||
// so the two pipelines resolve identically.
|
||||
alias: {
|
||||
// Viewer project
|
||||
'@': path.resolve(__dirname, '../platform/app/src'),
|
||||
'@components': path.resolve(__dirname, '../platform/app/src/components'),
|
||||
'@hooks': path.resolve(__dirname, '../platform/app/src/hooks'),
|
||||
'@routes': path.resolve(__dirname, '../platform/app/src/routes'),
|
||||
'@state': path.resolve(__dirname, '../platform/app/src/state'),
|
||||
...resolveConfig.alias,
|
||||
},
|
||||
// Which directories to search when resolving modules
|
||||
modules: [
|
||||
// Modules specific to this package
|
||||
path.resolve(__dirname, '../node_modules'),
|
||||
// Hoisted Yarn Workspace Modules
|
||||
path.resolve(__dirname, '../../../node_modules'),
|
||||
path.resolve(__dirname, '../platform/app/node_modules'),
|
||||
path.resolve(__dirname, '../platform/ui/node_modules'),
|
||||
SRC_DIR,
|
||||
],
|
||||
modules: resolveConfig.getModules(SRC_DIR),
|
||||
// Attempt to resolve these extensions in order.
|
||||
extensions: ['.js', '.jsx', '.json', '.ts', '.tsx', '*'],
|
||||
// symlinked resources are resolved to their real path, not their symlinked location
|
||||
// Workspace packages use relative imports between sibling packages.
|
||||
// Resolve symlinks to keep those imports anchored at the real package paths.
|
||||
symlinks: true,
|
||||
fallback: {
|
||||
fs: false,
|
||||
@@ -223,24 +218,34 @@ module.exports = (env, argv, { SRC_DIR, ENTRY }) => {
|
||||
buffer: require.resolve('buffer'),
|
||||
},
|
||||
},
|
||||
node: {
|
||||
// Leave __filename / __dirname references alone. The previous 'mock'
|
||||
// value triggers an rspack warning whenever bundled deps reference
|
||||
// __dirname (e.g. Emscripten-compiled cornerstone codecs). Those refs
|
||||
// sit inside `if (ENVIRONMENT_IS_NODE)` branches that never execute in
|
||||
// the browser, so leaving them un-substituted is harmless at runtime.
|
||||
__filename: false,
|
||||
__dirname: false,
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin(defineValues),
|
||||
new webpack.ProvidePlugin({
|
||||
Buffer: ['buffer', 'Buffer'],
|
||||
}),
|
||||
...(isProdBuild ? [] : [new ReactRefreshWebpackPlugin({ overlay: false })]),
|
||||
new webpack.IgnorePlugin({
|
||||
resourceRegExp: /^(fs|path)$/,
|
||||
contextRegExp: /@cornerstonejs[\\/]codec-/,
|
||||
}),
|
||||
...(isProdBuild || IS_COVERAGE || !ReactRefreshWebpackPlugin
|
||||
? []
|
||||
: [new ReactRefreshWebpackPlugin({ overlay: false })]),
|
||||
// Uncomment to generate bundle analyzer
|
||||
// new BundleAnalyzerPlugin(),
|
||||
],
|
||||
};
|
||||
|
||||
if (isProdBuild) {
|
||||
config.optimization.minimizer = [
|
||||
new TerserJSPlugin({
|
||||
parallel: true,
|
||||
terserOptions: {},
|
||||
}),
|
||||
];
|
||||
config.optimization.minimizer = [new webpack.SwcJsMinimizerRspackPlugin()];
|
||||
}
|
||||
|
||||
if (isQuickBuild) {
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
# AGENTS.md
|
||||
|
||||
This file provides guidance to AI coding agents (Claude, Codex, and other LLM tools) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is **OHIF** v3 (Open Health Imaging Foundation) - a medical imaging viewer. It's an extensible web imaging platform.
|
||||
## Development Commands
|
||||
|
||||
### Main Development
|
||||
```bash
|
||||
# Start development server for all packages
|
||||
yarn dev
|
||||
```
|
||||
|
||||
### Building
|
||||
```bash
|
||||
# Build all packages for production
|
||||
yarn build
|
||||
|
||||
# Build specific packages
|
||||
cd platform/app && yarn build # Main viewer app
|
||||
```
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Monorepo Structure
|
||||
- **`platform/`** - Core OHIF infrastructure
|
||||
- `app/` - Main viewer application (`@ohif/viewer`)
|
||||
- `core/` - Core services and utilities
|
||||
- `ui-next/` - Modern UI component library
|
||||
- **`extensions/`** - Modular functionality plugins
|
||||
- **`modes/`** - Application workflow configurations
|
||||
|
||||
### Key Extension Architecture
|
||||
|
||||
**Extension System**: Each extension exports modules (viewports, tools, panels, commands) that the app dynamically loads. Extensions are self-contained with their own webpack builds.
|
||||
|
||||
|
||||
**Core Extensions:**
|
||||
- `cornerstone/` - Medical image rendering engine
|
||||
- `cornerstone-dicom-pmp/` - DICOM PMP support
|
||||
- `cornerstone-dicom-seg/` - DICOM Segmentation support
|
||||
- `cornerstone-dicom-sr/` - DICOM SR support
|
||||
- `dicom-pdf/` - DICOM PDF support
|
||||
- `dicom-video/` - DICOM Video support
|
||||
- `measurement-tracking/` - Measurement tracking support
|
||||
- `default/` - Standard OHIF functionality
|
||||
|
||||
### Service-Oriented Design (PUB-SUB)
|
||||
|
||||
The app uses a Services Manager pattern with these core services:
|
||||
- **Display Set Service**: Manages image series organization
|
||||
- **Measurement Service**: Handles annotations and measurements
|
||||
- **Hanging Protocol Service**: Controls image layout and display rules
|
||||
- **UI Service**: Manages panels, modals, and notifications
|
||||
- **Segmentation Service**: AI/ML powered image segmentation, loading segmentations, etc.
|
||||
- **Viewport Grid Service**: Manages viewport layout and display rules
|
||||
- **Viewport Display Set History Service**: Manages viewport display set history
|
||||
- **Viewport Dialog Service**: Manages viewport dialogs
|
||||
- **Notification Service**: Manages notifications
|
||||
- **Modal Service**: Manages modals
|
||||
- **Dialog Service**: Manages dialogs, more general not just viewport dialogs
|
||||
- **Customization Service**: Manages customization of the app
|
||||
- **Toolbar Service**: Manages the toolbar, viewport action corners, tool states
|
||||
- **User Authentication Service**: Manages user authentication, but used only for injecting tokens in dicomweb requests in our context
|
||||
- **Panel Service**: Manages side panels
|
||||
- **Cornerstone Viewport Service**: Manages the cornerstone viewport, rendering engines, presentation states, more tightly coupled to cornerstone than the other services
|
||||
- **Tool Group Service**: Manages tool groups, creating and managing tool groups, etc.
|
||||
- **Sync Group Service**: Manages sync groups, syncing zooming, panning, scrolling, etc.
|
||||
- **Cornerstone Cache Service**: Manages the cornerstone cache, caching images, etc.
|
||||
|
||||
Most of the services utilize a pub sub architecture and extend the pub sub service interace at `pubSubServiceInterface.ts`
|
||||
|
||||
### Commands Manager
|
||||
|
||||
The Commands Manager tracks named commands (or functions) that are scoped to
|
||||
a context. When we attempt to run a command with a given name, we look for it
|
||||
in our active contexts, in the order specified.
|
||||
If found, we run the command, passing in any application
|
||||
or call specific data specified in the command's definition.
|
||||
|
||||
You can call `commandsManager.runCommand` to run a command.
|
||||
|
||||
### Extension Manager
|
||||
|
||||
Aggregates and exposes extension modules throughout the OHIF application, manages data sources, and provides a centralized registry for accessing extension functionality.
|
||||
|
||||
### Build System
|
||||
|
||||
**Yarn Workspaces**: Optimized monorepo builds with dependency caching
|
||||
**Webpack 5**: Module federation for dynamic extension loading
|
||||
**Plugin Import System**: Extensions auto-register via `writePluginImportsFile.js`
|
||||
|
||||
### Key Technologies
|
||||
|
||||
- **React 18 + TypeScript**: UI framework
|
||||
- **Cornerstone.js**: Medical image rendering
|
||||
- **DICOM**: Medical imaging standard support
|
||||
- **ONNX Runtime**: AI model inference (SAM segmentation models)
|
||||
- **Zustand**: State management
|
||||
- **TailwindCSS**: Styling system
|
||||
|
||||
## Development Patterns
|
||||
|
||||
### Adding New Tools
|
||||
1. Create tool class in `extensions/cornerstone/src/tools/`
|
||||
2. Register in tool module's `toolNames.ts`
|
||||
3. Add to toolbar via `getToolbarModule.tsx`
|
||||
4. Add measurement mapping if needed in `measurementServiceMappings/`
|
||||
|
||||
### Creating Extensions
|
||||
Extensions must export:
|
||||
- `id.js` - Unique extension identifier
|
||||
- `index.tsx` - Extension registration
|
||||
- Module functions (`getToolbarModule`, `getViewportModule`, etc.)
|
||||
|
||||
### Viewport Customization
|
||||
Custom viewports extend base Cornerstone viewport:
|
||||
- Override render methods for custom overlays
|
||||
- Implement measurement tracking
|
||||
- Add viewport-specific tools and interactions
|
||||
|
||||
### Service Integration
|
||||
Register services in extension's `servicesManager.registerService` and access via:
|
||||
```javascript
|
||||
const { MeasurementService } = servicesManager.services;
|
||||
```
|
||||
|
||||
### Creating stores
|
||||
To create a store, you can make one in your extension's `stores/` directory, and you can follow the example of an existing store such as `useLutPresentationStore.ts` or `useSynchronizersStore.ts`.
|
||||
|
||||
### Creating hooks
|
||||
To create a hook, you can make one in your extension's `hooks/` directory, and you can follow the example of an existing hook such as `usePatientInfo.tsx`.
|
||||
|
||||
### Creating providers
|
||||
To create a provider, you can make one in your extension's `providers/` or `contexts/` directory, and you can follow the example of an existing provider such as `ViewportGridProvider.tsx`.
|
||||
|
||||
### Adding new icons
|
||||
To add a new icon, you can add it to the `icons/` directory, then register the icon using `import { addIcon } from '@ohif/extension-default/src/utils'`
|
||||
|
||||
### Creating synchronizers
|
||||
You can create custom synchronizers and place them in the `synchronizers/` directory, you can follow the example of `frameViewSynchronizer.ts`
|
||||
|
||||
### Utilites
|
||||
Any new utilites should be placed in the `utils/` directory, and you can follow the example of `formatPN.ts`
|
||||
|
||||
### Commands
|
||||
Commands are created in the commandsModule of the extension, for example the cornerstone extension has `commandsModule.tsx`, sometimes its also named `getCommandsModule.tsx.`
|
||||
|
||||
### Overriding OHIF Components
|
||||
|
||||
To override an OHIF component, you can create a new component in your extension's `components/` directory, then import it instead of the original ui-next component.
|
||||
|
||||
### Mode layout
|
||||
|
||||
The layoutTemplate is a function that returns a layout object, you can follow the example of `longitudinal/src/index.ts`. This would be helpful when you need to override a component as you can know where to look for the original component.
|
||||
|
||||
### Pub Sub
|
||||
Always prioritrize pub sub, by calling a services subscribe over useEffects as it's more reliable, for example
|
||||
|
||||
```ts
|
||||
useEffect(() => {
|
||||
const subscriptions = [
|
||||
cornerstoneViewportService.subscribe(EVENTS.VIEWPORT_DATA_CHANGED, handleViewportDataChanged),
|
||||
syncGroupService.subscribe(EVENTS.VIEWPORT_REMOVED, onHotKeyRemoval),
|
||||
syncGroupService.subscribe(EVENTS.VIEWPORT_ADDED, onHotKeyAddition),
|
||||
];
|
||||
|
||||
return () => {
|
||||
subscriptions.forEach(({ unsubscribe }) => unsubscribe());
|
||||
};
|
||||
}, []);
|
||||
```
|
||||
|
||||
### Never modify core architecture
|
||||
Do not modify the core and always find a way to implement the solution via the extensions and modes, only modify core as a last resort if all other fail or there's an architectural constraint.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Plugin Configuration
|
||||
Extensions are auto-discovered via `pluginConfig.json` and dynamically imported during build.
|
||||
|
||||
## Medical Imaging Specifics
|
||||
|
||||
### DICOM Support
|
||||
- Multi-format: CT, MRI, X-Ray, Mammography, Ultrasound
|
||||
- SOP Class handlers for specialized DICOM types (RT, SEG, SR)
|
||||
- DICOMweb protocol for web-based image retrieval
|
||||
|
||||
### Hanging Protocols
|
||||
Define how images are arranged and displayed:
|
||||
- Located in `hps/` directories
|
||||
- JSON configuration with viewport rules
|
||||
- Support for priors comparison and multi-monitor layouts
|
||||
|
||||
### Measurement Tools
|
||||
- Cornerstone Tools integration for annotations
|
||||
- Bidirectional measurements, polylines, annotations
|
||||
- Export capabilities (DICOM SR, CSV reports)
|
||||
- AI-assisted measurements via ONNX models
|
||||
+772
@@ -3,6 +3,778 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.13.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.88...v3.13.0-beta.89) (2026-06-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ohif tests to run with cornerstone 3d 5.0 ([#6043](https://github.com/OHIF/Viewers/issues/6043)) ([6dd150d](https://github.com/OHIF/Viewers/commit/6dd150d401ad73d60632a23378b7dfd4b5142690))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.87...v3.13.0-beta.88) (2026-06-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** Patch axios vulnerabilities. ([#6063](https://github.com/OHIF/Viewers/issues/6063)) ([99c6154](https://github.com/OHIF/Viewers/commit/99c615434309b113aed9ac9a977419eeae0528cb))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.86...v3.13.0-beta.87) (2026-05-29)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.85...v3.13.0-beta.86) (2026-05-28)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.84...v3.13.0-beta.85) (2026-05-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **WorkList:** New Study List (WorkList based on ui-next); old study list renamed to LegacyWorklist ([#6005](https://github.com/OHIF/Viewers/issues/6005)) ([daae4c1](https://github.com/OHIF/Viewers/commit/daae4c144e7cb80bbee7c05d9fceef8b332ed2a0))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.83...v3.13.0-beta.84) (2026-05-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** Add tmp as a resolution to fix security vulnerability. ([#6044](https://github.com/OHIF/Viewers/issues/6044)) ([bdcafc1](https://github.com/OHIF/Viewers/commit/bdcafc12de5e4f73a1a96cab9c0830d49315c044))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.82...v3.13.0-beta.83) (2026-05-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** restore navigation for duplicated contour segments ([#6038](https://github.com/OHIF/Viewers/issues/6038)) ([0c1ca6b](https://github.com/OHIF/Viewers/commit/0c1ca6b04a6c1aef478c7a7d9f360f9b9c50f188))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.81...v3.13.0-beta.82) (2026-05-22)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.80...v3.13.0-beta.81) (2026-05-21)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **tests:** Add tests for duplicating contour segments ([#6002](https://github.com/OHIF/Viewers/issues/6002)) ([2258c79](https://github.com/OHIF/Viewers/commit/2258c7957a18ed0f1a75d2bd5d379006797b2882))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.79...v3.13.0-beta.80) (2026-05-20)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.78...v3.13.0-beta.79) (2026-05-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **seg:** prevent viewport orientation change when loading SEG in manual grid layout ([#6021](https://github.com/OHIF/Viewers/issues/6021)) ([95251ab](https://github.com/OHIF/Viewers/commit/95251ab6709934e4ef59931379f8d9d7629f87b2))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.77...v3.13.0-beta.78) (2026-05-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **measurements:** read displayName in SplineROI and PlanarFreehandROI reports ([#5908](https://github.com/OHIF/Viewers/issues/5908)) ([27af682](https://github.com/OHIF/Viewers/commit/27af6821b56f2c5be3a5d4ce38d05be6fbce68f4))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.76...v3.13.0-beta.77) (2026-05-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** remove thresholdRange label in double-range tool settings ([#5931](https://github.com/OHIF/Viewers/issues/5931)) ([527cfb0](https://github.com/OHIF/Viewers/commit/527cfb0ae8c615aeaddbc7f16892ba4460a5b596))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.75...v3.13.0-beta.76) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.74...v3.13.0-beta.75) (2026-05-18)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.73...v3.13.0-beta.74) (2026-05-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** Update various dependencies to fix security vulnerabilities. ([#6023](https://github.com/OHIF/Viewers/issues/6023)) ([55b46f3](https://github.com/OHIF/Viewers/commit/55b46f39c65a183978a44a61fb322685134f3bd6))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.72...v3.13.0-beta.73) (2026-05-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **llm:** add instructions md file for claude and other LLM tools ([#6017](https://github.com/OHIF/Viewers/issues/6017)) ([f231eff](https://github.com/OHIF/Viewers/commit/f231eff5980495c9f3ac0bd907a03388d06c5b90))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.71...v3.13.0-beta.72) (2026-05-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **measurement-tracking:** restore tracked state on undo after Delete all ([#5994](https://github.com/OHIF/Viewers/issues/5994)) ([397aa4d](https://github.com/OHIF/Viewers/commit/397aa4d0e361e95dcbd83e0557a9cd84c0b8440a))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.70...v3.13.0-beta.71) (2026-05-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove waitForVolumeLoad from main toolbar page object ([#6004](https://github.com/OHIF/Viewers/issues/6004)) ([37e19f7](https://github.com/OHIF/Viewers/commit/37e19f734a675a95cedc8a8acc3980816a489574))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.69...v3.13.0-beta.70) (2026-05-07)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.68...v3.13.0-beta.69) (2026-05-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** Patch axios security vulnerabilities. ([#5998](https://github.com/OHIF/Viewers/issues/5998)) ([5e624f1](https://github.com/OHIF/Viewers/commit/5e624f13870cdb63300b82285b46d4b21b9d47c3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.67...v3.13.0-beta.68) (2026-05-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **ToolGroupService:** Centralize tool binding persistence and provide API to add and remove persisted bindings. ([#5989](https://github.com/OHIF/Viewers/issues/5989)) ([979d619](https://github.com/OHIF/Viewers/commit/979d619f7ccb426beb75d59721b01c98175d5241))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.66...v3.13.0-beta.67) (2026-04-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **ui-next:** Adds toggle state for ToolButton and Crosshair example ([#5914](https://github.com/OHIF/Viewers/issues/5914)) ([691e267](https://github.com/OHIF/Viewers/commit/691e26731f4f3b3957fe81fc051b09c972696cf6))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.65...v3.13.0-beta.66) (2026-04-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **config url:** Hardening fetch options. ([#5985](https://github.com/OHIF/Viewers/issues/5985)) ([468e573](https://github.com/OHIF/Viewers/commit/468e5734a9ab02516430cc0dab5d7f2106dea950))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.64...v3.13.0-beta.65) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.63...v3.13.0-beta.64) (2026-04-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **seg:** prevent segmentations from spreading to all viewports before hydration confirmation in 3D four-up ([#5967](https://github.com/OHIF/Viewers/issues/5967)) ([f8ccf9f](https://github.com/OHIF/Viewers/commit/f8ccf9ff2ea9ab7c38bd427514a8ae87902822a3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.62...v3.13.0-beta.63) (2026-04-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** refine dynamic config URL trust policy and document trusted-origin behavior ([#5973](https://github.com/OHIF/Viewers/issues/5973)) ([f3cca21](https://github.com/OHIF/Viewers/commit/f3cca21e49729fbf4bab85aa1de64b9dcfebd0ce))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.61...v3.13.0-beta.62) (2026-04-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** Patch protobufjs for CVE-2026-41242. ([#5974](https://github.com/OHIF/Viewers/issues/5974)) ([1fc97fe](https://github.com/OHIF/Viewers/commit/1fc97fea43cc5e6689bd0076b77a278c67252af7))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.60...v3.13.0-beta.61) (2026-04-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **slice scrollbar:** Integrate ViewportSliceProgressScrollbar with customizations and docs ([#5960](https://github.com/OHIF/Viewers/issues/5960)) ([8fc0dc1](https://github.com/OHIF/Viewers/commit/8fc0dc16e97f3262fdac902ecf2d7c20cb8f78cc))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.59...v3.13.0-beta.60) (2026-04-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **configuration:** Harden dynamic datasource URL trust boundaries and credential handling. ([#5963](https://github.com/OHIF/Viewers/issues/5963)) ([eede569](https://github.com/OHIF/Viewers/commit/eede569a88ed6a3177bbdea8552dfb93ca13cac5))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.58...v3.13.0-beta.59) (2026-04-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Use newer ONNX version and load without errors ([#5854](https://github.com/OHIF/Viewers/issues/5854)) ([cc5dc20](https://github.com/OHIF/Viewers/commit/cc5dc201649bcbfb4cfad21141dbd56000d30f53)), closes [#5875](https://github.com/OHIF/Viewers/issues/5875) [#5884](https://github.com/OHIF/Viewers/issues/5884) [#5886](https://github.com/OHIF/Viewers/issues/5886) [#5893](https://github.com/OHIF/Viewers/issues/5893) [#5874](https://github.com/OHIF/Viewers/issues/5874) [#5865](https://github.com/OHIF/Viewers/issues/5865)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.57...v3.13.0-beta.58) (2026-04-14)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.56...v3.13.0-beta.57) (2026-04-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Enhance multiframe instance handling and improve instance valida… ([#5956](https://github.com/OHIF/Viewers/issues/5956)) ([f5a66b9](https://github.com/OHIF/Viewers/commit/f5a66b9eea236cd3291eac857208d7465516c89a))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.55...v3.13.0-beta.56) (2026-04-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* A couple of changes to enable cs3d integration build ([#5944](https://github.com/OHIF/Viewers/issues/5944)) ([f6bbd5c](https://github.com/OHIF/Viewers/commit/f6bbd5c779e4692dc47c93327a890661b8dcc174))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.54...v3.13.0-beta.55) (2026-04-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ignore auth in git ([#5955](https://github.com/OHIF/Viewers/issues/5955)) ([961eea1](https://github.com/OHIF/Viewers/commit/961eea1c39c37a940c1707c3dfafcede5f4af994))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.53...v3.13.0-beta.54) (2026-04-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cornerstone:** read FrameOfReferenceUID from display set in viewport service ([#5950](https://github.com/OHIF/Viewers/issues/5950)) ([d219171](https://github.com/OHIF/Viewers/commit/d219171e25caf5a7c575080f63819d6f4fe45016))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.52...v3.13.0-beta.53) (2026-04-06)
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* rename DisplaySet.frameOfReferenceUID back to FrameOfReferenceUID ([#5943](https://github.com/OHIF/Viewers/issues/5943)) ([0e933c2](https://github.com/OHIF/Viewers/commit/0e933c256e07b7cda35ed2ba3cfb1ab35d895d57))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.51...v3.13.0-beta.52) (2026-04-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **defaultRouteInit:** pass sorted display sets to hanging protocol for deterministic viewport order ([#5933](https://github.com/OHIF/Viewers/issues/5933)) ([68b10d3](https://github.com/OHIF/Viewers/commit/68b10d365a72d656c83a1c61624dcbd245fff5db))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **component:** Adds SmartScrollbar to ui-next - OHIF-2558 ([#5924](https://github.com/OHIF/Viewers/issues/5924)) ([91a8715](https://github.com/OHIF/Viewers/commit/91a8715795c1501b271f10b361382331eb836bf9))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.50...v3.13.0-beta.51) (2026-04-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** Update yarn.lock that was missed in PR [#5936](https://github.com/OHIF/Viewers/issues/5936). ([#5940](https://github.com/OHIF/Viewers/issues/5940)) ([84ddf78](https://github.com/OHIF/Viewers/commit/84ddf78c879a7cb1aa62c3aaef4428adf67065da))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.49...v3.13.0-beta.50) (2026-04-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** update dependencies to fix security vulnerabilities ([#5936](https://github.com/OHIF/Viewers/issues/5936)) ([5358a39](https://github.com/OHIF/Viewers/commit/5358a3985a1fa87eb1e3e7493dd61254f790b6d8))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.48...v3.13.0-beta.49) (2026-04-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** restrict overlay segmentation menu to same frame of reference as viewport background display set ([#5900](https://github.com/OHIF/Viewers/issues/5900)) ([b9029ef](https://github.com/OHIF/Viewers/commit/b9029ef6f8d63a0e36ec929310c1c5ad3f563ef8))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.47...v3.13.0-beta.48) (2026-04-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **measurement:** Restore viewport interactivity when deleting in-progress Spline or Livewire measurement ([#5905](https://github.com/OHIF/Viewers/issues/5905)) ([7929f08](https://github.com/OHIF/Viewers/commit/7929f0898f1bf882682a912b1c32d93d0944726f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.46...v3.13.0-beta.47) (2026-03-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prevent black viewport when navigating series with client-created segmentation ([#5919](https://github.com/OHIF/Viewers/issues/5919)) ([e66fb5a](https://github.com/OHIF/Viewers/commit/e66fb5a2b8c93a60ea20d315f73def7a02ea205f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.45...v3.13.0-beta.46) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.44...v3.13.0-beta.45) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.43...v3.13.0-beta.44) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.42...v3.13.0-beta.43) (2026-03-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **SR:** Added support for spline and live wire SR items. ([#5870](https://github.com/OHIF/Viewers/issues/5870)) ([1d4802c](https://github.com/OHIF/Viewers/commit/1d4802c2a38dd75dca7afca87913e100453c9135))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.41...v3.13.0-beta.42) (2026-03-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add combined build ([#5895](https://github.com/OHIF/Viewers/issues/5895)) ([1df671e](https://github.com/OHIF/Viewers/commit/1df671e9ab67d43f98bf09f6838ddc0a5f220277))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.40...v3.13.0-beta.41) (2026-03-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **sr-hydration:** enable hydration and arrow navigation for 3D SR measurements ([#5887](https://github.com/OHIF/Viewers/issues/5887)) ([7a38903](https://github.com/OHIF/Viewers/commit/7a38903b1977b1cf0f3a0ba8a4a823fac5e8fdeb))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.39...v3.13.0-beta.40) (2026-03-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** Bump flattened version to address CVE-2026-32141. ([#5897](https://github.com/OHIF/Viewers/issues/5897)) ([d8d376e](https://github.com/OHIF/Viewers/commit/d8d376edaf9c2b7af237182657e3e2203cca5abb))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.38...v3.13.0-beta.39) (2026-03-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **window level:** The window level value is not displayed by default on all the viewports when selecting common/custom layout and TMTV. ([#5865](https://github.com/OHIF/Viewers/issues/5865)) ([fe1ecfe](https://github.com/OHIF/Viewers/commit/fe1ecfe0cc5d1bcf82686d821f356da8936a8c4b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.37...v3.13.0-beta.38) (2026-03-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** Display "No description S:{series number} {modality}" for segmentations with no label. ([#5874](https://github.com/OHIF/Viewers/issues/5874)) ([7b5d0ce](https://github.com/OHIF/Viewers/commit/7b5d0ce40e5422ccfce6091ac3d7559586cbe57e))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.36...v3.13.0-beta.37) (2026-03-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** Bump tar version to address CVE-2026-31802. ([#5893](https://github.com/OHIF/Viewers/issues/5893)) ([d015b2e](https://github.com/OHIF/Viewers/commit/d015b2e32a418042034c4f557c5a36499c72f702))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.35...v3.13.0-beta.36) (2026-03-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Modalities in study list should select starts with as primary ([#5886](https://github.com/OHIF/Viewers/issues/5886)) ([b83e978](https://github.com/OHIF/Viewers/commit/b83e978df8c9ffda3759378318267b8d0020653c))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.34...v3.13.0-beta.35) (2026-03-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Threshold tool:** Threshold tool no longer becomes deselected when the Dynamic option is selected ([#5884](https://github.com/OHIF/Viewers/issues/5884)) ([889026f](https://github.com/OHIF/Viewers/commit/889026f8a9c20cd21c31b4a02128afd5f057b14b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.33...v3.13.0-beta.34) (2026-03-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **seg hydration:** auto-hydrate RT struct on second load with disableConfirmationPrompts ([#5875](https://github.com/OHIF/Viewers/issues/5875)) ([6f773f9](https://github.com/OHIF/Viewers/commit/6f773f997214c388409f3af3e9fc0e5b84debc10))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.32...v3.13.0-beta.33) (2026-03-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** Bump svgo and tar to fix vulnerabilities. ([#5877](https://github.com/OHIF/Viewers/issues/5877)) ([61a1fcc](https://github.com/OHIF/Viewers/commit/61a1fccd7d47965831a6c80357219eed979ce4d6))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.31...v3.13.0-beta.32) (2026-03-05)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **ecg:** add DICOM ECG waveform extension ([#5856](https://github.com/OHIF/Viewers/issues/5856)) ([70f76ae](https://github.com/OHIF/Viewers/commit/70f76aeba1b27f8e4de5ec73a7b831428e38e3d2))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.30...v3.13.0-beta.31) (2026-03-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **microscopy:** rename measurement in microscopy mode ([#5866](https://github.com/OHIF/Viewers/issues/5866)) ([2358a73](https://github.com/OHIF/Viewers/commit/2358a73c3cd24953430064480fb9e66bfe36ea69))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.29...v3.13.0-beta.30) (2026-03-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** segment bidirectional tool error and show toast notification when no segment is drawn ([#5861](https://github.com/OHIF/Viewers/issues/5861)) ([7e10830](https://github.com/OHIF/Viewers/commit/7e10830d5802e22bda4df6a3f8008e9a414b4cd4))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.28...v3.13.0-beta.29) (2026-03-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** Address various security vulnerabilities. ([#5869](https://github.com/OHIF/Viewers/issues/5869)) ([be8e266](https://github.com/OHIF/Viewers/commit/be8e266a80f13d03ce9dc4a21a0227d3e1bc36ac))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.27...v3.13.0-beta.28) (2026-03-03)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.26...v3.13.0-beta.27) (2026-03-02)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.25...v3.13.0-beta.26) (2026-02-28)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.24...v3.13.0-beta.25) (2026-02-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Update CS3D 4.18.2 ([#5837](https://github.com/OHIF/Viewers/issues/5837)) ([5370b93](https://github.com/OHIF/Viewers/commit/5370b9382e7bfddeadd69bab9e653f5f997a6e19))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.23...v3.13.0-beta.24) (2026-02-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prevent viewer crash when opening DICOM Tag Browser from empty viewport ([#5827](https://github.com/OHIF/Viewers/issues/5827)) ([d11d6d4](https://github.com/OHIF/Viewers/commit/d11d6d401bc92a3870ec1089d97235b01a6b27c3))
|
||||
* **ui-next:** Add validation for opacity and border inputs in the segmentation panel - OHIF-2332 ([#5819](https://github.com/OHIF/Viewers/issues/5819)) ([a8f7099](https://github.com/OHIF/Viewers/commit/a8f709982f16983a11c780e696521df5aa05b604))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.22...v3.13.0-beta.23) (2026-02-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* palette color 8 encoded 16 ([#5823](https://github.com/OHIF/Viewers/issues/5823)) ([eeca1f7](https://github.com/OHIF/Viewers/commit/eeca1f7a7b529d1700f5d281a6fd98074547ffe9)), closes [#5813](https://github.com/OHIF/Viewers/issues/5813)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.21...v3.13.0-beta.22) (2026-02-23)
|
||||
|
||||
**Note:** Version bump only for package ohif-monorepo-root
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.20...v3.13.0-beta.21) (2026-02-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **RTStruct:** RTSTRUCT contours rendered on first slice for multi-frame images without IPP ([#5811](https://github.com/OHIF/Viewers/issues/5811)) ([b5573ca](https://github.com/OHIF/Viewers/commit/b5573caaa65d0d7ff3e83df0ec70b4aa7ea898ca))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.19...v3.13.0-beta.20) (2026-02-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Published version should match ([#5813](https://github.com/OHIF/Viewers/issues/5813)) ([d359a3b](https://github.com/OHIF/Viewers/commit/d359a3b784227b248c5b09548db363c7f8adbcb8))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.18...v3.13.0-beta.19) (2026-02-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** CVE-2026-27212 patched. Various dependency updates as a result of CVE-2026-26996. ([#5830](https://github.com/OHIF/Viewers/issues/5830)) ([2722960](https://github.com/OHIF/Viewers/commit/27229609cda3162e37573418ef82ca5d4e365075))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.17...v3.13.0-beta.18) (2026-02-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation overlay:** update viewport ds list upon seg delete - OHIF-2425 ([#5729](https://github.com/OHIF/Viewers/issues/5729)) ([b353541](https://github.com/OHIF/Viewers/commit/b35354120a01d89b27844f967c32c052bba8b096))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.16...v3.13.0-beta.17) (2026-02-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add copy to clipboard option for capture ([#5720](https://github.com/OHIF/Viewers/issues/5720)) ([53c67f3](https://github.com/OHIF/Viewers/commit/53c67f361234a0b4160c1b11fafcb143a0723336))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.15...v3.13.0-beta.16) (2026-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** Bump tar to 7.5.9 and lerna to 9.0.4 to fix CVE-2026-26960. ([#5824](https://github.com/OHIF/Viewers/issues/5824)) ([3d59c0d](https://github.com/OHIF/Viewers/commit/3d59c0d9d3783336eaa8d37cfc0172818942bf00))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.14...v3.13.0-beta.15) (2026-02-17)
|
||||
|
||||
|
||||
|
||||
+19
-35
@@ -20,49 +20,33 @@
|
||||
#
|
||||
|
||||
|
||||
# syntax=docker/dockerfile:1.7-labs
|
||||
# This dockerfile is used to publish the `ohif/app` image on dockerhub.
|
||||
#
|
||||
# It's a good example of how to build our static application and package it
|
||||
# with a web server capable of hosting it as static content.
|
||||
#
|
||||
# docker build
|
||||
# --------------
|
||||
# If you would like to use this dockerfile to build and tag an image, make sure
|
||||
# you set the context to the project's root directory:
|
||||
# https://docs.docker.com/engine/reference/commandline/build/
|
||||
#
|
||||
#
|
||||
# SUMMARY
|
||||
# --------------
|
||||
# This dockerfile is used as an input for a second stage to make things run faster.
|
||||
#
|
||||
|
||||
|
||||
# Stage 1: Build the application
|
||||
# docker build -t ohif/viewer:latest .
|
||||
# Copy Files
|
||||
FROM node:20.18.1-slim as builder
|
||||
FROM node:24-slim as builder
|
||||
|
||||
RUN apt-get update && apt-get install -y build-essential python3
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends build-essential python3 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN npm install -g pnpm@11
|
||||
|
||||
RUN mkdir /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
RUN npm install -g bun@1.2.23
|
||||
RUN npm install -g lerna@7.4.2
|
||||
ENV PATH=/usr/src/app/node_modules/.bin:$PATH
|
||||
|
||||
# Do an initial install and then a final install
|
||||
COPY package.json yarn.lock preinstall.js lerna.json ./
|
||||
COPY --parents ./addOns/package.json ./addOns/*/*/package.json ./extensions/*/package.json ./modes/*/package.json ./platform/*/package.json ./
|
||||
# Run the install before copying the rest of the files
|
||||
|
||||
RUN bun pm cache rm
|
||||
RUN bun install
|
||||
RUN bun add ajv@8.12.0
|
||||
# Copy package manifests for install caching. preinstall.js is included because
|
||||
# the root package.json's "preinstall" lifecycle script (node preinstall.js)
|
||||
# runs during `pnpm install` below -- before the full source is copied -- so the
|
||||
# script file must already be present or install fails with MODULE_NOT_FOUND.
|
||||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc preinstall.js ./
|
||||
COPY --parents ./extensions/*/package.json ./modes/*/package.json ./platform/*/package.json ./
|
||||
# Run the install before copying the rest of the files.
|
||||
# Keep --no-frozen-lockfile here (unlike CI): .dockerignore excludes
|
||||
# platform/docs, so the lockfile's docs importer has no manifest in the build
|
||||
# context and a frozen install would fail. pnpm reconciles (drops docs) instead.
|
||||
RUN pnpm install --no-frozen-lockfile
|
||||
# Copy the local directory
|
||||
COPY --link --exclude=yarn.lock --exclude=package.json --exclude=Dockerfile . .
|
||||
COPY --link --exclude=pnpm-lock.yaml --exclude=package.json --exclude=Dockerfile . .
|
||||
|
||||
# Build here
|
||||
# After install it should hopefully be stable until the local directory changes
|
||||
@@ -72,14 +56,14 @@ ARG APP_CONFIG=config/default.js
|
||||
ARG PUBLIC_URL=/
|
||||
ENV PUBLIC_URL=${PUBLIC_URL}
|
||||
|
||||
RUN bun run show:config
|
||||
RUN bun run build
|
||||
RUN pnpm run show:config
|
||||
RUN pnpm run build
|
||||
|
||||
# Precompress files
|
||||
RUN chmod u+x .docker/compressDist.sh
|
||||
RUN ./.docker/compressDist.sh
|
||||
|
||||
# Stage 3: Bundle the built application into a Docker container
|
||||
# Stage 2: Bundle the built application into a Docker container
|
||||
# which runs Nginx using Alpine Linux
|
||||
FROM nginxinc/nginx-unprivileged:1.27-alpine as final
|
||||
#RUN apk add --no-cache bash
|
||||
|
||||
@@ -49,6 +49,7 @@ provided by the <a href="https://ohif.org/">Open Health Imaging Foundation (OHIF
|
||||
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-4d.webp?raw=true" alt="4D" width="350"/> | 4D | [Demo](https://viewer.ohif.org/dynamic-volume?StudyInstanceUIDs=2.25.232704420736447710317909004159492840763) |
|
||||
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-video.webp?raw=true" alt="VIDEO" width="350"/> | Video | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=2.25.96975534054447904995905761963464388233) |
|
||||
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/microscopy.webp?raw=true" alt="microscopy" width="350"/> | Slide Microscopy | [Demo](https://viewer.ohif.org/microscopy?StudyInstanceUIDs=2.25.141277760791347900862109212450152067508) |
|
||||
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-ecg.webp?raw=true" alt="ECG" width="350"/> | ECG Waveform | [Demo](https://viewer-dev.ohif.org/viewer?StudyInstanceUIDs=2.25.209974489360710696739324151261716440238) |
|
||||
|
||||
## About
|
||||
|
||||
@@ -104,7 +105,6 @@ For commercial support, academic collaborations, and answers to common
|
||||
questions; please use [Get Support](https://ohif.org/get-support/) to contact
|
||||
us.
|
||||
|
||||
|
||||
## Developing
|
||||
|
||||
### Branches
|
||||
@@ -168,6 +168,64 @@ yarn config set workspaces-experimental true
|
||||
yarn install --frozen-lockfile
|
||||
```
|
||||
|
||||
### Cornerstone3D Integration Testing
|
||||
|
||||
OHIF's Playwright end-to-end tests can run against a **CS3D branch** or a
|
||||
**published CS3D version**, allowing changes that span both repositories to be
|
||||
validated together before merging.
|
||||
|
||||
#### Setting up an integration build
|
||||
|
||||
1. Add the **`ohif-integration`** label to your OHIF pull request.
|
||||
2. In the PR body, add a line specifying the CS3D ref:
|
||||
```
|
||||
CS3D_REF: feat/my-feature
|
||||
```
|
||||
- **Version ref** (e.g. `4.19+`, `4.18.2`) — the workflow resolves it to an
|
||||
exact published version and swaps the CS3D dependency via npm.
|
||||
- **Branch ref** (e.g. `main`, `cornerstonejs:feat/foo`) — the workflow
|
||||
clones the branch, builds CS3D from source with `bun run build:esm`, and
|
||||
symlinks the built packages into OHIF's `node_modules`.
|
||||
- For forks, use the `<owner>:<branch>` format
|
||||
(e.g. `myGithubUser:feat/foo`).
|
||||
- If no `CS3D_REF` is specified, the default is `4.19+`.
|
||||
3. The workflow can also be triggered manually via **workflow_dispatch** with a
|
||||
`cs3d_ref` input.
|
||||
|
||||
#### What happens in CI
|
||||
|
||||
The [Playwright workflow](.github/workflows/playwright.yml) runs two jobs:
|
||||
|
||||
| Job | Purpose |
|
||||
|-----|---------|
|
||||
| **Playwright Tests** | Builds OHIF (with CS3D linked or version-swapped), runs the full Playwright suite, uploads test results and coverage, and deploys a Netlify preview when `ohif-integration` is active. |
|
||||
| **CS3D Branch Merge Guard** | A lightweight check that **fails** when the `ohif-integration` label is present and `CS3D_REF` points to a branch (not a version). This prevents merging while still letting the Playwright tests show green so you can see whether the code actually works. |
|
||||
|
||||
#### Testing changes that span both repos
|
||||
|
||||
If a feature requires changes in both Cornerstone3D and OHIF:
|
||||
|
||||
1. Create your feature branch in CS3D and push it.
|
||||
2. Create a matching branch in OHIF.
|
||||
3. Add the `ohif-integration` label to the OHIF pull request.
|
||||
4. In the PR body, add: `CS3D_REF: <your-cs3d-branch>`.
|
||||
5. Playwright tests will build CS3D from source, link it, and run the full
|
||||
suite. The merge guard will block merge until you switch to a published
|
||||
version — but you can see the test results and the preview deploy while
|
||||
iterating.
|
||||
6. Once the CS3D side is merged and published, update the PR body to reference
|
||||
the published version (e.g. `CS3D_REF: 4.19+`). The tests will run against
|
||||
the registry version and the merge guard will pass.
|
||||
|
||||
#### Preview deploys
|
||||
|
||||
When `ohif-integration` is active, the Playwright workflow also builds the OHIF
|
||||
viewer and deploys it to Netlify as a preview. This gives you a live URL to
|
||||
manually test the combined CS3D + OHIF changes without running anything locally.
|
||||
|
||||
For details on linking CS3D locally for development, see the
|
||||
[Cornerstone3D README](libs/@cornerstonejs/README.md#local-development-linking--unlinking).
|
||||
|
||||
## Commands
|
||||
|
||||
These commands are available from the root directory. Each project directory
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# External Dependencies
|
||||
|
||||
This module contains optional dependencies and external dependencies for including in OHIF, such as the DICOM Microscopy Viewer component.
|
||||
-3991
File diff suppressed because it is too large.
Load diff
-95
@@ -1,95 +0,0 @@
|
||||
{
|
||||
"name": "@externals/devDependencies",
|
||||
"description": "External dev dependencies - put dev build dependencies here",
|
||||
"version": "3.13.0-beta.15",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"yarn": ">=1.19.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.2",
|
||||
"@kitware/vtk.js": "34.15.1",
|
||||
"clsx": "2.1.1",
|
||||
"core-js": "3.45.1",
|
||||
"moment": "2.30.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "7.28.0",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "0.5.17",
|
||||
"@rsbuild/core": "1.5.1",
|
||||
"@rsbuild/plugin-node-polyfill": "1.4.2",
|
||||
"@rsbuild/plugin-react": "1.4.0",
|
||||
"@svgr/webpack": "8.1.0",
|
||||
"@swc/helpers": "0.5.17",
|
||||
"@types/jest": "27.5.2",
|
||||
"@typescript-eslint/eslint-plugin": "6.21.0",
|
||||
"@typescript-eslint/parser": "6.21.0",
|
||||
"autoprefixer": "10.4.21",
|
||||
"babel-loader": "8.4.1",
|
||||
"babel-plugin-module-resolver": "5.0.2",
|
||||
"clean-webpack-plugin": "3.0.0",
|
||||
"copy-webpack-plugin": "9.1.0",
|
||||
"cross-env": "7.0.3",
|
||||
"css-loader": "6.11.0",
|
||||
"dotenv": "8.6.0",
|
||||
"eslint": "8.57.1",
|
||||
"eslint-config-prettier": "7.2.0",
|
||||
"eslint-config-react-app": "6.0.0",
|
||||
"eslint-plugin-cypress": "2.15.2",
|
||||
"eslint-plugin-flowtype": "7.0.0",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"eslint-plugin-jsx-a11y": "6.10.2",
|
||||
"eslint-plugin-node": "11.1.0",
|
||||
"eslint-plugin-prettier": "5.5.1",
|
||||
"eslint-plugin-promise": "5.2.0",
|
||||
"eslint-plugin-react": "7.37.5",
|
||||
"eslint-plugin-react-hooks": "4.6.2",
|
||||
"eslint-plugin-tsdoc": "0.2.17",
|
||||
"eslint-webpack-plugin": "2.7.0",
|
||||
"execa": "8.0.1",
|
||||
"extract-css-chunks-webpack-plugin": "4.10.0",
|
||||
"html-webpack-plugin": "5.6.3",
|
||||
"husky": "3.1.0",
|
||||
"jest": "29.7.0",
|
||||
"jest-canvas-mock": "2.5.2",
|
||||
"jest-environment-jsdom": "29.7.0",
|
||||
"jest-junit": "6.4.0",
|
||||
"lerna": "7.4.2",
|
||||
"lint-staged": "9.5.0",
|
||||
"mini-css-extract-plugin": "2.9.2",
|
||||
"optimize-css-assets-webpack-plugin": "6.0.1",
|
||||
"postcss": "8.5.6",
|
||||
"postcss-import": "14.1.0",
|
||||
"postcss-loader": "6.2.1",
|
||||
"postcss-preset-env": "7.8.3",
|
||||
"prettier": "3.6.2",
|
||||
"prettier-plugin-tailwindcss": "0.6.9",
|
||||
"react-refresh": "0.14.2",
|
||||
"semver": "7.7.2",
|
||||
"serve": "14.2.4",
|
||||
"shader-loader": "1.3.1",
|
||||
"shx": "0.3.4",
|
||||
"source-map-loader": "4.0.2",
|
||||
"style-loader": "1.3.0",
|
||||
"terser-webpack-plugin": "5.3.14",
|
||||
"typescript": "5.5.4",
|
||||
"unused-webpack-plugin": "2.4.0",
|
||||
"webpack": "5.105.0",
|
||||
"webpack-bundle-analyzer": "4.10.2",
|
||||
"webpack-cli": "5.1.4",
|
||||
"webpack-dev-server": "5.2.2",
|
||||
"webpack-hot-middleware": "2.26.1",
|
||||
"webpack-merge": "5.10.0",
|
||||
"workbox-webpack-plugin": "6.6.1",
|
||||
"worker-loader": "3.0.8"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "Included as direct dependency"
|
||||
}
|
||||
}
|
||||
-3964
File diff suppressed because it is too large.
Load diff
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"name": "@externals/dicom-microscopy-viewer",
|
||||
"description": "External reference to dicom-microscopy-viewer",
|
||||
"version": "3.13.0-beta.15",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dicom-microscopy-viewer": "0.48.17"
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
{
|
||||
"name": "ohif-monorepo-root",
|
||||
"private": true,
|
||||
"packageManager": "yarn@1.22.22",
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"../platform/i18n",
|
||||
"../platform/core",
|
||||
"../platform/ui",
|
||||
"../platform/ui-next",
|
||||
"../platform/app",
|
||||
"../extensions/*",
|
||||
"../modes/*",
|
||||
"../addOns/externals/*"
|
||||
],
|
||||
"nohoist": [
|
||||
"**/html-minifier-terser"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"preinstall": "cd .. && node preinstall.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.28.0",
|
||||
"@babel/plugin-transform-class-properties": "7.27.1",
|
||||
"@babel/plugin-transform-object-rest-spread": "7.28.0",
|
||||
"@babel/plugin-transform-private-methods": "7.27.1",
|
||||
"@babel/plugin-transform-private-property-in-object": "7.27.1",
|
||||
"@babel/plugin-syntax-dynamic-import": "7.8.3",
|
||||
"@babel/plugin-transform-arrow-functions": "7.27.1",
|
||||
"@babel/plugin-transform-regenerator": "7.28.1",
|
||||
"@babel/plugin-transform-runtime": "7.28.0",
|
||||
"@babel/plugin-transform-typescript": "7.28.0",
|
||||
"@babel/preset-env": "7.28.0",
|
||||
"@babel/preset-react": "7.27.1",
|
||||
"@babel/preset-typescript": "7.27.1"
|
||||
},
|
||||
"resolutions": {
|
||||
"**/@babel/runtime": "7.28.2",
|
||||
"commander": "8.3.0",
|
||||
"dcmjs": "0.49.4",
|
||||
"dicomweb-client": "0.10.4",
|
||||
"nth-check": "2.1.1",
|
||||
"trim-newlines": "5.0.0",
|
||||
"glob-parent": "6.0.2",
|
||||
"trim": "1.0.1",
|
||||
"package-json": "8.1.1",
|
||||
"typescript": "5.5.4"
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -26,7 +26,9 @@ module.exports = {
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
plugins: [
|
||||
'babel-plugin-istanbul',
|
||||
// jest's babel coverage provider injects babel-plugin-istanbul when
|
||||
// --collectCoverage is set; adding it here too makes babel 7 (pulled in
|
||||
// by jest 30) throw "Duplicate plugin/preset detected".
|
||||
'@babel/plugin-transform-object-rest-spread',
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
'@babel/plugin-transform-regenerator',
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
[install]
|
||||
frozenLockfile = true
|
||||
@@ -1,2 +0,0 @@
|
||||
[install]
|
||||
frozenLockfile = false
|
||||
+1
-1
@@ -1 +1 @@
|
||||
cca1a8683bc7d392a3a07268f24585642d13b1cd
|
||||
6dd150d401ad73d60632a23378b7dfd4b5142690
|
||||
@@ -1,8 +1,8 @@
|
||||
const webpack = require('webpack');
|
||||
const webpack = require('@rspack/core');
|
||||
const { merge } = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.base.js');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const MiniCssExtractPlugin = webpack.CssExtractRspackPlugin;
|
||||
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
@@ -35,9 +35,11 @@ module.exports = (env, argv) => {
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
library: {
|
||||
name: 'ohif-extension-cornerstone-dicom-pmap',
|
||||
type: 'umd',
|
||||
},
|
||||
path: ROOT_DIR,
|
||||
library: 'ohif-extension-cornerstone-dicom-pmap',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
},
|
||||
externals: [/\b(vtk.js)/, /\b(dcmjs)/, /\b(gl-matrix)/, /^@ohif/, /^@cornerstonejs/],
|
||||
|
||||
@@ -3,6 +3,619 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.13.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.88...v3.13.0-beta.89) (2026-06-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ohif tests to run with cornerstone 3d 5.0 ([#6043](https://github.com/OHIF/Viewers/issues/6043)) ([6dd150d](https://github.com/OHIF/Viewers/commit/6dd150d401ad73d60632a23378b7dfd4b5142690))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.87...v3.13.0-beta.88) (2026-06-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.86...v3.13.0-beta.87) (2026-05-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.85...v3.13.0-beta.86) (2026-05-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.84...v3.13.0-beta.85) (2026-05-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.83...v3.13.0-beta.84) (2026-05-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.82...v3.13.0-beta.83) (2026-05-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.81...v3.13.0-beta.82) (2026-05-22)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.80...v3.13.0-beta.81) (2026-05-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.79...v3.13.0-beta.80) (2026-05-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.78...v3.13.0-beta.79) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.77...v3.13.0-beta.78) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.76...v3.13.0-beta.77) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.75...v3.13.0-beta.76) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.74...v3.13.0-beta.75) (2026-05-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.73...v3.13.0-beta.74) (2026-05-15)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.72...v3.13.0-beta.73) (2026-05-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.71...v3.13.0-beta.72) (2026-05-12)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.70...v3.13.0-beta.71) (2026-05-07)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.69...v3.13.0-beta.70) (2026-05-07)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.68...v3.13.0-beta.69) (2026-05-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.67...v3.13.0-beta.68) (2026-05-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.66...v3.13.0-beta.67) (2026-04-30)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.65...v3.13.0-beta.66) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.64...v3.13.0-beta.65) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.63...v3.13.0-beta.64) (2026-04-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.62...v3.13.0-beta.63) (2026-04-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.61...v3.13.0-beta.62) (2026-04-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.60...v3.13.0-beta.61) (2026-04-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.59...v3.13.0-beta.60) (2026-04-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.58...v3.13.0-beta.59) (2026-04-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Use newer ONNX version and load without errors ([#5854](https://github.com/OHIF/Viewers/issues/5854)) ([cc5dc20](https://github.com/OHIF/Viewers/commit/cc5dc201649bcbfb4cfad21141dbd56000d30f53)), closes [#5875](https://github.com/OHIF/Viewers/issues/5875) [#5884](https://github.com/OHIF/Viewers/issues/5884) [#5886](https://github.com/OHIF/Viewers/issues/5886) [#5893](https://github.com/OHIF/Viewers/issues/5893) [#5874](https://github.com/OHIF/Viewers/issues/5874) [#5865](https://github.com/OHIF/Viewers/issues/5865)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.57...v3.13.0-beta.58) (2026-04-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.56...v3.13.0-beta.57) (2026-04-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.55...v3.13.0-beta.56) (2026-04-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* A couple of changes to enable cs3d integration build ([#5944](https://github.com/OHIF/Viewers/issues/5944)) ([f6bbd5c](https://github.com/OHIF/Viewers/commit/f6bbd5c779e4692dc47c93327a890661b8dcc174))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.54...v3.13.0-beta.55) (2026-04-10)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.53...v3.13.0-beta.54) (2026-04-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.52...v3.13.0-beta.53) (2026-04-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.51...v3.13.0-beta.52) (2026-04-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.50...v3.13.0-beta.51) (2026-04-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.49...v3.13.0-beta.50) (2026-04-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.48...v3.13.0-beta.49) (2026-04-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.47...v3.13.0-beta.48) (2026-04-01)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.46...v3.13.0-beta.47) (2026-03-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.45...v3.13.0-beta.46) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.44...v3.13.0-beta.45) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.43...v3.13.0-beta.44) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.42...v3.13.0-beta.43) (2026-03-17)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.41...v3.13.0-beta.42) (2026-03-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add combined build ([#5895](https://github.com/OHIF/Viewers/issues/5895)) ([1df671e](https://github.com/OHIF/Viewers/commit/1df671e9ab67d43f98bf09f6838ddc0a5f220277))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.40...v3.13.0-beta.41) (2026-03-16)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.39...v3.13.0-beta.40) (2026-03-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.38...v3.13.0-beta.39) (2026-03-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.37...v3.13.0-beta.38) (2026-03-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** Display "No description S:{series number} {modality}" for segmentations with no label. ([#5874](https://github.com/OHIF/Viewers/issues/5874)) ([7b5d0ce](https://github.com/OHIF/Viewers/commit/7b5d0ce40e5422ccfce6091ac3d7559586cbe57e))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.36...v3.13.0-beta.37) (2026-03-12)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.35...v3.13.0-beta.36) (2026-03-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.34...v3.13.0-beta.35) (2026-03-09)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.33...v3.13.0-beta.34) (2026-03-09)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.32...v3.13.0-beta.33) (2026-03-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.31...v3.13.0-beta.32) (2026-03-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.30...v3.13.0-beta.31) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.29...v3.13.0-beta.30) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.28...v3.13.0-beta.29) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.27...v3.13.0-beta.28) (2026-03-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.26...v3.13.0-beta.27) (2026-03-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.25...v3.13.0-beta.26) (2026-02-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.24...v3.13.0-beta.25) (2026-02-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Update CS3D 4.18.2 ([#5837](https://github.com/OHIF/Viewers/issues/5837)) ([5370b93](https://github.com/OHIF/Viewers/commit/5370b9382e7bfddeadd69bab9e653f5f997a6e19))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.23...v3.13.0-beta.24) (2026-02-24)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.22...v3.13.0-beta.23) (2026-02-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* palette color 8 encoded 16 ([#5823](https://github.com/OHIF/Viewers/issues/5823)) ([eeca1f7](https://github.com/OHIF/Viewers/commit/eeca1f7a7b529d1700f5d281a6fd98074547ffe9)), closes [#5813](https://github.com/OHIF/Viewers/issues/5813)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.21...v3.13.0-beta.22) (2026-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.20...v3.13.0-beta.21) (2026-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.19...v3.13.0-beta.20) (2026-02-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.18...v3.13.0-beta.19) (2026-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.17...v3.13.0-beta.18) (2026-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.16...v3.13.0-beta.17) (2026-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.15...v3.13.0-beta.16) (2026-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.14...v3.13.0-beta.15) (2026-02-17)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-pmap
|
||||
|
||||
@@ -1,42 +1,37 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone-dicom-pmap",
|
||||
"version": "3.13.0-beta.15",
|
||||
"version": "3.13.0-beta.97",
|
||||
"description": "DICOM Parametric Map read workflow",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
"repository": "OHIF/Viewers",
|
||||
"main": "dist/ohif-extension-cornerstone-dicom-pmap.umd.js",
|
||||
"module": "src/index.tsx",
|
||||
"engines": {
|
||||
"node": ">=24"
|
||||
},
|
||||
"files": [
|
||||
"dist/**",
|
||||
"public/**",
|
||||
"README.md"
|
||||
],
|
||||
"repository": "OHIF/Viewers",
|
||||
"keywords": [
|
||||
"ohif-extension"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14",
|
||||
"npm": ">=6",
|
||||
"yarn": ">=1.18.0"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:dicom-pmap": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
"build:package-1": "yarn run build",
|
||||
"start": "yarn run dev"
|
||||
"clean:deep": "pnpm run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development rspack build --config .webpack/webpack.dev.js --watch",
|
||||
"dev:dicom-pmap": "pnpm run dev",
|
||||
"build": "cross-env NODE_ENV=production rspack build --config .webpack/webpack.prod.js",
|
||||
"build:package-1": "pnpm run build",
|
||||
"start": "pnpm run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.13.0-beta.15",
|
||||
"@ohif/extension-cornerstone": "3.13.0-beta.15",
|
||||
"@ohif/extension-default": "3.13.0-beta.15",
|
||||
"@ohif/i18n": "3.13.0-beta.15",
|
||||
"@ohif/core": "workspace:*",
|
||||
"@ohif/extension-cornerstone": "workspace:*",
|
||||
"@ohif/extension-default": "workspace:*",
|
||||
"@ohif/i18n": "workspace:*",
|
||||
"prop-types": "15.8.1",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
@@ -45,9 +40,15 @@
|
||||
"react-router-dom": "6.30.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.2",
|
||||
"@cornerstonejs/adapters": "4.15.29",
|
||||
"@cornerstonejs/core": "4.15.29",
|
||||
"@kitware/vtk.js": "34.15.1"
|
||||
}
|
||||
"@babel/runtime": "7.29.7",
|
||||
"@cornerstonejs/adapters": "5.0.2",
|
||||
"@cornerstonejs/core": "5.0.2",
|
||||
"@kitware/vtk.js": "35.5.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "7.0.3"
|
||||
},
|
||||
"keywords": [
|
||||
"ohif-extension"
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
const webpack = require('webpack');
|
||||
const webpack = require('@rspack/core');
|
||||
const { merge } = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.base.js');
|
||||
@@ -32,9 +32,11 @@ module.exports = (env, argv) => {
|
||||
sideEffects: false,
|
||||
},
|
||||
output: {
|
||||
library: {
|
||||
name: 'ohif-extension-cornerstone-dicom-rt',
|
||||
type: 'umd',
|
||||
},
|
||||
path: ROOT_DIR,
|
||||
library: 'ohif-extension-cornerstone-dicom-rt',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
},
|
||||
externals: [/\b(vtk.js)/, /\b(dcmjs)/, /\b(gl-matrix)/, /^@ohif/, /^@cornerstonejs/],
|
||||
|
||||
@@ -3,6 +3,607 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.13.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.88...v3.13.0-beta.89) (2026-06-10)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.87...v3.13.0-beta.88) (2026-06-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.86...v3.13.0-beta.87) (2026-05-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.85...v3.13.0-beta.86) (2026-05-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.84...v3.13.0-beta.85) (2026-05-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.83...v3.13.0-beta.84) (2026-05-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.82...v3.13.0-beta.83) (2026-05-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.81...v3.13.0-beta.82) (2026-05-22)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.80...v3.13.0-beta.81) (2026-05-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.79...v3.13.0-beta.80) (2026-05-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.78...v3.13.0-beta.79) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.77...v3.13.0-beta.78) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.76...v3.13.0-beta.77) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.75...v3.13.0-beta.76) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.74...v3.13.0-beta.75) (2026-05-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.73...v3.13.0-beta.74) (2026-05-15)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.72...v3.13.0-beta.73) (2026-05-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.71...v3.13.0-beta.72) (2026-05-12)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.70...v3.13.0-beta.71) (2026-05-07)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.69...v3.13.0-beta.70) (2026-05-07)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.68...v3.13.0-beta.69) (2026-05-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.67...v3.13.0-beta.68) (2026-05-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.66...v3.13.0-beta.67) (2026-04-30)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.65...v3.13.0-beta.66) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.64...v3.13.0-beta.65) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.63...v3.13.0-beta.64) (2026-04-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.62...v3.13.0-beta.63) (2026-04-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.61...v3.13.0-beta.62) (2026-04-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.60...v3.13.0-beta.61) (2026-04-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.59...v3.13.0-beta.60) (2026-04-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.58...v3.13.0-beta.59) (2026-04-16)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.57...v3.13.0-beta.58) (2026-04-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.56...v3.13.0-beta.57) (2026-04-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.55...v3.13.0-beta.56) (2026-04-10)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.54...v3.13.0-beta.55) (2026-04-10)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.53...v3.13.0-beta.54) (2026-04-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.52...v3.13.0-beta.53) (2026-04-06)
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* rename DisplaySet.frameOfReferenceUID back to FrameOfReferenceUID ([#5943](https://github.com/OHIF/Viewers/issues/5943)) ([0e933c2](https://github.com/OHIF/Viewers/commit/0e933c256e07b7cda35ed2ba3cfb1ab35d895d57))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.51...v3.13.0-beta.52) (2026-04-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.50...v3.13.0-beta.51) (2026-04-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.49...v3.13.0-beta.50) (2026-04-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.48...v3.13.0-beta.49) (2026-04-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** restrict overlay segmentation menu to same frame of reference as viewport background display set ([#5900](https://github.com/OHIF/Viewers/issues/5900)) ([b9029ef](https://github.com/OHIF/Viewers/commit/b9029ef6f8d63a0e36ec929310c1c5ad3f563ef8))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.47...v3.13.0-beta.48) (2026-04-01)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.46...v3.13.0-beta.47) (2026-03-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.45...v3.13.0-beta.46) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.44...v3.13.0-beta.45) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.43...v3.13.0-beta.44) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.42...v3.13.0-beta.43) (2026-03-17)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.41...v3.13.0-beta.42) (2026-03-17)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.40...v3.13.0-beta.41) (2026-03-16)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.39...v3.13.0-beta.40) (2026-03-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.38...v3.13.0-beta.39) (2026-03-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.37...v3.13.0-beta.38) (2026-03-12)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.36...v3.13.0-beta.37) (2026-03-12)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.35...v3.13.0-beta.36) (2026-03-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.34...v3.13.0-beta.35) (2026-03-09)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.33...v3.13.0-beta.34) (2026-03-09)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.32...v3.13.0-beta.33) (2026-03-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.31...v3.13.0-beta.32) (2026-03-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.30...v3.13.0-beta.31) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.29...v3.13.0-beta.30) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.28...v3.13.0-beta.29) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.27...v3.13.0-beta.28) (2026-03-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.26...v3.13.0-beta.27) (2026-03-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.25...v3.13.0-beta.26) (2026-02-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.24...v3.13.0-beta.25) (2026-02-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.23...v3.13.0-beta.24) (2026-02-24)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.22...v3.13.0-beta.23) (2026-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.21...v3.13.0-beta.22) (2026-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.20...v3.13.0-beta.21) (2026-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.19...v3.13.0-beta.20) (2026-02-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.18...v3.13.0-beta.19) (2026-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.17...v3.13.0-beta.18) (2026-02-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation overlay:** update viewport ds list upon seg delete - OHIF-2425 ([#5729](https://github.com/OHIF/Viewers/issues/5729)) ([b353541](https://github.com/OHIF/Viewers/commit/b35354120a01d89b27844f967c32c052bba8b096))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.16...v3.13.0-beta.17) (2026-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.15...v3.13.0-beta.16) (2026-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.14...v3.13.0-beta.15) (2026-02-17)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-rt
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone-dicom-rt",
|
||||
"version": "3.13.0-beta.15",
|
||||
"version": "3.13.0-beta.97",
|
||||
"description": "DICOM RT read workflow",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
"repository": "OHIF/Viewers",
|
||||
"main": "dist/ohif-extension-cornerstone-dicom-rt.umd.js",
|
||||
"module": "src/index.tsx",
|
||||
"engines": {
|
||||
"node": ">=24"
|
||||
},
|
||||
"files": [
|
||||
"dist/**",
|
||||
"public/**",
|
||||
@@ -14,29 +18,20 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": "OHIF/Viewers",
|
||||
"keywords": [
|
||||
"ohif-extension"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14",
|
||||
"npm": ">=6",
|
||||
"yarn": ">=1.18.0"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:dicom-seg": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
"build:package-1": "yarn run build",
|
||||
"start": "yarn run dev"
|
||||
"clean:deep": "pnpm run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development rspack build --config .webpack/webpack.dev.js --watch",
|
||||
"dev:dicom-seg": "pnpm run dev",
|
||||
"build": "cross-env NODE_ENV=production rspack build --config .webpack/webpack.prod.js",
|
||||
"build:package-1": "pnpm run build",
|
||||
"start": "pnpm run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.13.0-beta.15",
|
||||
"@ohif/extension-cornerstone": "3.13.0-beta.15",
|
||||
"@ohif/extension-default": "3.13.0-beta.15",
|
||||
"@ohif/i18n": "3.13.0-beta.15",
|
||||
"@ohif/core": "workspace:*",
|
||||
"@ohif/extension-cornerstone": "workspace:*",
|
||||
"@ohif/extension-default": "workspace:*",
|
||||
"@ohif/i18n": "workspace:*",
|
||||
"prop-types": "15.8.1",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
@@ -45,6 +40,12 @@
|
||||
"react-router-dom": "6.30.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.2"
|
||||
}
|
||||
"@babel/runtime": "7.29.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "7.0.3"
|
||||
},
|
||||
"keywords": [
|
||||
"ohif-extension"
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { utils, Types as OhifTypes } from '@ohif/core';
|
||||
import i18n from '@ohif/i18n';
|
||||
import { segmentation as cstSegmentation } from '@cornerstonejs/tools';
|
||||
|
||||
import { SOPClassHandlerId } from './id';
|
||||
import loadRTStruct from './loadRTStruct';
|
||||
@@ -8,8 +9,6 @@ const { sopClassDictionary } = utils;
|
||||
|
||||
const sopClassUids = [sopClassDictionary.RTStructureSetStorage];
|
||||
|
||||
const cachedRTStructsSEG = new Set<string>();
|
||||
|
||||
const loadPromises = {};
|
||||
|
||||
function _getDisplaySetsFromSeries(
|
||||
@@ -57,6 +56,7 @@ function _getDisplaySetsFromSeries(
|
||||
StudyInstanceUID,
|
||||
SOPClassHandlerId,
|
||||
SOPClassUID,
|
||||
FrameOfReferenceUID: null,
|
||||
referencedImages: null,
|
||||
referencedSeriesInstanceUID: null,
|
||||
referencedDisplaySetInstanceUID: null,
|
||||
@@ -96,6 +96,9 @@ function _getDisplaySetsFromSeries(
|
||||
displaySet.referencedImages = instance.ReferencedSeriesSequence.ReferencedInstanceSequence;
|
||||
displaySet.referencedSeriesInstanceUID = referencedSeries.SeriesInstanceUID;
|
||||
|
||||
displaySet.FrameOfReferenceUID =
|
||||
instance.ReferencedFrameOfReferenceSequence?.[0]?.FrameOfReferenceUID;
|
||||
|
||||
const { displaySetService } = servicesManager.services;
|
||||
const referencedDisplaySets =
|
||||
displaySetService.getDisplaySetsForReferences(referencedSeriesSequence);
|
||||
@@ -114,6 +117,7 @@ function _getDisplaySetsFromSeries(
|
||||
if (addedDisplaySet.SeriesInstanceUID === displaySet.referencedSeriesInstanceUID) {
|
||||
displaySet.referencedDisplaySetInstanceUID = addedDisplaySet.displaySetInstanceUID;
|
||||
displaySet.isReconstructable = addedDisplaySet.isReconstructable;
|
||||
displaySet.FrameOfReferenceUID = addedDisplaySet.FrameOfReferenceUID;
|
||||
unsubscribe();
|
||||
}
|
||||
}
|
||||
@@ -122,6 +126,7 @@ function _getDisplaySetsFromSeries(
|
||||
const [referencedDisplaySet] = referencedDisplaySets;
|
||||
displaySet.referencedDisplaySetInstanceUID = referencedDisplaySet.displaySetInstanceUID;
|
||||
displaySet.isReconstructable = referencedDisplaySet.isReconstructable;
|
||||
displaySet.FrameOfReferenceUID = referencedDisplaySet.FrameOfReferenceUID;
|
||||
}
|
||||
|
||||
displaySet.load = ({ headers, createSegmentation = true }) =>
|
||||
@@ -143,23 +148,13 @@ function _load(
|
||||
if (
|
||||
(rtDisplaySet.loading || rtDisplaySet.isLoaded) &&
|
||||
loadPromises[SOPInstanceUID] &&
|
||||
cachedRTStructsSEG.has(rtDisplaySet.displaySetInstanceUID)
|
||||
_segmentationExists(rtDisplaySet)
|
||||
) {
|
||||
return loadPromises[SOPInstanceUID];
|
||||
}
|
||||
|
||||
rtDisplaySet.loading = true;
|
||||
|
||||
const { unsubscribe } = segmentationService.subscribe(
|
||||
segmentationService.EVENTS.SEGMENTATION_LOADING_COMPLETE,
|
||||
(evt: { rtDisplaySet: { displaySetInstanceUID: string } }) => {
|
||||
if (evt.rtDisplaySet?.displaySetInstanceUID === rtDisplaySet.displaySetInstanceUID) {
|
||||
cachedRTStructsSEG.add(rtDisplaySet.displaySetInstanceUID);
|
||||
unsubscribe();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// We don't want to fire multiple loads, so we'll wait for the first to finish
|
||||
// and also return the same promise to any other callers.
|
||||
loadPromises[SOPInstanceUID] = new Promise<void>(async (resolve, reject) => {
|
||||
@@ -219,6 +214,10 @@ function _deriveReferencedSeriesSequenceFromFrameOfReferenceSequence(
|
||||
return ReferencedSeriesSequence;
|
||||
}
|
||||
|
||||
function _segmentationExists(segDisplaySet) {
|
||||
return !!cstSegmentation.state.getSegmentation(segDisplaySet.displaySetInstanceUID);
|
||||
}
|
||||
|
||||
function getSopClassHandlerModule(params: OhifTypes.Extensions.ExtensionParams) {
|
||||
const { servicesManager, extensionManager } = params;
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ function OHIFCornerstoneRTViewport(props: withAppTypes) {
|
||||
|
||||
return () => {
|
||||
// remove the segmentation representations if seg displayset changed
|
||||
segmentationService.removeSegmentationRepresentations(viewportId);
|
||||
segmentationService.removeRepresentationsFromViewport(viewportId);
|
||||
referencedDisplaySetRef.current = null;
|
||||
toolGroupService.destroyToolGroup(toolGroupId);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const webpack = require('webpack');
|
||||
const webpack = require('@rspack/core');
|
||||
const { merge } = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.base.js');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const MiniCssExtractPlugin = webpack.CssExtractRspackPlugin;
|
||||
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
@@ -35,9 +35,11 @@ module.exports = (env, argv) => {
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
library: {
|
||||
name: 'ohif-extension-cornerstone-dicom-seg',
|
||||
type: 'umd',
|
||||
},
|
||||
path: ROOT_DIR,
|
||||
library: 'ohif-extension-cornerstone-dicom-seg',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
},
|
||||
externals: [/\b(vtk.js)/, /\b(dcmjs)/, /\b(gl-matrix)/, /^@ohif/, /^@cornerstonejs/],
|
||||
|
||||
@@ -3,6 +3,628 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.13.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.88...v3.13.0-beta.89) (2026-06-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ohif tests to run with cornerstone 3d 5.0 ([#6043](https://github.com/OHIF/Viewers/issues/6043)) ([6dd150d](https://github.com/OHIF/Viewers/commit/6dd150d401ad73d60632a23378b7dfd4b5142690))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.87...v3.13.0-beta.88) (2026-06-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.86...v3.13.0-beta.87) (2026-05-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.85...v3.13.0-beta.86) (2026-05-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.84...v3.13.0-beta.85) (2026-05-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.83...v3.13.0-beta.84) (2026-05-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.82...v3.13.0-beta.83) (2026-05-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.81...v3.13.0-beta.82) (2026-05-22)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.80...v3.13.0-beta.81) (2026-05-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.79...v3.13.0-beta.80) (2026-05-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.78...v3.13.0-beta.79) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.77...v3.13.0-beta.78) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.76...v3.13.0-beta.77) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.75...v3.13.0-beta.76) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.74...v3.13.0-beta.75) (2026-05-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.73...v3.13.0-beta.74) (2026-05-15)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.72...v3.13.0-beta.73) (2026-05-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.71...v3.13.0-beta.72) (2026-05-12)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.70...v3.13.0-beta.71) (2026-05-07)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.69...v3.13.0-beta.70) (2026-05-07)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.68...v3.13.0-beta.69) (2026-05-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.67...v3.13.0-beta.68) (2026-05-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.66...v3.13.0-beta.67) (2026-04-30)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.65...v3.13.0-beta.66) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.64...v3.13.0-beta.65) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.63...v3.13.0-beta.64) (2026-04-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.62...v3.13.0-beta.63) (2026-04-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.61...v3.13.0-beta.62) (2026-04-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.60...v3.13.0-beta.61) (2026-04-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.59...v3.13.0-beta.60) (2026-04-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.58...v3.13.0-beta.59) (2026-04-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Use newer ONNX version and load without errors ([#5854](https://github.com/OHIF/Viewers/issues/5854)) ([cc5dc20](https://github.com/OHIF/Viewers/commit/cc5dc201649bcbfb4cfad21141dbd56000d30f53)), closes [#5875](https://github.com/OHIF/Viewers/issues/5875) [#5884](https://github.com/OHIF/Viewers/issues/5884) [#5886](https://github.com/OHIF/Viewers/issues/5886) [#5893](https://github.com/OHIF/Viewers/issues/5893) [#5874](https://github.com/OHIF/Viewers/issues/5874) [#5865](https://github.com/OHIF/Viewers/issues/5865)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.57...v3.13.0-beta.58) (2026-04-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.56...v3.13.0-beta.57) (2026-04-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.55...v3.13.0-beta.56) (2026-04-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* A couple of changes to enable cs3d integration build ([#5944](https://github.com/OHIF/Viewers/issues/5944)) ([f6bbd5c](https://github.com/OHIF/Viewers/commit/f6bbd5c779e4692dc47c93327a890661b8dcc174))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.54...v3.13.0-beta.55) (2026-04-10)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.53...v3.13.0-beta.54) (2026-04-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.52...v3.13.0-beta.53) (2026-04-06)
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* rename DisplaySet.frameOfReferenceUID back to FrameOfReferenceUID ([#5943](https://github.com/OHIF/Viewers/issues/5943)) ([0e933c2](https://github.com/OHIF/Viewers/commit/0e933c256e07b7cda35ed2ba3cfb1ab35d895d57))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.51...v3.13.0-beta.52) (2026-04-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.50...v3.13.0-beta.51) (2026-04-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.49...v3.13.0-beta.50) (2026-04-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.48...v3.13.0-beta.49) (2026-04-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** restrict overlay segmentation menu to same frame of reference as viewport background display set ([#5900](https://github.com/OHIF/Viewers/issues/5900)) ([b9029ef](https://github.com/OHIF/Viewers/commit/b9029ef6f8d63a0e36ec929310c1c5ad3f563ef8))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.47...v3.13.0-beta.48) (2026-04-01)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.46...v3.13.0-beta.47) (2026-03-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.45...v3.13.0-beta.46) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.44...v3.13.0-beta.45) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.43...v3.13.0-beta.44) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.42...v3.13.0-beta.43) (2026-03-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **SR:** Added support for spline and live wire SR items. ([#5870](https://github.com/OHIF/Viewers/issues/5870)) ([1d4802c](https://github.com/OHIF/Viewers/commit/1d4802c2a38dd75dca7afca87913e100453c9135))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.41...v3.13.0-beta.42) (2026-03-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add combined build ([#5895](https://github.com/OHIF/Viewers/issues/5895)) ([1df671e](https://github.com/OHIF/Viewers/commit/1df671e9ab67d43f98bf09f6838ddc0a5f220277))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.40...v3.13.0-beta.41) (2026-03-16)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.39...v3.13.0-beta.40) (2026-03-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.38...v3.13.0-beta.39) (2026-03-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.37...v3.13.0-beta.38) (2026-03-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** Display "No description S:{series number} {modality}" for segmentations with no label. ([#5874](https://github.com/OHIF/Viewers/issues/5874)) ([7b5d0ce](https://github.com/OHIF/Viewers/commit/7b5d0ce40e5422ccfce6091ac3d7559586cbe57e))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.36...v3.13.0-beta.37) (2026-03-12)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.35...v3.13.0-beta.36) (2026-03-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.34...v3.13.0-beta.35) (2026-03-09)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.33...v3.13.0-beta.34) (2026-03-09)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.32...v3.13.0-beta.33) (2026-03-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.31...v3.13.0-beta.32) (2026-03-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.30...v3.13.0-beta.31) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.29...v3.13.0-beta.30) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.28...v3.13.0-beta.29) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.27...v3.13.0-beta.28) (2026-03-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.26...v3.13.0-beta.27) (2026-03-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.25...v3.13.0-beta.26) (2026-02-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.24...v3.13.0-beta.25) (2026-02-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Update CS3D 4.18.2 ([#5837](https://github.com/OHIF/Viewers/issues/5837)) ([5370b93](https://github.com/OHIF/Viewers/commit/5370b9382e7bfddeadd69bab9e653f5f997a6e19))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.23...v3.13.0-beta.24) (2026-02-24)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.22...v3.13.0-beta.23) (2026-02-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* palette color 8 encoded 16 ([#5823](https://github.com/OHIF/Viewers/issues/5823)) ([eeca1f7](https://github.com/OHIF/Viewers/commit/eeca1f7a7b529d1700f5d281a6fd98074547ffe9)), closes [#5813](https://github.com/OHIF/Viewers/issues/5813)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.21...v3.13.0-beta.22) (2026-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.20...v3.13.0-beta.21) (2026-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.19...v3.13.0-beta.20) (2026-02-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.18...v3.13.0-beta.19) (2026-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.17...v3.13.0-beta.18) (2026-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.16...v3.13.0-beta.17) (2026-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.15...v3.13.0-beta.16) (2026-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.14...v3.13.0-beta.15) (2026-02-17)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-seg
|
||||
|
||||
@@ -1,42 +1,37 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone-dicom-seg",
|
||||
"version": "3.13.0-beta.15",
|
||||
"version": "3.13.0-beta.97",
|
||||
"description": "DICOM SEG read workflow",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
"repository": "OHIF/Viewers",
|
||||
"main": "dist/ohif-extension-cornerstone-dicom-seg.umd.js",
|
||||
"module": "src/index.tsx",
|
||||
"engines": {
|
||||
"node": ">=24"
|
||||
},
|
||||
"files": [
|
||||
"dist/**",
|
||||
"public/**",
|
||||
"README.md"
|
||||
],
|
||||
"repository": "OHIF/Viewers",
|
||||
"keywords": [
|
||||
"ohif-extension"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14",
|
||||
"npm": ">=6",
|
||||
"yarn": ">=1.18.0"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:dicom-seg": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
"build:package-1": "yarn run build",
|
||||
"start": "yarn run dev"
|
||||
"clean:deep": "pnpm run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development rspack build --config .webpack/webpack.dev.js --watch",
|
||||
"dev:dicom-seg": "pnpm run dev",
|
||||
"build": "cross-env NODE_ENV=production rspack build --config .webpack/webpack.prod.js",
|
||||
"build:package-1": "pnpm run build",
|
||||
"start": "pnpm run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.13.0-beta.15",
|
||||
"@ohif/extension-cornerstone": "3.13.0-beta.15",
|
||||
"@ohif/extension-default": "3.13.0-beta.15",
|
||||
"@ohif/i18n": "3.13.0-beta.15",
|
||||
"@ohif/core": "workspace:*",
|
||||
"@ohif/extension-cornerstone": "workspace:*",
|
||||
"@ohif/extension-default": "workspace:*",
|
||||
"@ohif/i18n": "workspace:*",
|
||||
"prop-types": "15.8.1",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
@@ -45,9 +40,15 @@
|
||||
"react-router-dom": "6.30.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.2",
|
||||
"@cornerstonejs/adapters": "4.15.29",
|
||||
"@cornerstonejs/core": "4.15.29",
|
||||
"@kitware/vtk.js": "34.15.1"
|
||||
}
|
||||
"@babel/runtime": "7.29.7",
|
||||
"@cornerstonejs/adapters": "5.0.2",
|
||||
"@cornerstonejs/core": "5.0.2",
|
||||
"@kitware/vtk.js": "35.5.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "7.0.3"
|
||||
},
|
||||
"keywords": [
|
||||
"ohif-extension"
|
||||
]
|
||||
}
|
||||
@@ -2,9 +2,8 @@ import dcmjs from 'dcmjs';
|
||||
import { classes, Types, utils } from '@ohif/core';
|
||||
import { cache, metaData } from '@cornerstonejs/core';
|
||||
import { segmentation as cornerstoneToolsSegmentation } from '@cornerstonejs/tools';
|
||||
import { adaptersRT, helpers, adaptersSEG } from '@cornerstonejs/adapters';
|
||||
import { adaptersRT, adaptersSEG } from '@cornerstonejs/adapters';
|
||||
import { createReportDialogPrompt, useUIStateStore } from '@ohif/extension-default';
|
||||
import { DicomMetadataStore } from '@ohif/core';
|
||||
|
||||
import PROMPT_RESPONSES from '../../default/src/utils/_shared/PROMPT_RESPONSES';
|
||||
|
||||
@@ -29,11 +28,11 @@ const {
|
||||
},
|
||||
} = adaptersRT;
|
||||
|
||||
const { downloadDICOMData } = helpers;
|
||||
|
||||
const commandsModule = ({
|
||||
servicesManager,
|
||||
extensionManager,
|
||||
commandsManager,
|
||||
}: Types.Extensions.ExtensionParams): Types.Extensions.CommandsModule => {
|
||||
const { segmentationService, displaySetService, viewportGridService } =
|
||||
servicesManager.services as AppTypes.Services;
|
||||
@@ -194,8 +193,11 @@ const commandsModule = ({
|
||||
const generatedSegmentation = actions.generateSegmentation({
|
||||
segmentationId,
|
||||
});
|
||||
|
||||
downloadDICOMData(generatedSegmentation.dataset, `${segmentationInOHIF.label}`);
|
||||
const storeFn = commandsManager.runCommand('createStoreFunction', {
|
||||
dataSource: 'download',
|
||||
defaultFileName: `${segmentationInOHIF.label}.dcm`,
|
||||
});
|
||||
storeFn(generatedSegmentation.dataset);
|
||||
},
|
||||
/**
|
||||
* Stores a segmentation based on the provided segmentationId into a specified data source.
|
||||
@@ -217,11 +219,10 @@ const commandsModule = ({
|
||||
}
|
||||
|
||||
const { label, predecessorImageId } = segmentation;
|
||||
const defaultDataSource = dataSource ?? extensionManager.getActiveDataSource()[0];
|
||||
|
||||
const {
|
||||
value: reportName,
|
||||
dataSourceName: selectedDataSource,
|
||||
dataSourceName,
|
||||
series,
|
||||
priorSeriesNumber,
|
||||
action,
|
||||
@@ -231,50 +232,58 @@ const commandsModule = ({
|
||||
predecessorImageId,
|
||||
title: 'Store Segmentation',
|
||||
modality,
|
||||
enableDownload: true,
|
||||
});
|
||||
|
||||
if (action === PROMPT_RESPONSES.CREATE_REPORT) {
|
||||
try {
|
||||
const selectedDataSourceConfig = selectedDataSource
|
||||
? extensionManager.getDataSources(selectedDataSource)[0]
|
||||
: defaultDataSource;
|
||||
if (action !== PROMPT_RESPONSES.CREATE_REPORT) {
|
||||
return;
|
||||
}
|
||||
|
||||
const args = {
|
||||
segmentationId,
|
||||
options: {
|
||||
SeriesDescription: series ? undefined : reportName || label || 'Contour Series',
|
||||
SeriesNumber: series ? undefined : 1 + priorSeriesNumber,
|
||||
predecessorImageId: series,
|
||||
},
|
||||
};
|
||||
const generatedDataAsync =
|
||||
(modality === 'SEG' && actions.generateSegmentation(args)) ||
|
||||
(modality === 'RTSTRUCT' && actions.generateContour(args));
|
||||
const generatedData = await generatedDataAsync;
|
||||
const defaultFileName =
|
||||
modality === 'RTSTRUCT'
|
||||
? `rtss-${segmentationId}.dcm`
|
||||
: `${label || 'segmentation'}.dcm`;
|
||||
|
||||
if (!generatedData || !generatedData.dataset) {
|
||||
throw new Error('Error during segmentation generation');
|
||||
}
|
||||
const storeFn = commandsManager.runCommand('createStoreFunction', {
|
||||
dataSource: dataSourceName,
|
||||
defaultFileName,
|
||||
});
|
||||
|
||||
const { dataset: naturalizedReport } = generatedData;
|
||||
if (!storeFn) {
|
||||
throw new Error(`No valid store for dataSource: ${dataSourceName}`);
|
||||
}
|
||||
|
||||
// DCMJS assigns a dummy study id during creation, and this can cause problems, so clearing it out
|
||||
if (naturalizedReport.StudyID === 'No Study ID') {
|
||||
naturalizedReport.StudyID = '';
|
||||
}
|
||||
try {
|
||||
const args = {
|
||||
segmentationId,
|
||||
options: {
|
||||
SeriesDescription: series ? undefined : reportName || label || 'Contour Series',
|
||||
SeriesNumber: series ? undefined : 1 + priorSeriesNumber,
|
||||
predecessorImageId: series,
|
||||
},
|
||||
};
|
||||
const generatedDataAsync =
|
||||
(modality === 'SEG' && actions.generateSegmentation(args)) ||
|
||||
(modality === 'RTSTRUCT' && actions.generateContour(args));
|
||||
const generatedData = await generatedDataAsync;
|
||||
|
||||
await selectedDataSourceConfig.store.dicom(naturalizedReport);
|
||||
|
||||
// add the information for where we stored it to the instance as well
|
||||
naturalizedReport.wadoRoot = selectedDataSourceConfig.getConfig().wadoRoot;
|
||||
|
||||
DicomMetadataStore.addInstances([naturalizedReport], true);
|
||||
|
||||
return naturalizedReport;
|
||||
} catch (error) {
|
||||
console.debug('Error storing segmentation:', error);
|
||||
throw error;
|
||||
if (!generatedData?.dataset) {
|
||||
throw new Error('Error during segmentation generation');
|
||||
}
|
||||
|
||||
const { dataset: naturalizedReport } = generatedData;
|
||||
|
||||
// DCMJS assigns a dummy study id during creation, and this can cause problems, so clearing it out
|
||||
if (naturalizedReport.StudyID === 'No Study ID') {
|
||||
naturalizedReport.StudyID = '';
|
||||
}
|
||||
|
||||
await storeFn(naturalizedReport, {});
|
||||
|
||||
return naturalizedReport;
|
||||
} catch (error) {
|
||||
console.debug('Error storing segmentation:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -307,14 +316,11 @@ const commandsModule = ({
|
||||
downloadRTSS: async args => {
|
||||
const { dataset } = await actions.generateContour(args);
|
||||
const { InstanceNumber: instanceNumber = 1, SeriesInstanceUID: seriesUID } = dataset;
|
||||
|
||||
try {
|
||||
//Create a URL for the binary.
|
||||
const filename = `rtss-${seriesUID}-${instanceNumber}.dcm`;
|
||||
downloadDICOMData(dataset, filename);
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
const storeFn = commandsManager.runCommand('createStoreFunction', {
|
||||
dataSource: 'download',
|
||||
defaultFileName: `rtss-${seriesUID}-${instanceNumber}.dcm`,
|
||||
});
|
||||
await storeFn(dataset);
|
||||
},
|
||||
|
||||
toggleActiveSegmentationUtility: ({ itemId: buttonId }) => {
|
||||
|
||||
@@ -30,6 +30,7 @@ function _getDisplaySetsFromSeries(
|
||||
SeriesDate,
|
||||
StructureSetDate,
|
||||
SOPClassUID,
|
||||
FrameOfReferenceUID,
|
||||
wadoRoot,
|
||||
wadoUri,
|
||||
wadoUriRoot,
|
||||
@@ -49,6 +50,7 @@ function _getDisplaySetsFromSeries(
|
||||
StudyInstanceUID,
|
||||
SOPClassHandlerId,
|
||||
SOPClassUID,
|
||||
FrameOfReferenceUID,
|
||||
referencedImages: null,
|
||||
referencedSeriesInstanceUID: null,
|
||||
referencedDisplaySetInstanceUID: null,
|
||||
@@ -104,6 +106,7 @@ function _getDisplaySetsFromSeries(
|
||||
if (addedDisplaySet.SeriesInstanceUID === displaySet.referencedSeriesInstanceUID) {
|
||||
displaySet.referencedDisplaySetInstanceUID = addedDisplaySet.displaySetInstanceUID;
|
||||
displaySet.isReconstructable = addedDisplaySet.isReconstructable;
|
||||
displaySet.FrameOfReferenceUID = addedDisplaySet.FrameOfReferenceUID;
|
||||
unsubscribe();
|
||||
}
|
||||
}
|
||||
@@ -111,6 +114,7 @@ function _getDisplaySetsFromSeries(
|
||||
} else {
|
||||
displaySet.referencedDisplaySetInstanceUID = referencedDisplaySet.displaySetInstanceUID;
|
||||
displaySet.isReconstructable = referencedDisplaySet.isReconstructable;
|
||||
displaySet.FrameOfReferenceUID = referencedDisplaySet.FrameOfReferenceUID;
|
||||
}
|
||||
|
||||
displaySet.load = async ({ headers }) =>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const webpack = require('webpack');
|
||||
const webpack = require('@rspack/core');
|
||||
const { merge } = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.base.js');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const MiniCssExtractPlugin = webpack.CssExtractRspackPlugin;
|
||||
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
@@ -36,9 +36,11 @@ module.exports = (env, argv) => {
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
library: {
|
||||
name: 'ohif-extension-cornerstone-dicom-sr',
|
||||
type: 'umd',
|
||||
},
|
||||
path: ROOT_DIR,
|
||||
library: 'ohif-extension-cornerstone-dicom-sr',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
},
|
||||
externals: [/\b(vtk.js)/, /\b(dcmjs)/, /\b(gl-matrix)/, /^@ohif/, /^@cornerstonejs/],
|
||||
|
||||
@@ -3,6 +3,631 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.13.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.88...v3.13.0-beta.89) (2026-06-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ohif tests to run with cornerstone 3d 5.0 ([#6043](https://github.com/OHIF/Viewers/issues/6043)) ([6dd150d](https://github.com/OHIF/Viewers/commit/6dd150d401ad73d60632a23378b7dfd4b5142690))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.87...v3.13.0-beta.88) (2026-06-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.86...v3.13.0-beta.87) (2026-05-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.85...v3.13.0-beta.86) (2026-05-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.84...v3.13.0-beta.85) (2026-05-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.83...v3.13.0-beta.84) (2026-05-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.82...v3.13.0-beta.83) (2026-05-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.81...v3.13.0-beta.82) (2026-05-22)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.80...v3.13.0-beta.81) (2026-05-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.79...v3.13.0-beta.80) (2026-05-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.78...v3.13.0-beta.79) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.77...v3.13.0-beta.78) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.76...v3.13.0-beta.77) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.75...v3.13.0-beta.76) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.74...v3.13.0-beta.75) (2026-05-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.73...v3.13.0-beta.74) (2026-05-15)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.72...v3.13.0-beta.73) (2026-05-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.71...v3.13.0-beta.72) (2026-05-12)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.70...v3.13.0-beta.71) (2026-05-07)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.69...v3.13.0-beta.70) (2026-05-07)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.68...v3.13.0-beta.69) (2026-05-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.67...v3.13.0-beta.68) (2026-05-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.66...v3.13.0-beta.67) (2026-04-30)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.65...v3.13.0-beta.66) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.64...v3.13.0-beta.65) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.63...v3.13.0-beta.64) (2026-04-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.62...v3.13.0-beta.63) (2026-04-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.61...v3.13.0-beta.62) (2026-04-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.60...v3.13.0-beta.61) (2026-04-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.59...v3.13.0-beta.60) (2026-04-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.58...v3.13.0-beta.59) (2026-04-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Use newer ONNX version and load without errors ([#5854](https://github.com/OHIF/Viewers/issues/5854)) ([cc5dc20](https://github.com/OHIF/Viewers/commit/cc5dc201649bcbfb4cfad21141dbd56000d30f53)), closes [#5875](https://github.com/OHIF/Viewers/issues/5875) [#5884](https://github.com/OHIF/Viewers/issues/5884) [#5886](https://github.com/OHIF/Viewers/issues/5886) [#5893](https://github.com/OHIF/Viewers/issues/5893) [#5874](https://github.com/OHIF/Viewers/issues/5874) [#5865](https://github.com/OHIF/Viewers/issues/5865)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.57...v3.13.0-beta.58) (2026-04-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.56...v3.13.0-beta.57) (2026-04-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.55...v3.13.0-beta.56) (2026-04-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* A couple of changes to enable cs3d integration build ([#5944](https://github.com/OHIF/Viewers/issues/5944)) ([f6bbd5c](https://github.com/OHIF/Viewers/commit/f6bbd5c779e4692dc47c93327a890661b8dcc174))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.54...v3.13.0-beta.55) (2026-04-10)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.53...v3.13.0-beta.54) (2026-04-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.52...v3.13.0-beta.53) (2026-04-06)
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* rename DisplaySet.frameOfReferenceUID back to FrameOfReferenceUID ([#5943](https://github.com/OHIF/Viewers/issues/5943)) ([0e933c2](https://github.com/OHIF/Viewers/commit/0e933c256e07b7cda35ed2ba3cfb1ab35d895d57))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.51...v3.13.0-beta.52) (2026-04-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.50...v3.13.0-beta.51) (2026-04-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.49...v3.13.0-beta.50) (2026-04-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.48...v3.13.0-beta.49) (2026-04-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** restrict overlay segmentation menu to same frame of reference as viewport background display set ([#5900](https://github.com/OHIF/Viewers/issues/5900)) ([b9029ef](https://github.com/OHIF/Viewers/commit/b9029ef6f8d63a0e36ec929310c1c5ad3f563ef8))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.47...v3.13.0-beta.48) (2026-04-01)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.46...v3.13.0-beta.47) (2026-03-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.45...v3.13.0-beta.46) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.44...v3.13.0-beta.45) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.43...v3.13.0-beta.44) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.42...v3.13.0-beta.43) (2026-03-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **SR:** Added support for spline and live wire SR items. ([#5870](https://github.com/OHIF/Viewers/issues/5870)) ([1d4802c](https://github.com/OHIF/Viewers/commit/1d4802c2a38dd75dca7afca87913e100453c9135))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.41...v3.13.0-beta.42) (2026-03-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add combined build ([#5895](https://github.com/OHIF/Viewers/issues/5895)) ([1df671e](https://github.com/OHIF/Viewers/commit/1df671e9ab67d43f98bf09f6838ddc0a5f220277))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.40...v3.13.0-beta.41) (2026-03-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **sr-hydration:** enable hydration and arrow navigation for 3D SR measurements ([#5887](https://github.com/OHIF/Viewers/issues/5887)) ([7a38903](https://github.com/OHIF/Viewers/commit/7a38903b1977b1cf0f3a0ba8a4a823fac5e8fdeb))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.39...v3.13.0-beta.40) (2026-03-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.38...v3.13.0-beta.39) (2026-03-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.37...v3.13.0-beta.38) (2026-03-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** Display "No description S:{series number} {modality}" for segmentations with no label. ([#5874](https://github.com/OHIF/Viewers/issues/5874)) ([7b5d0ce](https://github.com/OHIF/Viewers/commit/7b5d0ce40e5422ccfce6091ac3d7559586cbe57e))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.36...v3.13.0-beta.37) (2026-03-12)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.35...v3.13.0-beta.36) (2026-03-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.34...v3.13.0-beta.35) (2026-03-09)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.33...v3.13.0-beta.34) (2026-03-09)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.32...v3.13.0-beta.33) (2026-03-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.31...v3.13.0-beta.32) (2026-03-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.30...v3.13.0-beta.31) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.29...v3.13.0-beta.30) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.28...v3.13.0-beta.29) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.27...v3.13.0-beta.28) (2026-03-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.26...v3.13.0-beta.27) (2026-03-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.25...v3.13.0-beta.26) (2026-02-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.24...v3.13.0-beta.25) (2026-02-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Update CS3D 4.18.2 ([#5837](https://github.com/OHIF/Viewers/issues/5837)) ([5370b93](https://github.com/OHIF/Viewers/commit/5370b9382e7bfddeadd69bab9e653f5f997a6e19))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.23...v3.13.0-beta.24) (2026-02-24)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.22...v3.13.0-beta.23) (2026-02-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* palette color 8 encoded 16 ([#5823](https://github.com/OHIF/Viewers/issues/5823)) ([eeca1f7](https://github.com/OHIF/Viewers/commit/eeca1f7a7b529d1700f5d281a6fd98074547ffe9)), closes [#5813](https://github.com/OHIF/Viewers/issues/5813)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.21...v3.13.0-beta.22) (2026-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.20...v3.13.0-beta.21) (2026-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.19...v3.13.0-beta.20) (2026-02-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.18...v3.13.0-beta.19) (2026-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.17...v3.13.0-beta.18) (2026-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.16...v3.13.0-beta.17) (2026-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.15...v3.13.0-beta.16) (2026-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.14...v3.13.0-beta.15) (2026-02-17)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dicom-sr
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone-dicom-sr",
|
||||
"version": "3.13.0-beta.15",
|
||||
"version": "3.13.0-beta.97",
|
||||
"description": "OHIF extension for an SR Cornerstone Viewport",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -8,9 +8,7 @@
|
||||
"main": "dist/ohif-extension-cornerstone-dicom-sr.umd.js",
|
||||
"module": "src/index.tsx",
|
||||
"engines": {
|
||||
"node": ">=14",
|
||||
"npm": ">=6",
|
||||
"yarn": ">=1.16.0"
|
||||
"node": ">=24"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
@@ -19,25 +17,21 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"keywords": [
|
||||
"ohif-extension"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:cornerstone": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
"build:package-1": "yarn run build",
|
||||
"start": "yarn run dev",
|
||||
"clean:deep": "pnpm run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development rspack build --config .webpack/webpack.dev.js --watch",
|
||||
"dev:cornerstone": "pnpm run dev",
|
||||
"build": "cross-env NODE_ENV=production rspack build --config .webpack/webpack.prod.js",
|
||||
"build:package-1": "pnpm run build",
|
||||
"start": "pnpm run dev",
|
||||
"test:unit": "jest --watchAll",
|
||||
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.13.0-beta.15",
|
||||
"@ohif/extension-cornerstone": "3.13.0-beta.15",
|
||||
"@ohif/extension-measurement-tracking": "3.13.0-beta.15",
|
||||
"@ohif/ui": "3.13.0-beta.15",
|
||||
"@ohif/core": "workspace:*",
|
||||
"@ohif/extension-cornerstone": "workspace:*",
|
||||
"@ohif/ui": "workspace:*",
|
||||
"dcmjs": "0.49.4",
|
||||
"dicom-parser": "1.8.21",
|
||||
"hammerjs": "2.0.8",
|
||||
@@ -45,10 +39,16 @@
|
||||
"react": "18.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.2",
|
||||
"@cornerstonejs/adapters": "4.15.29",
|
||||
"@cornerstonejs/core": "4.15.29",
|
||||
"@cornerstonejs/tools": "4.15.29",
|
||||
"@babel/runtime": "7.29.7",
|
||||
"@cornerstonejs/adapters": "5.0.2",
|
||||
"@cornerstonejs/core": "5.0.2",
|
||||
"@cornerstonejs/tools": "5.0.2",
|
||||
"classnames": "2.5.1"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "7.0.3"
|
||||
},
|
||||
"keywords": [
|
||||
"ohif-extension"
|
||||
]
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
import { metaData } from '@cornerstonejs/core';
|
||||
|
||||
import OHIF, { DicomMetadataStore, utils } from '@ohif/core';
|
||||
import dcmjs from 'dcmjs';
|
||||
import OHIF from '@ohif/core';
|
||||
import { adaptersSR } from '@cornerstonejs/adapters';
|
||||
|
||||
import getFilteredCornerstoneToolState from './utils/getFilteredCornerstoneToolState';
|
||||
import hydrateStructuredReport from './utils/hydrateStructuredReport';
|
||||
|
||||
const { downloadBlob } = utils;
|
||||
|
||||
const { MeasurementReport } = adaptersSR.Cornerstone3D;
|
||||
const { log } = OHIF;
|
||||
|
||||
@@ -75,24 +72,8 @@ const commandsModule = (props: withAppTypes) => {
|
||||
/**
|
||||
*
|
||||
* @param measurementData An array of measurements from the measurements service
|
||||
* @param additionalFindingTypes toolTypes that should be stored with labels as Findings
|
||||
* @param options Naturalized DICOM JSON headers to merge into the displaySet.
|
||||
* as opposed to Finding Sites.
|
||||
* that you wish to serialize.
|
||||
*/
|
||||
downloadReport: ({ measurementData, additionalFindingTypes, options = {} }) => {
|
||||
const srDataset = _generateReport(measurementData, additionalFindingTypes, options);
|
||||
const reportBlob = dcmjs.data.datasetToBlob(srDataset);
|
||||
|
||||
//Create a URL for the binary.
|
||||
downloadBlob(reportBlob, { filename: 'dicom-sr.dcm' });
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param measurementData An array of measurements from the measurements service
|
||||
* that you wish to serialize.
|
||||
* @param dataSource The dataSource that you wish to use to persist the data.
|
||||
* @param dataSource The data source name ('download', 'copyToClipboard', or a named data source).
|
||||
* @param additionalFindingTypes toolTypes that should be stored with labels as Findings
|
||||
* @param options Naturalized DICOM JSON headers to merge into the displaySet.
|
||||
* @return The naturalized report
|
||||
@@ -103,23 +84,30 @@ const commandsModule = (props: withAppTypes) => {
|
||||
additionalFindingTypes,
|
||||
options = {},
|
||||
}) => {
|
||||
// Use the @cornerstonejs adapter for converting to/from DICOM
|
||||
// But it is good enough for now whilst we only have cornerstone as a datasource.
|
||||
log.info('[DICOMSR] storeMeasurements');
|
||||
|
||||
if (!dataSource || !dataSource.store || !dataSource.store.dicom) {
|
||||
log.error('[DICOMSR] datasource has no dataSource.store.dicom endpoint!');
|
||||
const storeFn = commandsManager.runCommand('createStoreFunction', {
|
||||
dataSource,
|
||||
defaultFileName: 'dicom-sr.dcm',
|
||||
});
|
||||
|
||||
if (!storeFn) {
|
||||
log.error('[DICOMSR] No valid store for dataSource:', dataSource);
|
||||
return Promise.reject({});
|
||||
}
|
||||
|
||||
try {
|
||||
const naturalizedReport = _generateReport(measurementData, additionalFindingTypes, options);
|
||||
const naturalizedReport = _generateReport(
|
||||
measurementData,
|
||||
additionalFindingTypes,
|
||||
options
|
||||
);
|
||||
|
||||
const { StudyInstanceUID, ContentSequence } = naturalizedReport;
|
||||
const { ContentSequence } = naturalizedReport;
|
||||
// The content sequence has 5 or more elements, of which
|
||||
// the `[4]` element contains the annotation data, so this is
|
||||
// checking that there is some annotation data present.
|
||||
if (!ContentSequence?.[4].ContentSequence?.length) {
|
||||
if (!ContentSequence?.[4]?.ContentSequence?.length) {
|
||||
console.log('naturalizedReport missing imaging content', naturalizedReport);
|
||||
throw new Error('Invalid report, no content');
|
||||
}
|
||||
@@ -128,22 +116,12 @@ const commandsModule = (props: withAppTypes) => {
|
||||
}
|
||||
|
||||
const onBeforeDicomStore = customizationService.getCustomization('onBeforeDicomStore');
|
||||
|
||||
let dicomDict;
|
||||
if (typeof onBeforeDicomStore === 'function') {
|
||||
dicomDict = onBeforeDicomStore({ dicomDict, measurementData, naturalizedReport });
|
||||
}
|
||||
|
||||
await dataSource.store.dicom(naturalizedReport, null, dicomDict);
|
||||
|
||||
if (StudyInstanceUID) {
|
||||
dataSource.deleteStudyMetadataPromise(StudyInstanceUID);
|
||||
}
|
||||
|
||||
// The "Mode" route listens for DicomMetadataStore changes
|
||||
// When a new instance is added, it listens and
|
||||
// automatically calls makeDisplaySets
|
||||
DicomMetadataStore.addInstances([naturalizedReport], true);
|
||||
await storeFn(naturalizedReport, { measurementData, dicomDict });
|
||||
|
||||
return naturalizedReport;
|
||||
} catch (error) {
|
||||
@@ -166,7 +144,6 @@ const commandsModule = (props: withAppTypes) => {
|
||||
};
|
||||
|
||||
const definitions = {
|
||||
downloadReport: actions.downloadReport,
|
||||
storeMeasurements: actions.storeMeasurements,
|
||||
hydrateStructuredReport: actions.hydrateStructuredReport,
|
||||
};
|
||||
|
||||
@@ -200,8 +200,13 @@ async function _load(
|
||||
srDisplaySet.isRehydratable = isRehydratable(srDisplaySet, mappings);
|
||||
srDisplaySet.isLoaded = true;
|
||||
|
||||
/** Check currently added displaySets and add measurements if the sources exist */
|
||||
displaySetService.activeDisplaySets.forEach(activeDisplaySet => {
|
||||
/** Check currently added displaySets and add measurements if the sources exist.
|
||||
* Walk the SR's study first in default series order (not load order) so SCOORD3D
|
||||
* FrameOfReference matching picks a stable series when several share FOR. */
|
||||
const displaySetsForSRPass = utils.sortDisplaySetsCopy(displaySetService.activeDisplaySets, {
|
||||
studyInstanceUIDFirst: srDisplaySet.StudyInstanceUID,
|
||||
});
|
||||
displaySetsForSRPass.forEach(activeDisplaySet => {
|
||||
_checkIfCanAddMeasurementsToDisplaySet(
|
||||
srDisplaySet,
|
||||
activeDisplaySet,
|
||||
@@ -637,16 +642,35 @@ function _processNonGeometricallyDefinedMeasurement(mergedContentSequence) {
|
||||
NUMContentItems.forEach(item => {
|
||||
const { ConceptNameCodeSequence, ContentSequence, MeasuredValueSequence } = item;
|
||||
|
||||
// Handle spatial reference ONLY if ContentSequence exists
|
||||
// Handle spatial reference ONLY if ContentSequence exists.
|
||||
// ContentSequence may be a scalar SCOORD or an array when additional named
|
||||
// SCOORDs (e.g. control points) are nested alongside the primary geometry.
|
||||
// Pick the primary geometry entry: prefer the SCOORD without a
|
||||
// ConceptNameCodeSequence (plain polyline), falling back to the first SCOORD.
|
||||
if (ContentSequence) {
|
||||
const { ValueType } = ContentSequence;
|
||||
const scoordItem = Array.isArray(ContentSequence)
|
||||
? (ContentSequence.find(
|
||||
cs =>
|
||||
(cs.ValueType === 'SCOORD' || cs.ValueType === 'SCOORD3D') &&
|
||||
!cs.ConceptNameCodeSequence
|
||||
) ?? ContentSequence.find(cs => cs.ValueType === 'SCOORD' || cs.ValueType === 'SCOORD3D'))
|
||||
: ContentSequence;
|
||||
|
||||
if (!scoordItem) {
|
||||
console.warn(
|
||||
'ContentSequence array contains no SCOORD or SCOORD3D entry, skipping annotation.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const { ValueType } = scoordItem;
|
||||
|
||||
if (ValueType !== 'SCOORD' && ValueType !== 'SCOORD3D') {
|
||||
console.warn(`Graphic ${ValueType} not currently supported, skipping annotation.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const coords = _getCoordsFromSCOORDOrSCOORD3D(ContentSequence);
|
||||
const coords = _getCoordsFromSCOORDOrSCOORD3D(scoordItem);
|
||||
|
||||
if (coords) {
|
||||
measurement.coords.push(coords);
|
||||
|
||||
@@ -69,7 +69,12 @@ export default class DICOMSRDisplayTool extends AnnotationTool {
|
||||
trackingUniqueIdentifiers.includes(annotation.data?.TrackingUniqueIdentifier)
|
||||
);
|
||||
|
||||
if (!viewport._actors?.size) {
|
||||
const hasActors =
|
||||
typeof viewport.getActors === 'function'
|
||||
? viewport.getActors().length > 0
|
||||
: Boolean(viewport._actors?.size);
|
||||
|
||||
if (!hasActors) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ export default function hydrateStructuredReport(
|
||||
const { ReferencedSOPInstanceUID, imageId, frameNumber = 1 } = measurement;
|
||||
const key = `${ReferencedSOPInstanceUID}:${frameNumber}`;
|
||||
|
||||
if (!sopInstanceUIDToImageId[key]) {
|
||||
if (imageId && !sopInstanceUIDToImageId[key]) {
|
||||
sopInstanceUIDToImageId[key] = imageId;
|
||||
}
|
||||
});
|
||||
@@ -118,41 +118,17 @@ export default function hydrateStructuredReport(
|
||||
}
|
||||
});
|
||||
|
||||
// Set the series touched as tracked.
|
||||
const imageIds = [];
|
||||
|
||||
// TODO: notification if no hydratable?
|
||||
Object.keys(hydratableMeasurementsInSR).forEach(annotationType => {
|
||||
const toolDataForAnnotationType = hydratableMeasurementsInSR[annotationType];
|
||||
|
||||
toolDataForAnnotationType.forEach(toolData => {
|
||||
// Add the measurement to toolState
|
||||
// dcmjs and Cornerstone3D has structural defect in supporting multi-frame
|
||||
// files, and looking up the imageId from sopInstanceUIDToImageId results
|
||||
// in the wrong value.
|
||||
const frameNumber = toolData.annotation.data?.frameNumber || 1;
|
||||
const imageId = sopInstanceUIDToImageId[`${toolData.sopInstanceUid}:${frameNumber}`];
|
||||
|
||||
if (!imageIds.includes(imageId)) {
|
||||
imageIds.push(imageId);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let targetStudyInstanceUID;
|
||||
const SeriesInstanceUIDs = [];
|
||||
|
||||
for (let i = 0; i < imageIds.length; i++) {
|
||||
const imageId = imageIds[i];
|
||||
if (!imageId) {
|
||||
continue;
|
||||
}
|
||||
const { SeriesInstanceUID, StudyInstanceUID } = metaData.get('instance', imageId);
|
||||
// Set the series touched as tracked.
|
||||
const imageIds = getImageIds(hydratableMeasurementsInSR, sopInstanceUIDToImageId);
|
||||
|
||||
for (const imageId of imageIds) {
|
||||
const { SeriesInstanceUID, StudyInstanceUID } = metaData.get('instance', imageId);
|
||||
if (!SeriesInstanceUIDs.includes(SeriesInstanceUID)) {
|
||||
SeriesInstanceUIDs.push(SeriesInstanceUID);
|
||||
}
|
||||
|
||||
if (!targetStudyInstanceUID) {
|
||||
targetStudyInstanceUID = StudyInstanceUID;
|
||||
} else if (targetStudyInstanceUID !== StudyInstanceUID) {
|
||||
@@ -160,6 +136,31 @@ export default function hydrateStructuredReport(
|
||||
}
|
||||
}
|
||||
|
||||
// For 3d annotations there are no image IDs,
|
||||
// so we need to find the display sets by frame of reference to get the SeriesInstanceUIDs
|
||||
const frameOfReferenceUIDs = getFrameOfReferenceUIDs(
|
||||
hydratableMeasurementsInSR,
|
||||
sopInstanceUIDToImageId
|
||||
);
|
||||
|
||||
for (const FrameOfReferenceUID of frameOfReferenceUIDs) {
|
||||
const displaySetsFOR = displaySetService.getDisplaySetsBy(
|
||||
ds => ds.FrameOfReferenceUID === FrameOfReferenceUID && !ds.isDerivedDisplaySet
|
||||
);
|
||||
const ds = chooseDisplaySet(displaySetsFOR, FrameOfReferenceUID);
|
||||
if (!ds) {
|
||||
continue;
|
||||
}
|
||||
if (!SeriesInstanceUIDs.includes(ds.SeriesInstanceUID)) {
|
||||
SeriesInstanceUIDs.push(ds.SeriesInstanceUID);
|
||||
}
|
||||
if (!targetStudyInstanceUID) {
|
||||
targetStudyInstanceUID = ds.StudyInstanceUID;
|
||||
} else if (targetStudyInstanceUID !== ds.StudyInstanceUID) {
|
||||
console.warn('NO SUPPORT FOR SRs THAT HAVE MEASUREMENTS FROM MULTIPLE STUDIES.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets reference data for what frame of reference and the referenced
|
||||
* image id, or for 3d measurements, the volumeId to apply this annotation to.
|
||||
@@ -196,7 +197,7 @@ export default function hydrateStructuredReport(
|
||||
toolDataForAnnotationType.forEach(toolData => {
|
||||
toolData.uid = guid();
|
||||
const referenceData = getReferenceData(toolData);
|
||||
const { imageId } = referenceData;
|
||||
const { referencedImageId } = referenceData;
|
||||
|
||||
const annotation = {
|
||||
annotationUID: toolData.annotation.annotationUID,
|
||||
@@ -241,8 +242,8 @@ export default function hydrateStructuredReport(
|
||||
locking.setAnnotationLocked(newAnnotationUID, true);
|
||||
}
|
||||
|
||||
if (imageId && !imageIds.includes(imageId)) {
|
||||
imageIds.push(imageId);
|
||||
if (referencedImageId && !imageIds.includes(referencedImageId)) {
|
||||
imageIds.push(referencedImageId);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -255,15 +256,64 @@ export default function hydrateStructuredReport(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unique imageIds from hydratable measurements that have an imageId reference
|
||||
* (i.e., 2D/SCOORD annotations).
|
||||
*/
|
||||
function getImageIds(hydratableMeasurementsInSR, sopInstanceUIDToImageId): string[] {
|
||||
const imageIds: string[] = [];
|
||||
Object.keys(hydratableMeasurementsInSR).forEach(annotationType => {
|
||||
const toolDataForAnnotationType = hydratableMeasurementsInSR[annotationType];
|
||||
|
||||
toolDataForAnnotationType.forEach(toolData => {
|
||||
// Add the measurement to toolState
|
||||
// dcmjs and Cornerstone3D has structural defect in supporting multi-frame
|
||||
// files, and looking up the imageId from sopInstanceUIDToImageId results
|
||||
// in the wrong value.
|
||||
const frameNumber = toolData.annotation.data?.frameNumber || 1;
|
||||
const imageId = sopInstanceUIDToImageId[`${toolData.sopInstanceUid}:${frameNumber}`];
|
||||
|
||||
if (imageId && !imageIds.includes(imageId)) {
|
||||
imageIds.push(imageId);
|
||||
}
|
||||
});
|
||||
});
|
||||
return imageIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unique FrameOfReferenceUIDs from hydratable measurements that have no imageId reference
|
||||
* (i.e., 3D/SCOORD3D annotations). This excludes annotations handled by the getImageIds function.
|
||||
*/
|
||||
function getFrameOfReferenceUIDs(hydratableMeasurementsInSR, sopInstanceUIDToImageId): string[] {
|
||||
const frameOfReferenceUIDs: string[] = [];
|
||||
|
||||
Object.keys(hydratableMeasurementsInSR).forEach(annotationType => {
|
||||
const toolDataForAnnotationType = hydratableMeasurementsInSR[annotationType];
|
||||
toolDataForAnnotationType.forEach(toolData => {
|
||||
const frameNumber = toolData.annotation.data?.frameNumber || 1;
|
||||
const imageId = sopInstanceUIDToImageId[`${toolData.sopInstanceUid}:${frameNumber}`];
|
||||
|
||||
if (!imageId) {
|
||||
const { FrameOfReferenceUID } = toolData.annotation.metadata;
|
||||
if (FrameOfReferenceUID && !frameOfReferenceUIDs.includes(FrameOfReferenceUID)) {
|
||||
frameOfReferenceUIDs.push(FrameOfReferenceUID);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return frameOfReferenceUIDs;
|
||||
}
|
||||
|
||||
/**
|
||||
* For 3d annotations, there are often several display sets which could
|
||||
* be used to display the annotation. Choose the first annotation with the
|
||||
* same frame of reference that is reconstructable, or the first display set
|
||||
* otherwise.
|
||||
*/
|
||||
function chooseDisplaySet(displaySets, annotation) {
|
||||
function chooseDisplaySet(displaySets, reference) {
|
||||
if (!displaySets?.length) {
|
||||
console.warn('No display set found for', annotation);
|
||||
console.warn('No display set found for', reference);
|
||||
return;
|
||||
}
|
||||
if (displaySets.length === 1) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const webpack = require('webpack');
|
||||
const webpack = require('@rspack/core');
|
||||
const { merge } = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.base.js');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const MiniCssExtractPlugin = webpack.CssExtractRspackPlugin;
|
||||
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
@@ -35,9 +35,11 @@ module.exports = (env, argv) => {
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
library: {
|
||||
name: 'ohif-extension-cornerstone',
|
||||
type: 'umd',
|
||||
},
|
||||
path: ROOT_DIR,
|
||||
library: 'ohif-extension-cornerstone',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
},
|
||||
externals: [/\b(vtk.js)/, /\b(dcmjs)/, /\b(gl-matrix)/, /^@ohif/, /^@cornerstonejs/],
|
||||
|
||||
@@ -3,6 +3,619 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.13.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.88...v3.13.0-beta.89) (2026-06-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ohif tests to run with cornerstone 3d 5.0 ([#6043](https://github.com/OHIF/Viewers/issues/6043)) ([6dd150d](https://github.com/OHIF/Viewers/commit/6dd150d401ad73d60632a23378b7dfd4b5142690))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.87...v3.13.0-beta.88) (2026-06-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.86...v3.13.0-beta.87) (2026-05-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.85...v3.13.0-beta.86) (2026-05-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.84...v3.13.0-beta.85) (2026-05-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.83...v3.13.0-beta.84) (2026-05-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.82...v3.13.0-beta.83) (2026-05-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.81...v3.13.0-beta.82) (2026-05-22)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.80...v3.13.0-beta.81) (2026-05-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.79...v3.13.0-beta.80) (2026-05-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.78...v3.13.0-beta.79) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.77...v3.13.0-beta.78) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.76...v3.13.0-beta.77) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.75...v3.13.0-beta.76) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.74...v3.13.0-beta.75) (2026-05-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.73...v3.13.0-beta.74) (2026-05-15)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.72...v3.13.0-beta.73) (2026-05-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.71...v3.13.0-beta.72) (2026-05-12)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.70...v3.13.0-beta.71) (2026-05-07)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.69...v3.13.0-beta.70) (2026-05-07)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.68...v3.13.0-beta.69) (2026-05-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.67...v3.13.0-beta.68) (2026-05-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.66...v3.13.0-beta.67) (2026-04-30)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.65...v3.13.0-beta.66) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.64...v3.13.0-beta.65) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.63...v3.13.0-beta.64) (2026-04-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.62...v3.13.0-beta.63) (2026-04-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.61...v3.13.0-beta.62) (2026-04-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.60...v3.13.0-beta.61) (2026-04-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.59...v3.13.0-beta.60) (2026-04-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.58...v3.13.0-beta.59) (2026-04-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Use newer ONNX version and load without errors ([#5854](https://github.com/OHIF/Viewers/issues/5854)) ([cc5dc20](https://github.com/OHIF/Viewers/commit/cc5dc201649bcbfb4cfad21141dbd56000d30f53)), closes [#5875](https://github.com/OHIF/Viewers/issues/5875) [#5884](https://github.com/OHIF/Viewers/issues/5884) [#5886](https://github.com/OHIF/Viewers/issues/5886) [#5893](https://github.com/OHIF/Viewers/issues/5893) [#5874](https://github.com/OHIF/Viewers/issues/5874) [#5865](https://github.com/OHIF/Viewers/issues/5865)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.57...v3.13.0-beta.58) (2026-04-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.56...v3.13.0-beta.57) (2026-04-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.55...v3.13.0-beta.56) (2026-04-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* A couple of changes to enable cs3d integration build ([#5944](https://github.com/OHIF/Viewers/issues/5944)) ([f6bbd5c](https://github.com/OHIF/Viewers/commit/f6bbd5c779e4692dc47c93327a890661b8dcc174))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.54...v3.13.0-beta.55) (2026-04-10)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.53...v3.13.0-beta.54) (2026-04-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.52...v3.13.0-beta.53) (2026-04-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.51...v3.13.0-beta.52) (2026-04-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.50...v3.13.0-beta.51) (2026-04-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.49...v3.13.0-beta.50) (2026-04-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.48...v3.13.0-beta.49) (2026-04-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.47...v3.13.0-beta.48) (2026-04-01)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.46...v3.13.0-beta.47) (2026-03-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.45...v3.13.0-beta.46) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.44...v3.13.0-beta.45) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.43...v3.13.0-beta.44) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.42...v3.13.0-beta.43) (2026-03-17)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.41...v3.13.0-beta.42) (2026-03-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add combined build ([#5895](https://github.com/OHIF/Viewers/issues/5895)) ([1df671e](https://github.com/OHIF/Viewers/commit/1df671e9ab67d43f98bf09f6838ddc0a5f220277))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.40...v3.13.0-beta.41) (2026-03-16)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.39...v3.13.0-beta.40) (2026-03-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.38...v3.13.0-beta.39) (2026-03-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.37...v3.13.0-beta.38) (2026-03-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** Display "No description S:{series number} {modality}" for segmentations with no label. ([#5874](https://github.com/OHIF/Viewers/issues/5874)) ([7b5d0ce](https://github.com/OHIF/Viewers/commit/7b5d0ce40e5422ccfce6091ac3d7559586cbe57e))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.36...v3.13.0-beta.37) (2026-03-12)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.35...v3.13.0-beta.36) (2026-03-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.34...v3.13.0-beta.35) (2026-03-09)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.33...v3.13.0-beta.34) (2026-03-09)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.32...v3.13.0-beta.33) (2026-03-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.31...v3.13.0-beta.32) (2026-03-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.30...v3.13.0-beta.31) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.29...v3.13.0-beta.30) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.28...v3.13.0-beta.29) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.27...v3.13.0-beta.28) (2026-03-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.26...v3.13.0-beta.27) (2026-03-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.25...v3.13.0-beta.26) (2026-02-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.24...v3.13.0-beta.25) (2026-02-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Update CS3D 4.18.2 ([#5837](https://github.com/OHIF/Viewers/issues/5837)) ([5370b93](https://github.com/OHIF/Viewers/commit/5370b9382e7bfddeadd69bab9e653f5f997a6e19))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.23...v3.13.0-beta.24) (2026-02-24)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.22...v3.13.0-beta.23) (2026-02-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* palette color 8 encoded 16 ([#5823](https://github.com/OHIF/Viewers/issues/5823)) ([eeca1f7](https://github.com/OHIF/Viewers/commit/eeca1f7a7b529d1700f5d281a6fd98074547ffe9)), closes [#5813](https://github.com/OHIF/Viewers/issues/5813)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.21...v3.13.0-beta.22) (2026-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.20...v3.13.0-beta.21) (2026-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.19...v3.13.0-beta.20) (2026-02-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.18...v3.13.0-beta.19) (2026-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.17...v3.13.0-beta.18) (2026-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.16...v3.13.0-beta.17) (2026-02-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.15...v3.13.0-beta.16) (2026-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.14...v3.13.0-beta.15) (2026-02-17)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone-dynamic-volume
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone-dynamic-volume",
|
||||
"version": "3.13.0-beta.15",
|
||||
"version": "3.13.0-beta.97",
|
||||
"description": "OHIF extension for 4D volumes data",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
"repository": "OHIF/Viewers",
|
||||
"main": "dist/ohif-extension-cornerstone-dynamic-volume.umd.js",
|
||||
"module": "src/index.ts",
|
||||
"engines": {
|
||||
"node": ">=24"
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./types": "./src/types/index.ts"
|
||||
@@ -19,21 +22,21 @@
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"build": "cross-env NODE_ENV=production webpack --config .webpack/webpack.prod.js",
|
||||
"build:package": "yarn run build",
|
||||
"dev": "cross-env NODE_ENV=development rspack build --config .webpack/webpack.dev.js --watch",
|
||||
"build": "cross-env NODE_ENV=production rspack build --config .webpack/webpack.prod.js",
|
||||
"build:package": "pnpm run build",
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"start": "yarn run dev",
|
||||
"clean:deep": "pnpm run clean && shx rm -rf node_modules",
|
||||
"start": "pnpm run dev",
|
||||
"test:unit": "jest --watchAll",
|
||||
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "3.13.0-beta.15",
|
||||
"@ohif/extension-cornerstone": "3.13.0-beta.15",
|
||||
"@ohif/extension-default": "3.13.0-beta.15",
|
||||
"@ohif/i18n": "3.13.0-beta.15",
|
||||
"@ohif/ui": "3.13.0-beta.15",
|
||||
"@ohif/core": "workspace:*",
|
||||
"@ohif/extension-cornerstone": "workspace:*",
|
||||
"@ohif/extension-default": "workspace:*",
|
||||
"@ohif/i18n": "workspace:*",
|
||||
"@ohif/ui": "workspace:*",
|
||||
"dcmjs": "0.49.4",
|
||||
"dicom-parser": "1.8.21",
|
||||
"hammerjs": "2.0.8",
|
||||
@@ -41,9 +44,12 @@
|
||||
"react": "18.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.2",
|
||||
"@cornerstonejs/core": "4.15.29",
|
||||
"@cornerstonejs/tools": "4.15.29",
|
||||
"@babel/runtime": "7.29.7",
|
||||
"@cornerstonejs/core": "5.0.2",
|
||||
"@cornerstonejs/tools": "5.0.2",
|
||||
"classnames": "2.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "7.0.3"
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
const webpack = require('webpack');
|
||||
const webpack = require('@rspack/core');
|
||||
const { merge } = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.base.js');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const MiniCssExtractPlugin = webpack.CssExtractRspackPlugin;
|
||||
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
@@ -35,9 +35,11 @@ module.exports = (env, argv) => {
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
library: {
|
||||
name: 'ohif-extension-cornerstone',
|
||||
type: 'umd',
|
||||
},
|
||||
path: ROOT_DIR,
|
||||
library: 'ohif-extension-cornerstone',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
},
|
||||
externals: [/\b(vtk.js)/, /\b(dcmjs)/, /\b(gl-matrix)/, /^@ohif/, /^@cornerstonejs/],
|
||||
|
||||
@@ -3,6 +3,676 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.13.0-beta.89](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.88...v3.13.0-beta.89) (2026-06-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ohif tests to run with cornerstone 3d 5.0 ([#6043](https://github.com/OHIF/Viewers/issues/6043)) ([6dd150d](https://github.com/OHIF/Viewers/commit/6dd150d401ad73d60632a23378b7dfd4b5142690))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.88](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.87...v3.13.0-beta.88) (2026-06-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.87](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.86...v3.13.0-beta.87) (2026-05-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.86](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.85...v3.13.0-beta.86) (2026-05-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.85](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.84...v3.13.0-beta.85) (2026-05-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.84](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.83...v3.13.0-beta.84) (2026-05-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.83](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.82...v3.13.0-beta.83) (2026-05-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** restore navigation for duplicated contour segments ([#6038](https://github.com/OHIF/Viewers/issues/6038)) ([0c1ca6b](https://github.com/OHIF/Viewers/commit/0c1ca6b04a6c1aef478c7a7d9f360f9b9c50f188))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.82](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.81...v3.13.0-beta.82) (2026-05-22)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.81](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.80...v3.13.0-beta.81) (2026-05-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.80](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.79...v3.13.0-beta.80) (2026-05-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.79](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.78...v3.13.0-beta.79) (2026-05-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **seg:** prevent viewport orientation change when loading SEG in manual grid layout ([#6021](https://github.com/OHIF/Viewers/issues/6021)) ([95251ab](https://github.com/OHIF/Viewers/commit/95251ab6709934e4ef59931379f8d9d7629f87b2))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.78](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.77...v3.13.0-beta.78) (2026-05-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **measurements:** read displayName in SplineROI and PlanarFreehandROI reports ([#5908](https://github.com/OHIF/Viewers/issues/5908)) ([27af682](https://github.com/OHIF/Viewers/commit/27af6821b56f2c5be3a5d4ce38d05be6fbce68f4))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.77](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.76...v3.13.0-beta.77) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.76](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.75...v3.13.0-beta.76) (2026-05-19)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.75](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.74...v3.13.0-beta.75) (2026-05-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.74](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.73...v3.13.0-beta.74) (2026-05-15)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.73](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.72...v3.13.0-beta.73) (2026-05-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.72](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.71...v3.13.0-beta.72) (2026-05-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **measurement-tracking:** restore tracked state on undo after Delete all ([#5994](https://github.com/OHIF/Viewers/issues/5994)) ([397aa4d](https://github.com/OHIF/Viewers/commit/397aa4d0e361e95dcbd83e0557a9cd84c0b8440a))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.71](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.70...v3.13.0-beta.71) (2026-05-07)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.70](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.69...v3.13.0-beta.70) (2026-05-07)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.69](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.68...v3.13.0-beta.69) (2026-05-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.68](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.67...v3.13.0-beta.68) (2026-05-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **ToolGroupService:** Centralize tool binding persistence and provide API to add and remove persisted bindings. ([#5989](https://github.com/OHIF/Viewers/issues/5989)) ([979d619](https://github.com/OHIF/Viewers/commit/979d619f7ccb426beb75d59721b01c98175d5241))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.67](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.66...v3.13.0-beta.67) (2026-04-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **ui-next:** Adds toggle state for ToolButton and Crosshair example ([#5914](https://github.com/OHIF/Viewers/issues/5914)) ([691e267](https://github.com/OHIF/Viewers/commit/691e26731f4f3b3957fe81fc051b09c972696cf6))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.66](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.65...v3.13.0-beta.66) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.65](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.64...v3.13.0-beta.65) (2026-04-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.64](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.63...v3.13.0-beta.64) (2026-04-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **seg:** prevent segmentations from spreading to all viewports before hydration confirmation in 3D four-up ([#5967](https://github.com/OHIF/Viewers/issues/5967)) ([f8ccf9f](https://github.com/OHIF/Viewers/commit/f8ccf9ff2ea9ab7c38bd427514a8ae87902822a3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.63](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.62...v3.13.0-beta.63) (2026-04-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.62](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.61...v3.13.0-beta.62) (2026-04-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.61](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.60...v3.13.0-beta.61) (2026-04-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **slice scrollbar:** Integrate ViewportSliceProgressScrollbar with customizations and docs ([#5960](https://github.com/OHIF/Viewers/issues/5960)) ([8fc0dc1](https://github.com/OHIF/Viewers/commit/8fc0dc16e97f3262fdac902ecf2d7c20cb8f78cc))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.60](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.59...v3.13.0-beta.60) (2026-04-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.59](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.58...v3.13.0-beta.59) (2026-04-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Use newer ONNX version and load without errors ([#5854](https://github.com/OHIF/Viewers/issues/5854)) ([cc5dc20](https://github.com/OHIF/Viewers/commit/cc5dc201649bcbfb4cfad21141dbd56000d30f53)), closes [#5875](https://github.com/OHIF/Viewers/issues/5875) [#5884](https://github.com/OHIF/Viewers/issues/5884) [#5886](https://github.com/OHIF/Viewers/issues/5886) [#5893](https://github.com/OHIF/Viewers/issues/5893) [#5874](https://github.com/OHIF/Viewers/issues/5874) [#5865](https://github.com/OHIF/Viewers/issues/5865)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.58](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.57...v3.13.0-beta.58) (2026-04-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.57](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.56...v3.13.0-beta.57) (2026-04-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.56](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.55...v3.13.0-beta.56) (2026-04-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* A couple of changes to enable cs3d integration build ([#5944](https://github.com/OHIF/Viewers/issues/5944)) ([f6bbd5c](https://github.com/OHIF/Viewers/commit/f6bbd5c779e4692dc47c93327a890661b8dcc174))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.55](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.54...v3.13.0-beta.55) (2026-04-10)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.54](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.53...v3.13.0-beta.54) (2026-04-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cornerstone:** read FrameOfReferenceUID from display set in viewport service ([#5950](https://github.com/OHIF/Viewers/issues/5950)) ([d219171](https://github.com/OHIF/Viewers/commit/d219171e25caf5a7c575080f63819d6f4fe45016))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.53](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.52...v3.13.0-beta.53) (2026-04-06)
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* rename DisplaySet.frameOfReferenceUID back to FrameOfReferenceUID ([#5943](https://github.com/OHIF/Viewers/issues/5943)) ([0e933c2](https://github.com/OHIF/Viewers/commit/0e933c256e07b7cda35ed2ba3cfb1ab35d895d57))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.52](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.51...v3.13.0-beta.52) (2026-04-06)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.51](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.50...v3.13.0-beta.51) (2026-04-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.50](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.49...v3.13.0-beta.50) (2026-04-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.49](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.48...v3.13.0-beta.49) (2026-04-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** restrict overlay segmentation menu to same frame of reference as viewport background display set ([#5900](https://github.com/OHIF/Viewers/issues/5900)) ([b9029ef](https://github.com/OHIF/Viewers/commit/b9029ef6f8d63a0e36ec929310c1c5ad3f563ef8))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.48](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.47...v3.13.0-beta.48) (2026-04-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **measurement:** Restore viewport interactivity when deleting in-progress Spline or Livewire measurement ([#5905](https://github.com/OHIF/Viewers/issues/5905)) ([7929f08](https://github.com/OHIF/Viewers/commit/7929f0898f1bf882682a912b1c32d93d0944726f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.47](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.46...v3.13.0-beta.47) (2026-03-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.46](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.45...v3.13.0-beta.46) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.45](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.44...v3.13.0-beta.45) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.44](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.43...v3.13.0-beta.44) (2026-03-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.43](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.42...v3.13.0-beta.43) (2026-03-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **SR:** Added support for spline and live wire SR items. ([#5870](https://github.com/OHIF/Viewers/issues/5870)) ([1d4802c](https://github.com/OHIF/Viewers/commit/1d4802c2a38dd75dca7afca87913e100453c9135))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.42](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.41...v3.13.0-beta.42) (2026-03-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add combined build ([#5895](https://github.com/OHIF/Viewers/issues/5895)) ([1df671e](https://github.com/OHIF/Viewers/commit/1df671e9ab67d43f98bf09f6838ddc0a5f220277))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.41](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.40...v3.13.0-beta.41) (2026-03-16)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.40](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.39...v3.13.0-beta.40) (2026-03-13)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.39](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.38...v3.13.0-beta.39) (2026-03-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **window level:** The window level value is not displayed by default on all the viewports when selecting common/custom layout and TMTV. ([#5865](https://github.com/OHIF/Viewers/issues/5865)) ([fe1ecfe](https://github.com/OHIF/Viewers/commit/fe1ecfe0cc5d1bcf82686d821f356da8936a8c4b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.38](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.37...v3.13.0-beta.38) (2026-03-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** Display "No description S:{series number} {modality}" for segmentations with no label. ([#5874](https://github.com/OHIF/Viewers/issues/5874)) ([7b5d0ce](https://github.com/OHIF/Viewers/commit/7b5d0ce40e5422ccfce6091ac3d7559586cbe57e))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.37](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.36...v3.13.0-beta.37) (2026-03-12)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.36](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.35...v3.13.0-beta.36) (2026-03-11)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.35](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.34...v3.13.0-beta.35) (2026-03-09)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.34](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.33...v3.13.0-beta.34) (2026-03-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **seg hydration:** auto-hydrate RT struct on second load with disableConfirmationPrompts ([#5875](https://github.com/OHIF/Viewers/issues/5875)) ([6f773f9](https://github.com/OHIF/Viewers/commit/6f773f997214c388409f3af3e9fc0e5b84debc10))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.33](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.32...v3.13.0-beta.33) (2026-03-05)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.32](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.31...v3.13.0-beta.32) (2026-03-05)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **ecg:** add DICOM ECG waveform extension ([#5856](https://github.com/OHIF/Viewers/issues/5856)) ([70f76ae](https://github.com/OHIF/Viewers/commit/70f76aeba1b27f8e4de5ec73a7b831428e38e3d2))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.31](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.30...v3.13.0-beta.31) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.30](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.29...v3.13.0-beta.30) (2026-03-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation:** segment bidirectional tool error and show toast notification when no segment is drawn ([#5861](https://github.com/OHIF/Viewers/issues/5861)) ([7e10830](https://github.com/OHIF/Viewers/commit/7e10830d5802e22bda4df6a3f8008e9a414b4cd4))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.29](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.28...v3.13.0-beta.29) (2026-03-04)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.28](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.27...v3.13.0-beta.28) (2026-03-03)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.27](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.26...v3.13.0-beta.27) (2026-03-02)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.26](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.25...v3.13.0-beta.26) (2026-02-28)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.25](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.24...v3.13.0-beta.25) (2026-02-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Update CS3D 4.18.2 ([#5837](https://github.com/OHIF/Viewers/issues/5837)) ([5370b93](https://github.com/OHIF/Viewers/commit/5370b9382e7bfddeadd69bab9e653f5f997a6e19))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.24](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.23...v3.13.0-beta.24) (2026-02-24)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.23](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.22...v3.13.0-beta.23) (2026-02-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* palette color 8 encoded 16 ([#5823](https://github.com/OHIF/Viewers/issues/5823)) ([eeca1f7](https://github.com/OHIF/Viewers/commit/eeca1f7a7b529d1700f5d281a6fd98074547ffe9)), closes [#5813](https://github.com/OHIF/Viewers/issues/5813)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.22](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.21...v3.13.0-beta.22) (2026-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.21](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.20...v3.13.0-beta.21) (2026-02-23)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.20](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.19...v3.13.0-beta.20) (2026-02-21)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.19](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.18...v3.13.0-beta.19) (2026-02-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.18](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.17...v3.13.0-beta.18) (2026-02-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segmentation overlay:** update viewport ds list upon seg delete - OHIF-2425 ([#5729](https://github.com/OHIF/Viewers/issues/5729)) ([b353541](https://github.com/OHIF/Viewers/commit/b35354120a01d89b27844f967c32c052bba8b096))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.17](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.16...v3.13.0-beta.17) (2026-02-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add copy to clipboard option for capture ([#5720](https://github.com/OHIF/Viewers/issues/5720)) ([53c67f3](https://github.com/OHIF/Viewers/commit/53c67f361234a0b4160c1b11fafcb143a0723336))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.16](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.15...v3.13.0-beta.16) (2026-02-18)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [3.13.0-beta.15](https://github.com/OHIF/Viewers/compare/v3.13.0-beta.14...v3.13.0-beta.15) (2026-02-17)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
@@ -5,8 +5,6 @@ module.exports = {
|
||||
moduleNameMapper: {
|
||||
...base.moduleNameMapper,
|
||||
'@ohif/(.*)': '<rootDir>/../../platform/$1/src',
|
||||
'^@cornerstonejs/([^/]+)/(.*)$': '<rootDir>/../../node_modules/@cornerstonejs/$1/dist/esm/$2',
|
||||
'^@cornerstonejs/([^/]+)$': '<rootDir>/../../node_modules/@cornerstonejs/$1/dist/esm',
|
||||
},
|
||||
// rootDir: "../.."
|
||||
// testMatch: [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone",
|
||||
"version": "3.13.0-beta.15",
|
||||
"version": "3.13.0-beta.97",
|
||||
"description": "OHIF extension for Cornerstone",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -13,9 +13,7 @@
|
||||
"./types": "./src/types/index.ts"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10",
|
||||
"npm": ">=6",
|
||||
"yarn": ">=1.16.0"
|
||||
"node": ">=24"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
@@ -26,12 +24,12 @@
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "shx rm -rf dist",
|
||||
"clean:deep": "yarn run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config .webpack/webpack.dev.js --watch --output-pathinfo",
|
||||
"dev:cornerstone": "yarn run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --progress --config .webpack/webpack.prod.js",
|
||||
"build:package-1": "yarn run build",
|
||||
"start": "yarn run dev",
|
||||
"clean:deep": "pnpm run clean && shx rm -rf node_modules",
|
||||
"dev": "cross-env NODE_ENV=development rspack build --config .webpack/webpack.dev.js --watch",
|
||||
"dev:cornerstone": "pnpm run dev",
|
||||
"build": "cross-env NODE_ENV=production rspack build --config .webpack/webpack.prod.js",
|
||||
"build:package-1": "pnpm run build",
|
||||
"start": "pnpm run dev",
|
||||
"test:unit": "jest --watchAll",
|
||||
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
|
||||
},
|
||||
@@ -40,9 +38,10 @@
|
||||
"@cornerstonejs/codec-libjpeg-turbo-8bit": "1.2.2",
|
||||
"@cornerstonejs/codec-openjpeg": "1.3.0",
|
||||
"@cornerstonejs/codec-openjph": "2.4.7",
|
||||
"@cornerstonejs/dicom-image-loader": "4.15.29",
|
||||
"@ohif/core": "3.13.0-beta.15",
|
||||
"@ohif/ui": "3.13.0-beta.15",
|
||||
"@cornerstonejs/dicom-image-loader": "5.0.2",
|
||||
"@ohif/core": "workspace:*",
|
||||
"@ohif/extension-default": "workspace:*",
|
||||
"@ohif/ui": "workspace:*",
|
||||
"dcmjs": "0.49.4",
|
||||
"dicom-parser": "1.8.21",
|
||||
"hammerjs": "2.0.8",
|
||||
@@ -52,16 +51,17 @@
|
||||
"react-resize-detector": "10.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.28.2",
|
||||
"@cornerstonejs/adapters": "4.15.29",
|
||||
"@cornerstonejs/ai": "4.15.29",
|
||||
"@cornerstonejs/core": "4.15.29",
|
||||
"@cornerstonejs/labelmap-interpolation": "4.15.29",
|
||||
"@cornerstonejs/polymorphic-segmentation": "4.15.29",
|
||||
"@cornerstonejs/tools": "4.15.29",
|
||||
"@babel/runtime": "7.29.7",
|
||||
"@cornerstonejs/adapters": "5.0.2",
|
||||
"@cornerstonejs/ai": "5.0.2",
|
||||
"@cornerstonejs/core": "5.0.2",
|
||||
"@cornerstonejs/labelmap-interpolation": "5.0.2",
|
||||
"@cornerstonejs/metadata": "5.0.2",
|
||||
"@cornerstonejs/polymorphic-segmentation": "5.0.2",
|
||||
"@cornerstonejs/tools": "5.0.2",
|
||||
"@icr/polyseg-wasm": "0.4.0",
|
||||
"@itk-wasm/morphological-contour-interpolation": "1.1.0",
|
||||
"@kitware/vtk.js": "34.15.1",
|
||||
"@kitware/vtk.js": "35.5.3",
|
||||
"html2canvas": "1.4.1",
|
||||
"immutability-helper": "3.1.1",
|
||||
"lodash.compact": "3.0.1",
|
||||
@@ -70,5 +70,8 @@
|
||||
"lodash.zip": "4.2.0",
|
||||
"shader-loader": "1.3.1",
|
||||
"worker-loader": "3.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "7.0.3"
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import ViewportImageScrollbar from './ViewportImageScrollbar';
|
||||
import ViewportSliceProgressScrollbar from './ViewportSliceProgressScrollbar/ViewportSliceProgressScrollbar';
|
||||
import CustomizableViewportOverlay from './CustomizableViewportOverlay';
|
||||
import ViewportOrientationMarkers from './ViewportOrientationMarkers';
|
||||
import ViewportImageSliceLoadingIndicator from './ViewportImageSliceLoadingIndicator';
|
||||
|
||||
function CornerstoneOverlays(props: withAppTypes) {
|
||||
const { viewportId, element, scrollbarHeight, servicesManager } = props;
|
||||
const { cornerstoneViewportService } = servicesManager.services;
|
||||
const { cornerstoneViewportService, customizationService } = servicesManager.services;
|
||||
const [imageSliceData, setImageSliceData] = useState({
|
||||
imageIndex: 0,
|
||||
numberOfSlices: 0,
|
||||
@@ -43,17 +44,31 @@ function CornerstoneOverlays(props: withAppTypes) {
|
||||
}
|
||||
}
|
||||
|
||||
const viewportScrollbarVariant = customizationService.getCustomization('viewportScrollbar.variant');
|
||||
const useProgressScrollbar = viewportScrollbarVariant !== 'legacy';
|
||||
|
||||
return (
|
||||
<div className="noselect">
|
||||
<ViewportImageScrollbar
|
||||
viewportId={viewportId}
|
||||
viewportData={viewportData}
|
||||
element={element}
|
||||
imageSliceData={imageSliceData}
|
||||
setImageSliceData={setImageSliceData}
|
||||
scrollbarHeight={scrollbarHeight}
|
||||
servicesManager={servicesManager}
|
||||
/>
|
||||
{useProgressScrollbar ? (
|
||||
<ViewportSliceProgressScrollbar
|
||||
viewportId={viewportId}
|
||||
viewportData={viewportData}
|
||||
element={element}
|
||||
imageSliceData={imageSliceData}
|
||||
setImageSliceData={setImageSliceData}
|
||||
servicesManager={servicesManager}
|
||||
/>
|
||||
) : (
|
||||
<ViewportImageScrollbar
|
||||
viewportId={viewportId}
|
||||
viewportData={viewportData}
|
||||
element={element}
|
||||
imageSliceData={imageSliceData}
|
||||
setImageSliceData={setImageSliceData}
|
||||
scrollbarHeight={scrollbarHeight}
|
||||
servicesManager={servicesManager}
|
||||
/>
|
||||
)}
|
||||
|
||||
<CustomizableViewportOverlay
|
||||
imageSliceData={imageSliceData}
|
||||
|
||||
@@ -67,10 +67,9 @@ function CustomizableViewportOverlay({
|
||||
}) {
|
||||
const { cornerstoneViewportService, customizationService, toolGroupService, displaySetService } =
|
||||
servicesManager.services;
|
||||
const [voi, setVOI] = useState({ windowCenter: null, windowWidth: null });
|
||||
const [scale, setScale] = useState(1);
|
||||
const [annotationState, setAnnotationState] = useState(0);
|
||||
const { isViewportBackgroundLight: isLight } = useViewportRendering(viewportId);
|
||||
const { isViewportBackgroundLight: isLight, windowLevel: voi } = useViewportRendering(viewportId);
|
||||
const { imageIndex } = imageSliceData;
|
||||
|
||||
// Historical usage defined the overlays as separate items due to lack of
|
||||
@@ -110,30 +109,6 @@ function CustomizableViewportOverlay({
|
||||
};
|
||||
}, [viewportData, viewportId, instanceNumber, cornerstoneViewportService]);
|
||||
|
||||
/**
|
||||
* Updating the VOI when the viewport changes its voi
|
||||
*/
|
||||
useEffect(() => {
|
||||
const updateVOI = eventDetail => {
|
||||
const { range } = eventDetail.detail;
|
||||
|
||||
if (!range) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { lower, upper } = range;
|
||||
const { windowWidth, windowCenter } = utilities.windowLevel.toWindowLevel(lower, upper);
|
||||
|
||||
setVOI({ windowCenter, windowWidth });
|
||||
};
|
||||
|
||||
element.addEventListener(Enums.Events.VOI_MODIFIED, updateVOI);
|
||||
|
||||
return () => {
|
||||
element.removeEventListener(Enums.Events.VOI_MODIFIED, updateVOI);
|
||||
};
|
||||
}, [viewportId, viewportData, voi, element]);
|
||||
|
||||
const annotationModified = useCallback(evt => {
|
||||
if (evt.detail.annotation.metadata.toolName === UltrasoundPleuraBLineTool.toolName) {
|
||||
// Update the annotation state to trigger a re-render
|
||||
@@ -226,6 +201,7 @@ function CustomizableViewportOverlay({
|
||||
scale,
|
||||
instanceNumber,
|
||||
annotationState,
|
||||
isLight,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -391,7 +367,7 @@ function OverlayItem(props) {
|
||||
title={title}
|
||||
>
|
||||
{label ? <span className="mr-1 shrink-0">{label}</span> : null}
|
||||
<span className="ml-0 mr-2 shrink-0">{value}</span>
|
||||
<span className="ml-0 shrink-0">{value}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -402,6 +378,7 @@ function OverlayItem(props) {
|
||||
*/
|
||||
function VOIOverlayItem({ voi, customization }: OverlayItemProps) {
|
||||
const { windowWidth, windowCenter } = voi;
|
||||
const { title } = customization;
|
||||
if (typeof windowCenter !== 'number' || typeof windowWidth !== 'number') {
|
||||
return null;
|
||||
}
|
||||
@@ -410,6 +387,7 @@ function VOIOverlayItem({ voi, customization }: OverlayItemProps) {
|
||||
<div
|
||||
className="overlay-item flex flex-row"
|
||||
style={{ color: customization?.color }}
|
||||
title={title}
|
||||
>
|
||||
<span className="mr-0.5 shrink-0 opacity-[0.70]">W:</span>
|
||||
<span className="mr-2.5 shrink-0">{windowWidth.toFixed(0)}</span>
|
||||
@@ -443,11 +421,13 @@ function InstanceNumberOverlayItem({
|
||||
customization,
|
||||
}: OverlayItemProps) {
|
||||
const { imageIndex, numberOfSlices } = imageSliceData;
|
||||
const { title } = customization;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="overlay-item flex flex-row"
|
||||
style={{ color: (customization && customization.color) || undefined }}
|
||||
title={title}
|
||||
>
|
||||
<span>
|
||||
{instanceNumber !== undefined && instanceNumber !== null ? (
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Enums, VolumeViewport3D, utilities as csUtils } from '@cornerstonejs/core';
|
||||
import { Enums, utilities as csUtils } from '@cornerstonejs/core';
|
||||
import { ImageScrollbar } from '@ohif/ui-next';
|
||||
import { isVolume3DViewportType } from '../../utils/getLegacyViewportType';
|
||||
|
||||
function CornerstoneImageScrollbar({
|
||||
viewportData,
|
||||
@@ -40,7 +41,7 @@ function CornerstoneImageScrollbar({
|
||||
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
|
||||
if (!viewport || viewport instanceof VolumeViewport3D) {
|
||||
if (!viewport || isVolume3DViewportType(viewport)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -69,7 +70,7 @@ function CornerstoneImageScrollbar({
|
||||
|
||||
const updateIndex = event => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
if (!viewport || viewport instanceof VolumeViewport3D) {
|
||||
if (!viewport || isVolume3DViewportType(viewport)) {
|
||||
return;
|
||||
}
|
||||
const { imageIndex, newImageIdIndex = imageIndex, imageIdIndex } = event.detail;
|
||||
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { utilities as csUtils } from '@cornerstonejs/core';
|
||||
import { isVolume3DViewportType } from '../../../utils/getLegacyViewportType';
|
||||
import {
|
||||
SmartScrollbar,
|
||||
SmartScrollbarTrack,
|
||||
SmartScrollbarFill,
|
||||
SmartScrollbarIndicator,
|
||||
SmartScrollbarEndpoints,
|
||||
} from '@ohif/ui-next';
|
||||
import { getViewportImageIds } from './helpers';
|
||||
import {
|
||||
useLoadedSliceBytes,
|
||||
useProgressScrollbarMode,
|
||||
useViewedSliceBytes,
|
||||
useViewportSliceSync,
|
||||
} from './hooks';
|
||||
import { ViewportSliceProgressScrollbarProps } from './types';
|
||||
|
||||
function ViewportSliceProgressScrollbar({
|
||||
viewportData,
|
||||
viewportId,
|
||||
element,
|
||||
imageSliceData,
|
||||
setImageSliceData,
|
||||
servicesManager,
|
||||
}: ViewportSliceProgressScrollbarProps) {
|
||||
const { cineService, cornerstoneViewportService, customizationService, viewedDataService } =
|
||||
servicesManager.services;
|
||||
|
||||
const showLoadedEndpoints =
|
||||
customizationService.getCustomization('viewportScrollbar.showLoadedEndpoints') !== false;
|
||||
const showLoadedFill =
|
||||
customizationService.getCustomization('viewportScrollbar.showLoadedFill') !== false;
|
||||
const showViewedFill =
|
||||
customizationService.getCustomization('viewportScrollbar.showViewedFill') !== false;
|
||||
const showLoadingPattern =
|
||||
customizationService.getCustomization('viewportScrollbar.showLoadingPattern') !== false;
|
||||
const viewedDwellMsRaw = customizationService.getCustomization('viewportScrollbar.viewedDwellMs');
|
||||
const loadedBatchIntervalMsRaw = customizationService.getCustomization(
|
||||
'viewportScrollbar.loadedBatchIntervalMs'
|
||||
);
|
||||
const viewedDwellMs =
|
||||
typeof viewedDwellMsRaw === 'number' && viewedDwellMsRaw >= 0 ? viewedDwellMsRaw : 0;
|
||||
const loadedBatchIntervalMs =
|
||||
typeof loadedBatchIntervalMsRaw === 'number' && loadedBatchIntervalMsRaw >= 0
|
||||
? loadedBatchIntervalMsRaw
|
||||
: 200;
|
||||
|
||||
const { numberOfSlices, imageIndex } = imageSliceData;
|
||||
|
||||
const imageIds = useMemo(() => getViewportImageIds(viewportData), [viewportData]);
|
||||
const imageIdToIndex = useMemo(() => {
|
||||
const map = new Map<string, number>();
|
||||
for (let i = 0; i < imageIds.length; i++) {
|
||||
const imageId = imageIds[i];
|
||||
if (imageId) {
|
||||
map.set(imageId, i);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}, [imageIds]);
|
||||
|
||||
const isFullMode = useProgressScrollbarMode({
|
||||
viewportData,
|
||||
viewportId,
|
||||
element,
|
||||
cornerstoneViewportService,
|
||||
});
|
||||
|
||||
useViewportSliceSync({
|
||||
viewportData,
|
||||
viewportId,
|
||||
element,
|
||||
cornerstoneViewportService,
|
||||
setImageSliceData,
|
||||
});
|
||||
|
||||
const {
|
||||
bytes: loadedBytes,
|
||||
version: loadedVersion,
|
||||
isFull: isFullyLoaded,
|
||||
} = useLoadedSliceBytes({
|
||||
isFullMode,
|
||||
numberOfSlices,
|
||||
viewportData,
|
||||
imageIds,
|
||||
imageIdToIndex,
|
||||
loadedBatchIntervalMs,
|
||||
});
|
||||
|
||||
const { bytes: viewedBytes, version: viewedVersion } = useViewedSliceBytes({
|
||||
isFullMode,
|
||||
numberOfSlices,
|
||||
imageIndex,
|
||||
imageIds,
|
||||
imageIdToIndex,
|
||||
viewedDwellMs,
|
||||
viewedDataService,
|
||||
});
|
||||
|
||||
const onScrollbarValueChange = targetImageIndex => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
|
||||
if (!viewport || isVolume3DViewportType(viewport)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { isCineEnabled } = cineService.getState();
|
||||
|
||||
if (isCineEnabled) {
|
||||
cineService.stopClip(element, { viewportId });
|
||||
cineService.setCine({ id: viewportId, frameRate: undefined, isPlaying: false });
|
||||
}
|
||||
|
||||
csUtils.jumpToSlice(viewport.element, {
|
||||
imageIndex: targetImageIndex,
|
||||
debounceLoading: true,
|
||||
});
|
||||
};
|
||||
|
||||
const isLoading = isFullMode && showLoadingPattern ? !isFullyLoaded : false;
|
||||
|
||||
if (!numberOfSlices || numberOfSlices <= 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0,
|
||||
height: '100%',
|
||||
padding: '8px 5px',
|
||||
zIndex: 10,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
height: '100%',
|
||||
width: '11px',
|
||||
}}
|
||||
>
|
||||
<SmartScrollbar
|
||||
className="absolute inset-0"
|
||||
value={imageIndex || 0}
|
||||
total={numberOfSlices}
|
||||
onValueChange={onScrollbarValueChange}
|
||||
isLoading={isLoading}
|
||||
enableKeyboardNavigation={false}
|
||||
aria-label="Image navigation scrollbar"
|
||||
indicator={
|
||||
customizationService.getCustomization('viewportScrollbar.indicator') as
|
||||
| Record<string, unknown>
|
||||
| undefined
|
||||
}
|
||||
>
|
||||
<SmartScrollbarTrack>
|
||||
{isFullMode && showLoadedFill && (
|
||||
<SmartScrollbarFill
|
||||
marked={loadedBytes}
|
||||
version={loadedVersion}
|
||||
className="bg-neutral/25"
|
||||
loadingClassName="bg-neutral/50"
|
||||
/>
|
||||
)}
|
||||
{isFullMode && showViewedFill && (
|
||||
<SmartScrollbarFill
|
||||
marked={viewedBytes}
|
||||
version={viewedVersion}
|
||||
className="bg-primary/35"
|
||||
loadingClassName="bg-primary/35"
|
||||
/>
|
||||
)}
|
||||
</SmartScrollbarTrack>
|
||||
<SmartScrollbarIndicator />
|
||||
{isFullMode && showLoadedEndpoints && (
|
||||
<SmartScrollbarEndpoints
|
||||
marked={loadedBytes}
|
||||
version={loadedVersion}
|
||||
/>
|
||||
)}
|
||||
</SmartScrollbar>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ViewportSliceProgressScrollbar.propTypes = {
|
||||
viewportData: PropTypes.object,
|
||||
viewportId: PropTypes.string.isRequired,
|
||||
element: PropTypes.instanceOf(Element),
|
||||
imageSliceData: PropTypes.object.isRequired,
|
||||
setImageSliceData: PropTypes.func.isRequired,
|
||||
servicesManager: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default ViewportSliceProgressScrollbar;
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
import { Enums } from '@cornerstonejs/core';
|
||||
import { ViewportData } from './types';
|
||||
import { isVolume3DViewportType } from '../../../utils/getLegacyViewportType';
|
||||
|
||||
export function getImageIndexFromEvent(event): number | undefined {
|
||||
const { imageIndex, newImageIdIndex = imageIndex, imageIdIndex } = event.detail;
|
||||
return newImageIdIndex ?? imageIdIndex;
|
||||
}
|
||||
|
||||
export function getViewportImageIds(viewportData: ViewportData): string[] {
|
||||
if (!viewportData?.data?.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const firstData = viewportData.data[0];
|
||||
const volumeImageIds = (firstData as any).volume?.imageIds as string[] | undefined;
|
||||
const datumImageIds = (firstData as any).imageIds as string[] | undefined;
|
||||
|
||||
return volumeImageIds || datumImageIds || [];
|
||||
}
|
||||
|
||||
export function isProgressFullMode(viewportData: ViewportData, viewport): boolean {
|
||||
if (!viewportData || !viewport || isVolume3DViewportType(viewport)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (viewportData.viewportType === Enums.ViewportType.STACK) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (viewportData.viewportType === Enums.ViewportType.ORTHOGRAPHIC) {
|
||||
return !!viewport.isInAcquisitionPlane?.();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getImageIdFromCacheEvent(event): string | undefined {
|
||||
const detail = event?.detail;
|
||||
return detail?.imageId || detail?.image?.imageId || detail?.cachedImage?.imageId;
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
cache as cornerstoneCache,
|
||||
Enums,
|
||||
eventTarget,
|
||||
utilities,
|
||||
} from '@cornerstonejs/core';
|
||||
import { useByteArray } from '@ohif/ui-next';
|
||||
import { isVolume3DViewportType } from '../../../utils/getLegacyViewportType';
|
||||
import { getImageIdFromCacheEvent, getImageIndexFromEvent, isProgressFullMode } from './helpers';
|
||||
import { ImageSliceData, ViewportData } from './types';
|
||||
|
||||
export function useProgressScrollbarMode({
|
||||
viewportData,
|
||||
viewportId,
|
||||
element,
|
||||
cornerstoneViewportService,
|
||||
}: {
|
||||
viewportData: ViewportData;
|
||||
viewportId: string;
|
||||
element: HTMLElement;
|
||||
cornerstoneViewportService: AppTypes.CornerstoneViewportService;
|
||||
}) {
|
||||
const [isFullMode, setIsFullMode] = useState(false);
|
||||
const lastViewPlaneNormalRef = useRef<number[] | null>(null);
|
||||
|
||||
/**
|
||||
* Tracks whether this viewport should render full progress UI (stack or acquisition-plane
|
||||
* orthographic volume) versus minimal UI. We compute once on setup and recompute on each
|
||||
* CAMERA_MODIFIED event so stack->MPR transitions and acquisition-plane changes are reflected
|
||||
* immediately.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (!viewportData) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updateMode = () => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
const viewportImageData = viewport?.getImageData?.();
|
||||
const nextViewPlaneNormal = viewport?.getCamera?.()?.viewPlaneNormal as number[] | undefined;
|
||||
// Do not update the lastViewPlaneNormalRef until we have a valid viewportImageData.
|
||||
// Without viewportImageData, the viewport is not fully initialized and the isAcquisitionPlane
|
||||
// check will not be accurate.
|
||||
if (viewportImageData && nextViewPlaneNormal) {
|
||||
lastViewPlaneNormalRef.current = [...nextViewPlaneNormal];
|
||||
}
|
||||
const nextMode = isProgressFullMode(viewportData, viewport);
|
||||
setIsFullMode(prevMode => (prevMode === nextMode ? prevMode : nextMode));
|
||||
};
|
||||
|
||||
updateMode();
|
||||
|
||||
const onCameraModified = () => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
const nextViewPlaneNormal = viewport?.getCamera?.()?.viewPlaneNormal as number[] | undefined;
|
||||
const previousViewPlaneNormal = lastViewPlaneNormalRef.current;
|
||||
|
||||
// Ignore camera updates that keep the same orientation (pan/zoom/scroll).
|
||||
if (nextViewPlaneNormal && previousViewPlaneNormal) {
|
||||
if (utilities.isEqual(nextViewPlaneNormal, previousViewPlaneNormal)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
updateMode();
|
||||
};
|
||||
element.addEventListener(Enums.Events.CAMERA_MODIFIED, onCameraModified);
|
||||
|
||||
return () => {
|
||||
element.removeEventListener(Enums.Events.CAMERA_MODIFIED, onCameraModified);
|
||||
};
|
||||
}, [viewportData, viewportId, cornerstoneViewportService, element]);
|
||||
|
||||
return isFullMode;
|
||||
}
|
||||
|
||||
export function useViewportSliceSync({
|
||||
viewportData,
|
||||
viewportId,
|
||||
element,
|
||||
cornerstoneViewportService,
|
||||
setImageSliceData,
|
||||
}: {
|
||||
viewportData: ViewportData;
|
||||
viewportId: string;
|
||||
element: HTMLElement;
|
||||
cornerstoneViewportService: AppTypes.CornerstoneViewportService;
|
||||
setImageSliceData: (data: ImageSliceData) => void;
|
||||
}) {
|
||||
/**
|
||||
* Keeps shared slice state in sync: first initialize from the live viewport snapshot, then
|
||||
* subscribe to navigation/render events for incremental updates while users scroll.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (!viewportData) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
if (viewport && !isVolume3DViewportType(viewport)) {
|
||||
try {
|
||||
const currentImageIndex = viewport.getCurrentImageIdIndex();
|
||||
const currentNumberOfSlices = viewport.getNumberOfSlices();
|
||||
|
||||
setImageSliceData({
|
||||
imageIndex: currentImageIndex,
|
||||
numberOfSlices: currentNumberOfSlices,
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
}
|
||||
}
|
||||
|
||||
const { viewportType } = viewportData;
|
||||
const eventId =
|
||||
(viewportType === Enums.ViewportType.STACK && Enums.Events.STACK_NEW_IMAGE) ||
|
||||
(viewportType === Enums.ViewportType.ORTHOGRAPHIC && Enums.Events.VOLUME_NEW_IMAGE) ||
|
||||
Enums.Events.IMAGE_RENDERED;
|
||||
|
||||
const updateIndex = event => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
if (!viewport || isVolume3DViewportType(viewport)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextImageIndex = getImageIndexFromEvent(event);
|
||||
if (nextImageIndex == null) {
|
||||
return;
|
||||
}
|
||||
const nextNumberOfSlices = viewport.getNumberOfSlices();
|
||||
|
||||
setImageSliceData({
|
||||
imageIndex: nextImageIndex,
|
||||
numberOfSlices: nextNumberOfSlices,
|
||||
});
|
||||
};
|
||||
|
||||
element.addEventListener(eventId, updateIndex);
|
||||
|
||||
return () => {
|
||||
element.removeEventListener(eventId, updateIndex);
|
||||
};
|
||||
}, [viewportData, element, viewportId, cornerstoneViewportService, setImageSliceData]);
|
||||
}
|
||||
|
||||
export function useLoadedSliceBytes({
|
||||
isFullMode,
|
||||
numberOfSlices,
|
||||
viewportData,
|
||||
imageIds,
|
||||
imageIdToIndex,
|
||||
loadedBatchIntervalMs,
|
||||
}: {
|
||||
isFullMode: boolean;
|
||||
numberOfSlices: number;
|
||||
viewportData: ViewportData;
|
||||
imageIds: string[];
|
||||
imageIdToIndex: Map<string, number>;
|
||||
loadedBatchIntervalMs: number;
|
||||
}) {
|
||||
const loadedState = useByteArray(numberOfSlices || 0, loadedBatchIntervalMs);
|
||||
const {
|
||||
resetWith: resetLoaded,
|
||||
setByte: setLoadedByte,
|
||||
clearByte: clearLoadedByte,
|
||||
} = loadedState;
|
||||
|
||||
/**
|
||||
* Keeps the loaded byte array in sync with Cornerstone cache: seed from cache whenever stack /
|
||||
* mode / slice count changes, then subscribe so cache add/remove updates stay incremental.
|
||||
* Seeding runs immediately before registering listeners in the same effect.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (isFullMode && numberOfSlices) {
|
||||
resetLoaded(bytes => {
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
const imageId = imageIds[i];
|
||||
if (imageId && cornerstoneCache.isLoaded(imageId)) {
|
||||
bytes[i] = 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!isFullMode || !viewportData) {
|
||||
return;
|
||||
}
|
||||
|
||||
const markLoaded = event => {
|
||||
const imageId = getImageIdFromCacheEvent(event);
|
||||
if (!imageId) {
|
||||
return;
|
||||
}
|
||||
const index = imageIdToIndex.get(imageId);
|
||||
if (index !== undefined) {
|
||||
setLoadedByte(index);
|
||||
}
|
||||
};
|
||||
|
||||
const markRemoved = event => {
|
||||
const imageId = getImageIdFromCacheEvent(event);
|
||||
if (!imageId) {
|
||||
return;
|
||||
}
|
||||
const index = imageIdToIndex.get(imageId);
|
||||
if (index !== undefined) {
|
||||
clearLoadedByte(index);
|
||||
}
|
||||
};
|
||||
|
||||
eventTarget.addEventListener(Enums.Events.IMAGE_CACHE_IMAGE_ADDED, markLoaded);
|
||||
eventTarget.addEventListener(Enums.Events.IMAGE_CACHE_IMAGE_REMOVED, markRemoved);
|
||||
|
||||
return () => {
|
||||
eventTarget.removeEventListener(Enums.Events.IMAGE_CACHE_IMAGE_ADDED, markLoaded);
|
||||
eventTarget.removeEventListener(Enums.Events.IMAGE_CACHE_IMAGE_REMOVED, markRemoved);
|
||||
};
|
||||
}, [
|
||||
imageIds,
|
||||
isFullMode,
|
||||
numberOfSlices,
|
||||
viewportData,
|
||||
imageIdToIndex,
|
||||
resetLoaded,
|
||||
setLoadedByte,
|
||||
clearLoadedByte,
|
||||
]);
|
||||
|
||||
return loadedState;
|
||||
}
|
||||
|
||||
export function useViewedSliceBytes({
|
||||
isFullMode,
|
||||
numberOfSlices,
|
||||
imageIndex,
|
||||
imageIds,
|
||||
imageIdToIndex,
|
||||
viewedDwellMs,
|
||||
viewedDataService,
|
||||
}: {
|
||||
isFullMode: boolean;
|
||||
numberOfSlices: number;
|
||||
imageIndex: number;
|
||||
imageIds: string[];
|
||||
imageIdToIndex: Map<string, number>;
|
||||
viewedDwellMs: number;
|
||||
viewedDataService: AppTypes.ViewedDataService;
|
||||
}) {
|
||||
const viewedState = useByteArray(numberOfSlices || 0);
|
||||
const { resetWith: resetViewed, setByte: setViewedByte } = viewedState;
|
||||
|
||||
/**
|
||||
* Keeps the viewed byte array in sync with the global viewed-data store: seed from the store
|
||||
* whenever stack / mode / slice count changes, then subscribe so `markDataViewed` updates stay
|
||||
* incremental. Seeding runs immediately before registering the listener in the same effect.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (isFullMode && numberOfSlices) {
|
||||
resetViewed(bytes => {
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
const imageId = imageIds[i];
|
||||
if (imageId && viewedDataService?.isDataViewed(imageId)) {
|
||||
bytes[i] = 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!viewedDataService) {
|
||||
return;
|
||||
}
|
||||
|
||||
const subscription = viewedDataService.subscribeViewedDataChanges(
|
||||
({
|
||||
viewedDataId,
|
||||
viewedDataCleared,
|
||||
}: {
|
||||
viewedDataId?: string;
|
||||
viewedDataCleared?: boolean;
|
||||
}) => {
|
||||
if (!isFullMode || !numberOfSlices) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (viewedDataCleared) {
|
||||
resetViewed(bytes => {
|
||||
bytes.fill(0);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const index = imageIdToIndex.get(viewedDataId);
|
||||
if (index !== undefined) {
|
||||
setViewedByte(index);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
subscription.unsubscribe();
|
||||
};
|
||||
}, [
|
||||
imageIds,
|
||||
isFullMode,
|
||||
numberOfSlices,
|
||||
imageIdToIndex,
|
||||
resetViewed,
|
||||
setViewedByte,
|
||||
viewedDataService,
|
||||
]);
|
||||
|
||||
/**
|
||||
* Marks slices as viewed in full mode. With `viewedDwellMs === 0`, marking is immediate on
|
||||
* index change; otherwise a dwell timer is used and cleaned up on subsequent changes/unmount.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (!isFullMode || !numberOfSlices) {
|
||||
return;
|
||||
}
|
||||
|
||||
const markViewed = (targetIndex: number) => {
|
||||
setViewedByte(targetIndex);
|
||||
const imageId = imageIds[targetIndex];
|
||||
if (imageId) {
|
||||
viewedDataService?.markDataViewed(imageId);
|
||||
}
|
||||
};
|
||||
|
||||
if (viewedDwellMs === 0) {
|
||||
markViewed(imageIndex || 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const timerId = window.setTimeout(() => {
|
||||
markViewed(imageIndex || 0);
|
||||
}, viewedDwellMs);
|
||||
|
||||
return () => {
|
||||
window.clearTimeout(timerId);
|
||||
};
|
||||
}, [
|
||||
isFullMode,
|
||||
numberOfSlices,
|
||||
imageIndex,
|
||||
imageIds,
|
||||
setViewedByte,
|
||||
viewedDwellMs,
|
||||
viewedDataService,
|
||||
]);
|
||||
|
||||
return viewedState;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './ViewportSliceProgressScrollbar';
|
||||
@@ -0,0 +1,17 @@
|
||||
import { StackViewportData, VolumeViewportData } from '../../../types/CornerstoneCacheService';
|
||||
|
||||
export type ViewportData = StackViewportData | VolumeViewportData;
|
||||
|
||||
export type ImageSliceData = {
|
||||
imageIndex: number;
|
||||
numberOfSlices: number;
|
||||
};
|
||||
|
||||
export type ViewportSliceProgressScrollbarProps = {
|
||||
viewportData: ViewportData | null;
|
||||
viewportId: string;
|
||||
element: HTMLElement;
|
||||
imageSliceData: ImageSliceData;
|
||||
setImageSliceData: (data: ImageSliceData) => void;
|
||||
servicesManager: AppTypes.ServicesManager;
|
||||
};
|
||||
@@ -1,11 +1,7 @@
|
||||
import {
|
||||
getEnabledElement,
|
||||
StackViewport,
|
||||
VolumeViewport,
|
||||
utilities as csUtils,
|
||||
Enums as CoreEnums,
|
||||
Types as CoreTypes,
|
||||
BaseVolumeViewport,
|
||||
getRenderingEngines,
|
||||
} from '@cornerstonejs/core';
|
||||
import {
|
||||
@@ -38,6 +34,12 @@ import { getFirstAnnotationSelected } from './utils/measurementServiceMappings/u
|
||||
import { getViewportEnabledElement } from './utils/getViewportEnabledElement';
|
||||
import getActiveViewportEnabledElement from './utils/getActiveViewportEnabledElement';
|
||||
import toggleVOISliceSync from './utils/toggleVOISliceSync';
|
||||
import {
|
||||
isStackViewportType,
|
||||
isOrthographicViewportType,
|
||||
isVolume3DViewportType,
|
||||
isVolumeViewportType,
|
||||
} from './utils/getLegacyViewportType';
|
||||
import {
|
||||
usePositionPresentationStore,
|
||||
useSegmentationPresentationStore,
|
||||
@@ -145,7 +147,21 @@ function commandsModule({
|
||||
|
||||
function _getActiveViewportToolGroupId() {
|
||||
const viewport = _getActiveViewportEnabledElement();
|
||||
return toolGroupService.getToolGroupForViewport(viewport.id);
|
||||
const toolGroup = viewport && toolGroupService.getToolGroupForViewport(viewport.id);
|
||||
return toolGroup?.id;
|
||||
}
|
||||
|
||||
function _usesPrimaryActivation(bindings) {
|
||||
if (!bindings?.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return bindings.some(
|
||||
binding =>
|
||||
binding.mouseButton === Enums.MouseBindings.Primary &&
|
||||
binding.modifierKey == null &&
|
||||
binding.numTouchPoints == null
|
||||
);
|
||||
}
|
||||
|
||||
function _getActiveSegmentationInfo() {
|
||||
@@ -310,7 +326,7 @@ function commandsModule({
|
||||
// Todo: check if PMAP modality should be handled such as SEG
|
||||
displaySet.Modality !== 'SEG'
|
||||
? SegmentationRepresentations.Contour
|
||||
: viewport.type === CoreEnums.ViewportType.VOLUME_3D
|
||||
: isVolume3DViewportType(viewport)
|
||||
? SegmentationRepresentations.Surface
|
||||
: SegmentationRepresentations.Labelmap;
|
||||
|
||||
@@ -398,12 +414,31 @@ function commandsModule({
|
||||
|
||||
const { segmentationId: targetId, segmentIndex: targetIndex } = targetSegmentation;
|
||||
|
||||
// Check if the segment has voxels before computing bidirectional measurement
|
||||
const uniqueSegmentIndices = cstUtils.segmentation.getUniqueSegmentIndices(targetId);
|
||||
const hasVoxels = uniqueSegmentIndices.includes(targetIndex);
|
||||
|
||||
if (!hasVoxels) {
|
||||
uiNotificationService.show({
|
||||
title: i18n.t('SegmentationPanel:Segment Bidirectional'),
|
||||
message: i18n.t(
|
||||
'SegmentationPanel:Draw a segment before using bidirectional measurement'
|
||||
),
|
||||
type: 'warning',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Get bidirectional measurement data
|
||||
const bidirectionalData = await cstUtils.segmentation.getSegmentLargestBidirectional({
|
||||
segmentationId: targetId,
|
||||
segmentIndices: [targetIndex],
|
||||
});
|
||||
|
||||
if (!bidirectionalData.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const activeViewportId = viewportGridService.getActiveViewportId();
|
||||
|
||||
// Process each bidirectional measurement
|
||||
@@ -445,7 +480,7 @@ function commandsModule({
|
||||
measurement => measurement.segmentIndex === targetIndex
|
||||
);
|
||||
commandsManager.run('jumpToMeasurement', {
|
||||
uid: activeBidirectional.annotationUID,
|
||||
uid: activeBidirectional?.annotationUID,
|
||||
});
|
||||
},
|
||||
interpolateLabelmap: () => {
|
||||
@@ -737,6 +772,9 @@ function commandsModule({
|
||||
* Also marks any provided display measurements isActive value
|
||||
*/
|
||||
jumpToMeasurement: ({ uid, displayMeasurements = [] }) => {
|
||||
if (!uid) {
|
||||
return;
|
||||
}
|
||||
measurementService.jumpToMeasurement(viewportGridService.getActiveViewportId(), uid);
|
||||
for (const measurement of displayMeasurements) {
|
||||
measurement.isActive = measurement.uid === uid;
|
||||
@@ -874,7 +912,7 @@ function commandsModule({
|
||||
|
||||
const { lower, upper } = csUtils.windowLevel.toLowHighRange(windowWidthNum, windowCenterNum);
|
||||
|
||||
if (viewport instanceof BaseVolumeViewport) {
|
||||
if (isVolumeViewportType(viewport)) {
|
||||
const volumeId = actions.getVolumeIdForDisplaySet({
|
||||
viewportId,
|
||||
displaySetInstanceUID,
|
||||
@@ -950,8 +988,12 @@ function commandsModule({
|
||||
},
|
||||
getVolumeIdForDisplaySet: ({ viewportId, displaySetInstanceUID }) => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
if (viewport instanceof BaseVolumeViewport) {
|
||||
const volumeIds = viewport.getAllVolumeIds();
|
||||
// `instanceof BaseVolumeViewport` is false for GenericViewport compat adapters,
|
||||
// so use the capability guard instead (cornerstone 5.x generic-viewport guide).
|
||||
// A stack-mode adapter passes the guard but getAllVolumeIds() returns [], so the
|
||||
// result is the same null as before on stacks.
|
||||
if (csUtils.viewportSupportsVolumeId(viewport)) {
|
||||
const volumeIds = (viewport as CoreTypes.IVolumeViewport).getAllVolumeIds();
|
||||
const volumeId = volumeIds.find(id => id.includes(displaySetInstanceUID));
|
||||
return volumeId;
|
||||
}
|
||||
@@ -995,32 +1037,48 @@ function commandsModule({
|
||||
|
||||
toolIsEnabled ? toolGroup.setToolDisabled(toolName) : toolGroup.setToolEnabled(toolName);
|
||||
},
|
||||
toggleActiveDisabledToolbar({ value, itemId, toolGroupId }) {
|
||||
toggleActiveDisabledToolbar({ value, itemId, toolGroupId, toolGroupIds }) {
|
||||
const toolName = itemId || value;
|
||||
toolGroupId = toolGroupId ?? _getActiveViewportToolGroupId();
|
||||
const toolGroup = toolGroupService.getToolGroup(toolGroupId);
|
||||
if (!toolGroup || !toolGroup.hasTool(toolName)) {
|
||||
return;
|
||||
}
|
||||
const resolvedToolGroupIds = toolGroupIds?.length
|
||||
? toolGroupIds
|
||||
: [toolGroupId ?? _getActiveViewportToolGroupId()];
|
||||
|
||||
const toolIsActive = [
|
||||
Enums.ToolModes.Active,
|
||||
Enums.ToolModes.Enabled,
|
||||
Enums.ToolModes.Passive,
|
||||
].includes(toolGroup.getToolOptions(toolName).mode);
|
||||
|
||||
toolIsActive
|
||||
? toolGroup.setToolDisabled(toolName)
|
||||
: actions.setToolActive({ toolName, toolGroupId });
|
||||
|
||||
// we should set the previously active tool to active after we set the
|
||||
// current tool disabled
|
||||
if (toolIsActive) {
|
||||
const prevToolName = toolGroup.getPrevActivePrimaryToolName();
|
||||
if (prevToolName !== toolName) {
|
||||
actions.setToolActive({ toolName: prevToolName, toolGroupId });
|
||||
resolvedToolGroupIds.forEach(toolGroupId => {
|
||||
const toolGroup = toolGroupService.getToolGroup(toolGroupId);
|
||||
if (!toolGroup || !toolGroup.hasTool(toolName)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const toolIsActive = [
|
||||
Enums.ToolModes.Active,
|
||||
Enums.ToolModes.Enabled,
|
||||
Enums.ToolModes.Passive,
|
||||
].includes(toolGroup.getToolOptions(toolName).mode);
|
||||
|
||||
if (toolIsActive) {
|
||||
toolGroup.setToolDisabled(toolName);
|
||||
|
||||
const bindings = toolGroupService.getToolBindings(toolGroupId, toolName);
|
||||
|
||||
if (_usesPrimaryActivation(bindings)) {
|
||||
// we should set the previously active tool to active after we set the
|
||||
// current tool disabled
|
||||
const prevToolName = toolGroup.getPrevActivePrimaryToolName();
|
||||
if (prevToolName !== toolName) {
|
||||
actions.setToolActive({ toolName: prevToolName, toolGroupId });
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const bindings = toolGroupService.getToolBindings(toolGroupId, toolName);
|
||||
if (_usesPrimaryActivation(bindings)) {
|
||||
actions.setToolActive({ toolName, toolGroupId, bindings });
|
||||
} else {
|
||||
toolGroup.setToolActive(toolName, { bindings });
|
||||
}
|
||||
});
|
||||
},
|
||||
setToolActiveToolbar: ({ value, itemId, toolName, toolGroupIds = [], bindings }) => {
|
||||
// Sometimes it is passed as value (tools with options), sometimes as itemId (toolbar buttons)
|
||||
@@ -1204,7 +1262,7 @@ function commandsModule({
|
||||
}
|
||||
const { viewport } = enabledElement;
|
||||
|
||||
if (viewport instanceof StackViewport) {
|
||||
if (isStackViewportType(viewport)) {
|
||||
if (direction) {
|
||||
const { parallelScale } = viewport.getCamera();
|
||||
viewport.setCamera({ parallelScale: parallelScale * scaleFactor });
|
||||
@@ -1234,9 +1292,9 @@ function commandsModule({
|
||||
// -> Copied from cornerstone3D jumpToSlice\_getImageSliceData()
|
||||
let numberOfSlices = 0;
|
||||
|
||||
if (viewport instanceof StackViewport) {
|
||||
if (isStackViewportType(viewport)) {
|
||||
numberOfSlices = viewport.getImageIds().length;
|
||||
} else if (viewport instanceof VolumeViewport) {
|
||||
} else if (isOrthographicViewportType(viewport)) {
|
||||
numberOfSlices = csUtils.getImageSliceDataForVolumeViewport(viewport).numberOfSlices;
|
||||
} else {
|
||||
throw new Error('Unsupported viewport type');
|
||||
@@ -1292,11 +1350,11 @@ function commandsModule({
|
||||
// HP takes priority over the default opacity
|
||||
colormap = { ...colormap, opacity: hpOpacity || opacity };
|
||||
|
||||
if (viewport instanceof StackViewport) {
|
||||
if (isStackViewportType(viewport)) {
|
||||
viewport.setProperties({ colormap });
|
||||
}
|
||||
|
||||
if (viewport instanceof VolumeViewport) {
|
||||
if (isOrthographicViewportType(viewport)) {
|
||||
if (!displaySetInstanceUID) {
|
||||
const { viewports } = viewportGridService.getState();
|
||||
displaySetInstanceUID = viewports.get(viewportId)?.displaySetInstanceUIDs[0];
|
||||
@@ -1735,12 +1793,14 @@ function commandsModule({
|
||||
* Removes a segmentation from the viewport
|
||||
* @param props.segmentationId - The ID of the segmentation to remove
|
||||
*/
|
||||
removeSegmentationFromViewportCommand: ({ segmentationId }) => {
|
||||
const { segmentationService, viewportGridService } = servicesManager.services;
|
||||
segmentationService.removeSegmentationRepresentations(
|
||||
viewportGridService.getActiveViewportId(),
|
||||
{ segmentationId }
|
||||
);
|
||||
removeSegmentationFromViewportCommand: ({ segmentationId: displaySetInstanceUID }) => {
|
||||
const { viewportGridService } = servicesManager.services;
|
||||
const viewportId = viewportGridService.getActiveViewportId();
|
||||
|
||||
commandsManager.runCommand('removeDisplaySetLayer', {
|
||||
viewportId,
|
||||
displaySetInstanceUID,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -2072,6 +2132,15 @@ function commandsModule({
|
||||
displaySetInstanceUIDs,
|
||||
});
|
||||
|
||||
if (!updatedViewports?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
updatedViewports.forEach(({ viewportId: csViewportId }) => {
|
||||
const csViewport = cornerstoneViewportService.getCornerstoneViewport(csViewportId);
|
||||
csViewport?.setNeedsRender?.();
|
||||
});
|
||||
|
||||
actions.setDisplaySetsForViewports({
|
||||
viewportsToUpdate: updatedViewports.map(viewport => ({
|
||||
viewportId: viewport.viewportId,
|
||||
@@ -2082,7 +2151,7 @@ function commandsModule({
|
||||
setViewportOrientation: ({ viewportId, orientation }) => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
|
||||
if (!viewport || viewport.type !== CoreEnums.ViewportType.ORTHOGRAPHIC) {
|
||||
if (!viewport || !isOrthographicViewportType(viewport)) {
|
||||
console.warn('Orientation can only be set on volume viewports');
|
||||
return;
|
||||
}
|
||||
@@ -2164,7 +2233,7 @@ function commandsModule({
|
||||
|
||||
const { viewport } = enabledElement;
|
||||
|
||||
if (viewport instanceof BaseVolumeViewport) {
|
||||
if (isVolumeViewportType(viewport)) {
|
||||
const camera = viewport.getCamera();
|
||||
const rotAngle = (rotation * Math.PI) / 180;
|
||||
const rotMat = mat4.identity(new Float32Array(16));
|
||||
@@ -2340,14 +2409,25 @@ function commandsModule({
|
||||
targetSegmentInfo?: SegmentInfo;
|
||||
}) => {
|
||||
if (!targetSegmentInfo) {
|
||||
const sourceSegmentation = segmentationService.getSegmentation(
|
||||
sourceSegmentInfo.segmentationId
|
||||
);
|
||||
const sourceCachedStats =
|
||||
sourceSegmentation?.segments?.[sourceSegmentInfo.segmentIndex]?.cachedStats;
|
||||
|
||||
targetSegmentInfo = {
|
||||
segmentationId: sourceSegmentInfo.segmentationId,
|
||||
segmentIndex: segmentationService.getNextAvailableSegmentIndex(
|
||||
sourceSegmentInfo.segmentationId
|
||||
),
|
||||
};
|
||||
|
||||
// Copy source cachedStats so jump-to-segment navigation works on the duplicate segment.
|
||||
segmentationService.addSegment(targetSegmentInfo.segmentationId, {
|
||||
segmentIndex: targetSegmentInfo.segmentIndex,
|
||||
...(sourceCachedStats && {
|
||||
cachedStats: csUtils.deepClone(sourceCachedStats) as Record<string, unknown>,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,7 @@ import {
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
Icons,
|
||||
} from '@ohif/ui-next';
|
||||
|
||||
@@ -19,8 +17,6 @@ interface ExportSegmentationSubMenuItemProps {
|
||||
allowExport: boolean;
|
||||
actions: {
|
||||
storeSegmentation: (segmentationId: string, modality?: string) => Promise<unknown>;
|
||||
onSegmentationDownloadRTSS: (segmentationId: string) => void;
|
||||
onSegmentationDownload: (segmentationId: string) => void;
|
||||
downloadCSVSegmentationReport: (segmentationId: string) => void;
|
||||
};
|
||||
}
|
||||
@@ -37,14 +33,10 @@ export const ExportSegmentationSubMenuItem: React.FC<ExportSegmentationSubMenuIt
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger className="pl-1">
|
||||
<Icons.Export className="text-foreground" />
|
||||
<span className="pl-2">{t('Download & Export')}</span>
|
||||
<span className="pl-2">{t('Export')}</span>
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuLabel className="flex items-center pl-0">
|
||||
<Icons.Download className="h-5 w-5" />
|
||||
<span className="pl-1">{t('Download')}</span>
|
||||
</DropdownMenuLabel>
|
||||
{segmentationRepresentationType === SegmentationRepresentations.Labelmap && (
|
||||
<DropdownMenuItem
|
||||
onClick={e => {
|
||||
@@ -56,31 +48,6 @@ export const ExportSegmentationSubMenuItem: React.FC<ExportSegmentationSubMenuIt
|
||||
{t('CSV Report')}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
{segmentationRepresentationType === SegmentationRepresentations.Labelmap && (
|
||||
<DropdownMenuItem
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
actions.onSegmentationDownload(segmentationId);
|
||||
}}
|
||||
disabled={!allowExport}
|
||||
>
|
||||
{t('DICOM SEG')}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
<DropdownMenuItem
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
actions.onSegmentationDownloadRTSS(segmentationId);
|
||||
}}
|
||||
disabled={!allowExport}
|
||||
>
|
||||
{t('DICOM RTSS')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuLabel className="flex items-center pl-0">
|
||||
<Icons.Export className="h-5 w-5" />
|
||||
<span className="pl-1 pt-1">{t('Export')}</span>
|
||||
</DropdownMenuLabel>
|
||||
{segmentationRepresentationType === SegmentationRepresentations.Labelmap && (
|
||||
<DropdownMenuItem
|
||||
onClick={e => {
|
||||
|
||||
+9
-2
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Icons,
|
||||
@@ -43,6 +43,10 @@ function ViewportDataOverlayMenu({ viewportId }: withAppTypes<{ viewportId: stri
|
||||
|
||||
const [thresholdOpacityEnabled, setThresholdOpacityEnabled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setOptimisticOverlayDisplaySets(overlayDisplaySets);
|
||||
}, [backgroundDisplaySet?.displaySetInstanceUID, overlayDisplaySets]);
|
||||
|
||||
/**
|
||||
* Change the background display set
|
||||
*/
|
||||
@@ -482,7 +486,10 @@ function ViewportDataOverlayMenu({ viewportId }: withAppTypes<{ viewportId: stri
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="flex-1">
|
||||
<SelectTrigger
|
||||
className="flex-1"
|
||||
data-cy={`overlay-background-ds-select-${viewportId}`}
|
||||
>
|
||||
<SelectValue>
|
||||
{(
|
||||
backgroundDisplaySet?.SeriesDescription ||
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useEffect, useCallback, useState, ReactElement, useMemo } from '
|
||||
import PropTypes from 'prop-types';
|
||||
import debounce from 'lodash.debounce';
|
||||
import { PanelSection, WindowLevel } from '@ohif/ui-next';
|
||||
import { BaseVolumeViewport, Enums, eventTarget } from '@cornerstonejs/core';
|
||||
import { Enums, eventTarget, utilities as csUtils, Types } from '@cornerstonejs/core';
|
||||
import { useActiveViewportDisplaySets } from '@ohif/core';
|
||||
import {
|
||||
getNodeOpacity,
|
||||
@@ -27,10 +27,16 @@ const ViewportWindowLevel = ({
|
||||
const getViewportsWithVolumeIds = useCallback(
|
||||
(volumeIds: string[]) => {
|
||||
const renderingEngine = cornerstoneViewportService.getRenderingEngine();
|
||||
const viewports = renderingEngine.getVolumeViewports();
|
||||
// getVolumeViewports() was removed in the GenericViewport architecture
|
||||
// (a PLANAR_NEXT viewport can be volume-capable without being a VolumeViewport).
|
||||
// Official replacement: getViewports() + the viewportSupportsVolumeCompatibility
|
||||
// capability guard (cornerstone codemod cornerstone3d/5/generic-viewport).
|
||||
const viewports = renderingEngine
|
||||
.getViewports()
|
||||
.filter(csUtils.viewportSupportsVolumeCompatibility);
|
||||
|
||||
return viewports.filter(vp => {
|
||||
const viewportVolumeIds = vp instanceof BaseVolumeViewport ? vp.getAllVolumeIds() : [];
|
||||
const viewportVolumeIds = (vp as Types.IVolumeViewport).getAllVolumeIds();
|
||||
return (
|
||||
volumeIds.length === viewportVolumeIds.length &&
|
||||
volumeIds.every(volumeId => viewportVolumeIds.includes(volumeId))
|
||||
@@ -124,8 +130,9 @@ const ViewportWindowLevel = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const viewportVolumeIds =
|
||||
viewport instanceof BaseVolumeViewport ? viewport.getAllVolumeIds() : [];
|
||||
const viewportVolumeIds = csUtils.viewportSupportsVolumeId(viewport)
|
||||
? (viewport as Types.IVolumeViewport).getAllVolumeIds()
|
||||
: [];
|
||||
const viewports = getViewportsWithVolumeIds(viewportVolumeIds);
|
||||
|
||||
viewports.forEach(vp => {
|
||||
|
||||
@@ -64,12 +64,6 @@ export const CustomDropdownMenuContent = () => {
|
||||
context: 'CORNERSTONE',
|
||||
});
|
||||
},
|
||||
onSegmentationDownloadRTSS: segmentationId => {
|
||||
commandsManager.run('downloadRTSS', { segmentationId });
|
||||
},
|
||||
onSegmentationDownload: segmentationId => {
|
||||
commandsManager.run('downloadSegmentation', { segmentationId });
|
||||
},
|
||||
downloadCSVSegmentationReport: segmentationId => {
|
||||
commandsManager.run('downloadCSVSegmentationReport', { segmentationId });
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { ImageModal, FooterAction } from '@ohif/ui-next';
|
||||
import { ImageModal, FooterAction, toast } from '@ohif/ui-next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
const MAX_TEXTURE_SIZE = 10000;
|
||||
const DEFAULT_FILENAME = 'image';
|
||||
@@ -16,6 +16,7 @@ interface ViewportDownloadFormNewProps {
|
||||
onEnableViewport: (element: HTMLElement) => void;
|
||||
onDisableViewport: () => void;
|
||||
onDownload: (filename: string, fileType: string) => void;
|
||||
onCopyToClipboard: () => void;
|
||||
warningState: { enabled: boolean; value: string };
|
||||
}
|
||||
|
||||
@@ -32,6 +33,7 @@ function ViewportDownloadFormNew({
|
||||
onEnableViewport,
|
||||
onDisableViewport,
|
||||
onDownload,
|
||||
onCopyToClipboard,
|
||||
}: ViewportDownloadFormNewProps) {
|
||||
const [viewportElement, setViewportElement] = useState<HTMLElement | null>(null);
|
||||
const [showWarningMessage, setShowWarningMessage] = useState(true);
|
||||
@@ -138,13 +140,27 @@ function ViewportDownloadFormNew({
|
||||
<FooterAction.Secondary onClick={onClose}>
|
||||
{t('Common:Cancel')}
|
||||
</FooterAction.Secondary>
|
||||
<FooterAction.Secondary
|
||||
onClick={async () => {
|
||||
try {
|
||||
await onCopyToClipboard();
|
||||
toast.success(t('Image copied to clipboard'));
|
||||
onClose();
|
||||
} catch (error) {
|
||||
toast.error(t('Failed to copy image to clipboard'));
|
||||
console.error('Failed to copy to clipboard:', error);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('Copy to Clipboard')}
|
||||
</FooterAction.Secondary>
|
||||
<FooterAction.Primary
|
||||
onClick={() => {
|
||||
onDownload(filename || DEFAULT_FILENAME, fileType);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t('Common:Save')}
|
||||
{t('Save Image')}
|
||||
</FooterAction.Primary>
|
||||
</FooterAction.Right>
|
||||
</FooterAction>
|
||||
|
||||
@@ -25,6 +25,7 @@ export default {
|
||||
{
|
||||
id: 'WindowLevel',
|
||||
inheritsFrom: 'ohif.overlayItem.windowLevel',
|
||||
title: 'Window Level',
|
||||
},
|
||||
{
|
||||
id: 'ZoomLevel',
|
||||
@@ -39,6 +40,7 @@ export default {
|
||||
{
|
||||
id: 'InstanceNumber',
|
||||
inheritsFrom: 'ohif.overlayItem.instanceNumber',
|
||||
title: 'Instance Number',
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Default customization values for viewport scrollbar behavior.
|
||||
* The `progress` scrollbar variant is in full mode for stack viewports and
|
||||
* acquisition-plane orthographic viewports.
|
||||
* Otherwise, viewports using the `progress` scrollbar show only the indicator.
|
||||
*
|
||||
* - `viewportScrollbar.variant`: `'progress' | 'legacy'` (default: `'progress'`)
|
||||
* - `viewportScrollbar.showLoadedEndpoints`: show loaded-range endpoint caps in full mode
|
||||
* - `viewportScrollbar.showLoadedFill`: show loaded/cached fill in full mode
|
||||
* - `viewportScrollbar.showViewedFill`: show viewed fill in full mode
|
||||
* - `viewportScrollbar.showLoadingPattern`: show loading pattern in full mode while not fully loaded
|
||||
* - `viewportScrollbar.viewedDwellMs`: delay before marking current image viewed in full mode (ms)
|
||||
* - `viewportScrollbar.loadedBatchIntervalMs`: loaded-state version batch interval in full mode (ms)
|
||||
* - `viewportScrollbar.indicator`: optional custom indicator config
|
||||
*/
|
||||
export default function getViewportScrollbarCustomization() {
|
||||
return {
|
||||
'viewportScrollbar.variant': 'progress',
|
||||
'viewportScrollbar.showLoadedEndpoints': true,
|
||||
'viewportScrollbar.showLoadedFill': true,
|
||||
'viewportScrollbar.showViewedFill': true,
|
||||
'viewportScrollbar.showLoadingPattern': true,
|
||||
'viewportScrollbar.viewedDwellMs': 0,
|
||||
'viewportScrollbar.loadedBatchIntervalMs': 200,
|
||||
'viewportScrollbar.indicator': {},
|
||||
};
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import windowLevelPresetsCustomization from './customizations/windowLevelPresets
|
||||
import miscCustomization from './customizations/miscCustomization';
|
||||
import captureViewportModalCustomization from './customizations/captureViewportModalCustomization';
|
||||
import viewportDownloadWarningCustomization from './customizations/viewportDownloadWarningCustomization';
|
||||
import getViewportScrollbarCustomization from './customizations/viewportScrollbarCustomization';
|
||||
|
||||
function getCustomizationModule({ commandsManager, servicesManager, extensionManager }) {
|
||||
return [
|
||||
@@ -34,6 +35,7 @@ function getCustomizationModule({ commandsManager, servicesManager, extensionMan
|
||||
...miscCustomization,
|
||||
...captureViewportModalCustomization,
|
||||
...viewportDownloadWarningCustomization,
|
||||
...getViewportScrollbarCustomization(),
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -3,6 +3,7 @@ import i18n from '@ohif/i18n';
|
||||
import { utilities as csUtils, Enums as csEnums } from '@cornerstonejs/core';
|
||||
import dcmjs from 'dcmjs';
|
||||
import { dicomWebUtils } from '@ohif/extension-default';
|
||||
import { buildEcgModule } from './utils/ecgMetadata';
|
||||
|
||||
const { MetadataModules } = csEnums;
|
||||
const { utils } = OHIF;
|
||||
@@ -155,6 +156,84 @@ export function getDicomMicroscopySopClassHandler({ servicesManager, extensionMa
|
||||
};
|
||||
}
|
||||
|
||||
export function getSopClassHandlerModule(params) {
|
||||
return [getDicomMicroscopySopClassHandler(params)];
|
||||
/**
|
||||
* DICOM Waveform SOP Class UIDs for ECG / cardiac electrophysiology.
|
||||
* Reference: https://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_B.5.html
|
||||
*/
|
||||
const ECG_SOP_CLASS_UIDS = {
|
||||
TWELVE_LEAD_ECG_WAVEFORM_STORAGE: '1.2.840.10008.5.1.4.1.1.9.1.1',
|
||||
GENERAL_ECG_WAVEFORM_STORAGE: '1.2.840.10008.5.1.4.1.1.9.1.2',
|
||||
AMBULATORY_ECG_WAVEFORM_STORAGE: '1.2.840.10008.5.1.4.1.1.9.1.3',
|
||||
HEMODYNAMIC_WAVEFORM_STORAGE: '1.2.840.10008.5.1.4.1.1.9.2.1',
|
||||
CARDIAC_ELECTROPHYSIOLOGY_WAVEFORM_STORAGE: '1.2.840.10008.5.1.4.1.1.9.3.1',
|
||||
};
|
||||
|
||||
const ecgSopClassUids = Object.values(ECG_SOP_CLASS_UIDS);
|
||||
|
||||
const DicomEcgSOPClassHandlerId =
|
||||
'@ohif/extension-cornerstone.sopClassHandlerModule.DicomEcgSopClassHandler';
|
||||
|
||||
function _getEcgDisplaySetsFromSeries(instances, servicesManager) {
|
||||
const { userAuthenticationService } = servicesManager.services;
|
||||
|
||||
return instances.map(instance => {
|
||||
const { Modality, SOPInstanceUID } = instance;
|
||||
const { SeriesDescription, SeriesNumber, SeriesDate } = instance;
|
||||
const { SeriesInstanceUID, StudyInstanceUID, SOPClassUID } = instance;
|
||||
const imageId = instance.imageId;
|
||||
|
||||
// Register ECG metadata in the OHIF metadata provider so that
|
||||
// Cornerstone's ECGViewport can retrieve it via metaData.get('ecgModule', imageId).
|
||||
if (imageId) {
|
||||
const ecgModule = buildEcgModule(instance, userAuthenticationService);
|
||||
if (ecgModule) {
|
||||
csUtils.genericMetadataProvider.addRaw(imageId, {
|
||||
type: MetadataModules.ECG,
|
||||
metadata: ecgModule,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
Modality,
|
||||
displaySetInstanceUID: utils.guid(),
|
||||
SeriesDescription,
|
||||
SeriesNumber,
|
||||
SeriesDate,
|
||||
SOPInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
StudyInstanceUID,
|
||||
SOPClassHandlerId: DicomEcgSOPClassHandlerId,
|
||||
SOPClassUID,
|
||||
referencedImages: null,
|
||||
measurements: null,
|
||||
viewportType: csEnums.ViewportType.ECG,
|
||||
instances: [instance],
|
||||
instance,
|
||||
thumbnailSrc: null,
|
||||
isDerivedDisplaySet: false,
|
||||
isLoaded: false,
|
||||
sopClassUids: ecgSopClassUids,
|
||||
numImageFrames: 0,
|
||||
numInstances: 1,
|
||||
imageIds: imageId ? [imageId] : [],
|
||||
supportsWindowLevel: false,
|
||||
label: SeriesDescription || 'ECG',
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function getDicomEcgSopClassHandler({ servicesManager }) {
|
||||
const getDisplaySetsFromSeries = instances =>
|
||||
_getEcgDisplaySetsFromSeries(instances, servicesManager);
|
||||
|
||||
return {
|
||||
name: 'DicomEcgSopClassHandler',
|
||||
sopClassUids: ecgSopClassUids,
|
||||
getDisplaySetsFromSeries,
|
||||
};
|
||||
}
|
||||
|
||||
export function getSopClassHandlerModule(params) {
|
||||
return [getDicomMicroscopySopClassHandler(params), getDicomEcgSopClassHandler(params)];
|
||||
}
|
||||
@@ -429,6 +429,40 @@ export default function getToolbarModule({ servicesManager, extensionManager }:
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'evaluate.cornerstoneTool.toggleWithModifier',
|
||||
evaluate: ({ viewportId, button, disabledText, toggledOnIcon, defaultIcon }) => {
|
||||
const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);
|
||||
if (!toolGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
const toolName = toolbarService.getToolNameForButton(button);
|
||||
if (!toolGroup.hasTool(toolName)) {
|
||||
return getDisabledState(disabledText);
|
||||
}
|
||||
|
||||
const { mode } = toolGroup.getToolOptions(toolName) ?? {};
|
||||
const isToggled =
|
||||
mode === Enums.ToolModes.Passive ||
|
||||
mode === Enums.ToolModes.Active ||
|
||||
mode === Enums.ToolModes.Enabled;
|
||||
|
||||
const toolBindings = toolGroupService.getToolBindings(toolGroup.id, toolName);
|
||||
const hasModifierKey =
|
||||
toolBindings?.some(binding => binding.modifierKey != null) ?? false;
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
isActive: false,
|
||||
isToggled,
|
||||
icon:
|
||||
isToggled && hasModifierKey && toggledOnIcon
|
||||
? toggledOnIcon
|
||||
: defaultIcon ?? button.props.icon,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'evaluate.action',
|
||||
evaluate: () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useSystem } from '@ohif/core/src';
|
||||
import { useViewportDisplaySets } from './useViewportDisplaySets';
|
||||
import { BaseVolumeViewport } from '@cornerstonejs/core';
|
||||
import { isVolumeViewportType } from '../utils/getLegacyViewportType';
|
||||
|
||||
/**
|
||||
* Hook that provides measurement tracking information for a viewport
|
||||
@@ -54,7 +54,7 @@ export function useMeasurementTracking({ viewportId }: { viewportId: string }) {
|
||||
const viewport = cornerstoneViewportService?.getCornerstoneViewport(viewportId);
|
||||
const SeriesInstanceUID = backgroundDisplaySet.SeriesInstanceUID;
|
||||
|
||||
if (viewport instanceof BaseVolumeViewport) {
|
||||
if (isVolumeViewportType(viewport)) {
|
||||
const currentImageId = viewport?.getCurrentImageId();
|
||||
|
||||
if (!currentImageId) {
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import React, { useCallback, useState, useEffect, useMemo } from 'react';
|
||||
import { useSystem } from '@ohif/core';
|
||||
import { useViewportDisplaySets } from './useViewportDisplaySets';
|
||||
import { Types, utilities, Enums, cache } from '@cornerstonejs/core';
|
||||
import { getDataIdForViewport } from '../utils/getDataIdForViewport';
|
||||
import {
|
||||
StackViewport,
|
||||
Types,
|
||||
VolumeViewport3D,
|
||||
utilities,
|
||||
Enums,
|
||||
BaseVolumeViewport,
|
||||
cache,
|
||||
} from '@cornerstonejs/core';
|
||||
isStackViewportType,
|
||||
isVolumeViewportType,
|
||||
isVolume3DViewportType,
|
||||
} from '../utils/getLegacyViewportType';
|
||||
import { WindowLevelPreset } from '../types/WindowLevel';
|
||||
import { ColorbarPositionType, ColorbarOptions, ColorbarProperties } from '../types/Colorbar';
|
||||
import { VolumeRenderingConfig } from '../types/VolumeRenderingConfig';
|
||||
@@ -104,11 +102,6 @@ const opacityToLinear = (opacityValue: number): number => {
|
||||
return Math.pow(opacityValue, 1.0 / GAMMA);
|
||||
};
|
||||
|
||||
const is3DViewport = ({ viewportId, cornerstoneViewportService }) => {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
return viewport instanceof VolumeViewport3D;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to access window level functionality for a specific viewport
|
||||
*
|
||||
@@ -124,15 +117,17 @@ export function useViewportRendering(
|
||||
const { cornerstoneViewportService, colorbarService, customizationService } =
|
||||
servicesManager.services;
|
||||
|
||||
const [is3DVolume, setIs3DVolume] = useState(
|
||||
is3DViewport({ viewportId, cornerstoneViewportService })
|
||||
);
|
||||
const [hasColorbar, setHasColorbar] = useState(colorbarService.hasColorbar(viewportId));
|
||||
const [colorbarPosition, setColorbarPosition] = useState<ColorbarPositionType>(
|
||||
options?.location ? getPosition(options.location) : 'bottom'
|
||||
);
|
||||
const [voiRange, setVoiRange] = useState<{ lower: number; upper: number } | undefined>();
|
||||
const voiRangeRef = React.useRef<{ lower: number; upper: number } | undefined>();
|
||||
// Viewport from service; kept in state so we can subscribe to VIEWPORT_DATA_CHANGED when null and re-run effects when it becomes available
|
||||
const [viewport, setViewport] = useState<Types.IViewport | null>(() =>
|
||||
viewportId ? (cornerstoneViewportService.getCornerstoneViewport(viewportId) ?? null) : null
|
||||
);
|
||||
const [is3DVolume, setIs3DVolume] = useState(isVolume3DViewportType(viewport));
|
||||
const [opacity, setOpacityState] = useState<number | undefined>();
|
||||
const [opacityLinear, setOpacityLinearState] = useState<number | undefined>();
|
||||
const [threshold, setThresholdState] = useState<number | undefined>();
|
||||
@@ -178,6 +173,34 @@ export function useViewportRendering(
|
||||
);
|
||||
}, [viewportDisplaySets, presets]);
|
||||
|
||||
// Keep viewport in state; when not available, subscribe to VIEWPORT_DATA_CHANGED so we set it when the viewport is ready
|
||||
useEffect(() => {
|
||||
if (!viewportId) {
|
||||
setViewport(null);
|
||||
return;
|
||||
}
|
||||
const vp = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
setViewport(vp ?? null);
|
||||
if (vp) {
|
||||
return;
|
||||
}
|
||||
const { unsubscribe } = cornerstoneViewportService.subscribe(
|
||||
cornerstoneViewportService.EVENTS.VIEWPORT_DATA_CHANGED,
|
||||
({ viewportId: eventViewportId }) => {
|
||||
if (eventViewportId !== viewportId) {
|
||||
return;
|
||||
}
|
||||
const next = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
if (next) {
|
||||
setViewport(next);
|
||||
}
|
||||
}
|
||||
);
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, [viewportId, cornerstoneViewportService]);
|
||||
|
||||
// Calculate pixel value range for the active display set
|
||||
useEffect(() => {
|
||||
if (!activeDisplaySetInstanceUID) {
|
||||
@@ -189,17 +212,15 @@ export function useViewportRendering(
|
||||
return;
|
||||
}
|
||||
|
||||
const csViewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
|
||||
if (!csViewport) {
|
||||
if (!viewport) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(csViewport instanceof BaseVolumeViewport)) {
|
||||
if (!isVolumeViewportType(viewport)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const volumeIds = csViewport.getAllVolumeIds();
|
||||
const volumeIds = viewport.getAllVolumeIds();
|
||||
const volumeId = volumeIds.find(id => id.includes(activeDisplaySetInstanceUID));
|
||||
|
||||
if (!volumeId) {
|
||||
@@ -207,7 +228,7 @@ export function useViewportRendering(
|
||||
}
|
||||
|
||||
// only handle volume viewports for now
|
||||
const imageData = csViewport.getImageData(volumeId);
|
||||
const imageData = viewport.getImageData(volumeId);
|
||||
|
||||
if (!imageData) {
|
||||
return;
|
||||
@@ -220,7 +241,7 @@ export function useViewportRendering(
|
||||
const range = voxelManager.getRange();
|
||||
|
||||
setPixelValueRange({ min: range[0], max: range[1] });
|
||||
}, [activeDisplaySetInstanceUID, displaySetService, cornerstoneViewportService, viewportId]);
|
||||
}, [activeDisplaySetInstanceUID, displaySetService, viewport]);
|
||||
|
||||
// Get the presets specifically for the active display set
|
||||
const activeDisplaySetPresets = useMemo(() => {
|
||||
@@ -240,55 +261,47 @@ export function useViewportRendering(
|
||||
}, [allWindowLevelPresets, activeDisplaySetInstanceUID]);
|
||||
|
||||
useEffect(() => {
|
||||
setIs3DVolume(is3DViewport({ viewportId, cornerstoneViewportService }));
|
||||
setIs3DVolume(isVolume3DViewportType(viewport));
|
||||
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
|
||||
// Initialize the VOI range from the viewport
|
||||
if (viewport && activeDisplaySetInstanceUID) {
|
||||
try {
|
||||
let properties;
|
||||
|
||||
if (viewport instanceof StackViewport) {
|
||||
properties = viewport.getProperties();
|
||||
if (properties.voiRange) {
|
||||
setVoiRange(properties.voiRange);
|
||||
voiRangeRef.current = properties.voiRange;
|
||||
}
|
||||
} else if (viewport instanceof BaseVolumeViewport) {
|
||||
// For volume viewports, find the actor for the active display set
|
||||
const volumeIds = viewport.getAllVolumeIds();
|
||||
const volumeId = volumeIds.find(id => id.includes(activeDisplaySetInstanceUID));
|
||||
|
||||
if (volumeId) {
|
||||
properties = viewport.getProperties(volumeId);
|
||||
if (properties?.voiRange) {
|
||||
setVoiRange(properties.voiRange);
|
||||
voiRangeRef.current = properties.voiRange;
|
||||
}
|
||||
|
||||
// Get opacity from colormap if available
|
||||
if (properties?.colormap?.opacity !== undefined) {
|
||||
const isArray = Array.isArray(properties.colormap.opacity);
|
||||
const opacity = isArray
|
||||
? properties.colormap.opacity.reduce((max, current) => Math.max(max, current), 0)
|
||||
: properties.colormap.opacity;
|
||||
|
||||
setOpacityState(opacity);
|
||||
setOpacityLinearState(opacityToLinear(opacity));
|
||||
}
|
||||
|
||||
// Get threshold from colormap if available
|
||||
if (properties?.colormap && properties.colormap.threshold !== undefined) {
|
||||
setThresholdState(properties.colormap.threshold);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error initializing VOI range:', error);
|
||||
}
|
||||
if (!viewport || !activeDisplaySetInstanceUID) {
|
||||
return;
|
||||
}
|
||||
}, [cornerstoneViewportService, viewportId, activeDisplaySetInstanceUID]);
|
||||
try {
|
||||
const dataId = getDataIdForViewport(viewport as unknown, activeDisplaySetInstanceUID);
|
||||
|
||||
const properties =
|
||||
dataId != null
|
||||
? (viewport as Types.IBaseVolumeViewport).getProperties(dataId)
|
||||
: viewport.getProperties();
|
||||
|
||||
if (!properties) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (properties.voiRange) {
|
||||
setVoiRange(properties.voiRange);
|
||||
voiRangeRef.current = properties.voiRange;
|
||||
}
|
||||
|
||||
if (properties.colormap?.opacity !== undefined) {
|
||||
const opacityVal = properties.colormap.opacity;
|
||||
const opacity = Array.isArray(opacityVal)
|
||||
? (opacityVal as unknown as number[]).reduce(
|
||||
(max, current) => Math.max(max, current),
|
||||
0
|
||||
)
|
||||
: opacityVal;
|
||||
setOpacityState(opacity);
|
||||
setOpacityLinearState(opacityToLinear(opacity));
|
||||
}
|
||||
|
||||
if (properties.colormap?.threshold !== undefined) {
|
||||
setThresholdState(properties.colormap.threshold);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error initializing VOI range:', error);
|
||||
}
|
||||
}, [activeDisplaySetInstanceUID, viewport]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!viewportId) {
|
||||
@@ -313,19 +326,11 @@ export function useViewportRendering(
|
||||
}, [colorbarService, viewportId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!viewportId || !activeDisplaySetInstanceUID) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
if (!viewport) {
|
||||
if (!activeDisplaySetInstanceUID || !viewport?.element) {
|
||||
return;
|
||||
}
|
||||
|
||||
const element = viewport.element;
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updateVOI = eventDetail => {
|
||||
const { range } = eventDetail.detail;
|
||||
@@ -369,7 +374,7 @@ export function useViewportRendering(
|
||||
element.removeEventListener(Enums.Events.VOI_MODIFIED, updateVOI);
|
||||
element.removeEventListener(Enums.Events.COLORMAP_MODIFIED, updateColormap);
|
||||
};
|
||||
}, [viewportId, activeDisplaySetInstanceUID, cornerstoneViewportService, opacityToLinear]);
|
||||
}, [activeDisplaySetInstanceUID, viewport, opacityToLinear]);
|
||||
|
||||
const validateActiveDisplaySet = useCallback(() => {
|
||||
if (!activeDisplaySetInstanceUID) {
|
||||
@@ -560,17 +565,12 @@ export function useViewportRendering(
|
||||
context: 'CORNERSTONE',
|
||||
});
|
||||
},
|
||||
[commandsManager, viewportId, validateActiveDisplaySet]
|
||||
[commandsManager, validateActiveDisplaySet, viewport, viewportId]
|
||||
);
|
||||
|
||||
const setOpacity = useCallback(
|
||||
(opacityValue: number) => {
|
||||
if (!viewportId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
if (!viewport || !(viewport instanceof BaseVolumeViewport)) {
|
||||
if (!viewport || !isVolumeViewportType(viewport)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -607,7 +607,7 @@ export function useViewportRendering(
|
||||
|
||||
viewport.render();
|
||||
},
|
||||
[cornerstoneViewportService, viewportId, validateActiveDisplaySet, opacityToLinear]
|
||||
[validateActiveDisplaySet, opacityToLinear, viewport]
|
||||
);
|
||||
|
||||
const setOpacityLinear = useCallback(
|
||||
@@ -621,12 +621,7 @@ export function useViewportRendering(
|
||||
|
||||
const setThreshold = useCallback(
|
||||
(thresholdValue: number) => {
|
||||
if (!viewportId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
if (!viewport || !(viewport instanceof BaseVolumeViewport)) {
|
||||
if (!viewport || !isVolumeViewportType(viewport)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -653,23 +648,21 @@ export function useViewportRendering(
|
||||
|
||||
viewport.render();
|
||||
},
|
||||
[cornerstoneViewportService, viewportId, validateActiveDisplaySet]
|
||||
[validateActiveDisplaySet, viewport]
|
||||
);
|
||||
|
||||
// Get the current colormap for the active display set
|
||||
const colormap = useMemo(() => {
|
||||
if (!viewportId || !activeDisplaySetInstanceUID || !viewportDisplaySets?.length) {
|
||||
if (!activeDisplaySetInstanceUID || !viewportDisplaySets?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
|
||||
|
||||
if (!viewport) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (viewport instanceof StackViewport) {
|
||||
if (isStackViewportType(viewport)) {
|
||||
const { colormap } = viewport.getProperties();
|
||||
if (!colormap) {
|
||||
return (
|
||||
@@ -711,13 +704,7 @@ export function useViewportRendering(
|
||||
colorbarProperties?.colormaps?.[0]
|
||||
);
|
||||
}
|
||||
}, [
|
||||
cornerstoneViewportService,
|
||||
viewportId,
|
||||
activeDisplaySetInstanceUID,
|
||||
viewportDisplaySets,
|
||||
colorbarProperties?.colormaps,
|
||||
]);
|
||||
}, [activeDisplaySetInstanceUID, viewportDisplaySets, colorbarProperties?.colormaps, viewport]);
|
||||
|
||||
// 3D volume rendering functions
|
||||
const setVolumeRenderingPreset = useCallback(
|
||||
@@ -801,7 +788,9 @@ export function useViewportRendering(
|
||||
setWindowLevel,
|
||||
setVOIRange,
|
||||
voiRange,
|
||||
windowLevel: utilities.windowLevel.toWindowLevel(voiRange?.lower, voiRange?.upper),
|
||||
windowLevel: voiRange
|
||||
? utilities.windowLevel.toWindowLevel(voiRange?.lower, voiRange?.upper)
|
||||
: { windowCenter: null, windowWidth: null },
|
||||
|
||||
// Colorbar functions
|
||||
hasColorbar,
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useSystem } from '@ohif/core';
|
||||
const excludedModalities = ['SM', 'OT', 'DOC', 'ECG'];
|
||||
|
||||
function mapSegmentationToDisplay(segmentation, customizationService) {
|
||||
const { label, segments } = segmentation;
|
||||
const { label, segments, fallbackLabel } = segmentation;
|
||||
|
||||
// Get the readable text mapping once
|
||||
const readableTextMap = customizationService.getCustomization('panelSegmentation.readableText');
|
||||
@@ -76,6 +76,7 @@ function mapSegmentationToDisplay(segmentation, customizationService) {
|
||||
return {
|
||||
...segmentation,
|
||||
label,
|
||||
fallbackLabel,
|
||||
segments: updatedSegments,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -20,6 +20,34 @@ export const HYDRATE_SEG_SYNC_GROUP = {
|
||||
},
|
||||
};
|
||||
|
||||
const viewportStructure = {
|
||||
layoutType: 'grid',
|
||||
properties: {
|
||||
rows: 1,
|
||||
columns: 3,
|
||||
layoutOptions: [
|
||||
{
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 1 / 3,
|
||||
height: 1,
|
||||
},
|
||||
{
|
||||
x: 1 / 3,
|
||||
y: 0,
|
||||
width: 1 / 3,
|
||||
height: 1,
|
||||
},
|
||||
{
|
||||
x: 2 / 3,
|
||||
y: 0,
|
||||
width: 1 / 3,
|
||||
height: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const mpr: Types.HangingProtocol.Protocol = {
|
||||
id: 'mpr',
|
||||
name: i18n.t('Hps:MPR'),
|
||||
@@ -53,33 +81,7 @@ export const mpr: Types.HangingProtocol.Protocol = {
|
||||
stages: [
|
||||
{
|
||||
name: 'MPR 1x3',
|
||||
viewportStructure: {
|
||||
layoutType: 'grid',
|
||||
properties: {
|
||||
rows: 1,
|
||||
columns: 3,
|
||||
layoutOptions: [
|
||||
{
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 1 / 3,
|
||||
height: 1,
|
||||
},
|
||||
{
|
||||
x: 1 / 3,
|
||||
y: 0,
|
||||
width: 1 / 3,
|
||||
height: 1,
|
||||
},
|
||||
{
|
||||
x: 2 / 3,
|
||||
y: 0,
|
||||
width: 1 / 3,
|
||||
height: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
viewportStructure,
|
||||
viewports: [
|
||||
{
|
||||
viewportOptions: {
|
||||
@@ -134,5 +136,63 @@ export const mpr: Types.HangingProtocol.Protocol = {
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
name: 'MPR Reformat 1x3',
|
||||
viewportStructure,
|
||||
viewports: [
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'mpr-axial',
|
||||
toolGroupId: 'mpr',
|
||||
viewportType: 'volume',
|
||||
orientation: 'axial_reformat',
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
id: 'activeDisplaySet',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'mpr-sagittal',
|
||||
toolGroupId: 'mpr',
|
||||
viewportType: 'volume',
|
||||
orientation: 'sagittal_reformat',
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
id: 'activeDisplaySet',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
viewportOptions: {
|
||||
viewportId: 'mpr-coronal',
|
||||
toolGroupId: 'mpr',
|
||||
viewportType: 'volume',
|
||||
orientation: 'coronal_reformat',
|
||||
initialImageOptions: {
|
||||
preset: 'middle',
|
||||
},
|
||||
syncGroups: [VOI_SYNC_GROUP, HYDRATE_SEG_SYNC_GROUP],
|
||||
},
|
||||
displaySets: [
|
||||
{
|
||||
id: 'activeDisplaySet',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -21,6 +21,7 @@ import SegmentationService from './services/SegmentationService';
|
||||
import CornerstoneCacheService from './services/CornerstoneCacheService';
|
||||
import CornerstoneViewportService from './services/ViewportService/CornerstoneViewportService';
|
||||
import ColorbarService from './services/ColorbarService';
|
||||
import ViewedDataService from './services/ViewedDataService';
|
||||
import * as CornerstoneExtensionTypes from './types';
|
||||
|
||||
import { toolNames } from './initCornerstoneTools';
|
||||
@@ -180,6 +181,7 @@ const cornerstoneExtension: Types.Extensions.Extension = {
|
||||
useSelectedSegmentationsForViewportStore
|
||||
.getState()
|
||||
.clearSelectedSegmentationsForViewportStore();
|
||||
servicesManager.services.viewedDataService?.clearViewedData();
|
||||
segmentationService.removeAllSegmentations();
|
||||
},
|
||||
|
||||
@@ -196,6 +198,7 @@ const cornerstoneExtension: Types.Extensions.Extension = {
|
||||
servicesManager.registerService(SegmentationService.REGISTRATION);
|
||||
servicesManager.registerService(CornerstoneCacheService.REGISTRATION);
|
||||
servicesManager.registerService(ColorbarService.REGISTRATION);
|
||||
servicesManager.registerService(ViewedDataService.REGISTRATION);
|
||||
|
||||
const { syncGroupService } = servicesManager.services;
|
||||
syncGroupService.registerCustomSynchronizer('frameview', createFrameViewSynchronizer);
|
||||
|
||||
@@ -74,6 +74,10 @@ export default async function init({
|
||||
rendering: {
|
||||
...cornerstone.getConfiguration().rendering,
|
||||
strictZSpacingForVolumeViewport: appConfig.strictZSpacingForVolumeViewport,
|
||||
// Opt-in: route legacy viewport types through the new GenericViewport render
|
||||
// paths while keeping the legacy public API via compatibility adapters.
|
||||
// No-op on cornerstone builds that predate the GenericViewport architecture.
|
||||
useGenericViewport: Boolean(appConfig.useGenericViewport),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -178,14 +182,6 @@ export default async function init({
|
||||
);
|
||||
});
|
||||
|
||||
// add metadata providers
|
||||
metaData.addProvider(
|
||||
csUtilities.calibratedPixelSpacingMetadataProvider.get.bind(
|
||||
csUtilities.calibratedPixelSpacingMetadataProvider
|
||||
)
|
||||
); // this provider is required for Calibration tool
|
||||
metaData.addProvider(metadataProvider.get.bind(metadataProvider), 9999);
|
||||
|
||||
// These are set reasonably low to allow for interleaved retrieves and slower
|
||||
// connections.
|
||||
imageLoadPoolManager.maxNumRequests = {
|
||||
@@ -197,6 +193,16 @@ export default async function init({
|
||||
|
||||
initWADOImageLoader(userAuthenticationService, appConfig, extensionManager);
|
||||
|
||||
// Add OHIF metadata providers after dicomImageLoader.init().
|
||||
// The linked metadata branch clears providers during loader init.
|
||||
metaData.addProvider(csUtilities.genericMetadataProvider.get, 9998);
|
||||
metaData.addProvider(
|
||||
csUtilities.calibratedPixelSpacingMetadataProvider.get.bind(
|
||||
csUtilities.calibratedPixelSpacingMetadataProvider
|
||||
)
|
||||
); // this provider is required for Calibration tool
|
||||
metaData.addProvider(metadataProvider.get.bind(metadataProvider), 9999);
|
||||
|
||||
/* Measurement Service */
|
||||
this.measurementServiceSource = connectToolsToMeasurementService({
|
||||
servicesManager,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { eventTarget, Types } from '@cornerstonejs/core';
|
||||
import { Enums, annotation } from '@cornerstonejs/tools';
|
||||
import { eventTarget, Types, utilities as csUtils } from '@cornerstonejs/core';
|
||||
import { Enums, annotation, cancelActiveManipulations } from '@cornerstonejs/tools';
|
||||
import { DicomMetadataStore } from '@ohif/core';
|
||||
|
||||
import * as CSExtensionEnums from './enums';
|
||||
@@ -17,6 +17,8 @@ const { CORNERSTONE_3D_TOOLS_SOURCE_NAME, CORNERSTONE_3D_TOOLS_SOURCE_VERSION }
|
||||
const { removeAnnotation } = annotation.state;
|
||||
const csToolsEvents = Enums.Events;
|
||||
|
||||
const { DefaultHistoryMemo } = csUtils.HistoryMemo;
|
||||
|
||||
const initMeasurementService = (
|
||||
measurementService,
|
||||
displaySetService,
|
||||
@@ -354,7 +356,7 @@ const connectMeasurementServiceToTools = ({
|
||||
const { MEASUREMENT_REMOVED, MEASUREMENTS_CLEARED, MEASUREMENT_UPDATED, RAW_MEASUREMENT_ADDED } =
|
||||
measurementService.EVENTS;
|
||||
|
||||
measurementService.subscribe(MEASUREMENTS_CLEARED, ({ measurements }) => {
|
||||
measurementService.subscribe(MEASUREMENTS_CLEARED, ({ measurements, trackingContext }) => {
|
||||
if (!Object.keys(measurements).length) {
|
||||
return;
|
||||
}
|
||||
@@ -373,6 +375,29 @@ const connectMeasurementServiceToTools = ({
|
||||
options: { deleting: true },
|
||||
});
|
||||
}
|
||||
|
||||
// If tracking context was provided, push a memo that keeps XState in sync with
|
||||
// Cornerstone's annotation history across unlimited undo/redo cycles:
|
||||
// undo → re-populate trackedStudy/trackedSeries so the panel reflects the
|
||||
// restored annotations.
|
||||
// redo → wipe trackedStudy/trackedSeries because the annotations have been
|
||||
// re-deleted by their own Cornerstone memos; no measurements are
|
||||
// deleted here (they are already gone), so CLEAR_TRACKING_CONTEXT is
|
||||
// used instead of UNTRACK_ALL to avoid a double-delete.
|
||||
if (trackingContext) {
|
||||
DefaultHistoryMemo.push({
|
||||
id: csUtils.uuidv4(),
|
||||
operationType: 'trackingState',
|
||||
restoreMemo(undo?: boolean) {
|
||||
if (undo === true) {
|
||||
commandsManager.run('restoreTrackedSeries', trackingContext);
|
||||
} else if (undo === false) {
|
||||
commandsManager.run('clearTrackedSeries');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
commandsManager.run('endRecordingForAnnotationGroup');
|
||||
|
||||
// trigger a render
|
||||
@@ -504,6 +529,12 @@ const connectMeasurementServiceToTools = ({
|
||||
if (source?.name && source.name !== CORNERSTONE_3D_TOOLS_SOURCE_NAME) {
|
||||
return;
|
||||
}
|
||||
// Cancel any active tool manipulation (e.g., Spline/Livewire) to avoid leaving the tool
|
||||
// in a drawing state after deleting a not completed measurement, which can block viewport interactivity.
|
||||
const element = getActiveViewportEnabledElement(viewportGridService)?.viewport?.element;
|
||||
if (element) {
|
||||
cancelActiveManipulations(element);
|
||||
}
|
||||
const removedAnnotation = annotation.state.getAnnotation(removedMeasurementId);
|
||||
removeAnnotation(removedMeasurementId);
|
||||
// Ensure `removedAnnotation` is available before triggering the memo,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { PubSubService, Types as OhifTypes } from '@ohif/core';
|
||||
import { RENDERING_ENGINE_ID } from '../ViewportService/constants';
|
||||
import { getRenderingEngine } from '@cornerstonejs/core';
|
||||
import { getDataIdForViewport } from '../../utils/getDataIdForViewport';
|
||||
import { ColorbarOptions, ChangeTypes } from '../../types/Colorbar';
|
||||
|
||||
export default class ColorbarService extends PubSubService {
|
||||
@@ -38,25 +39,6 @@ export default class ColorbarService extends PubSubService {
|
||||
this.servicesManager = servicesManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the appropriate data ID for a viewport and display set
|
||||
* @param viewport - The viewport instance
|
||||
* @param displaySetInstanceUID - The display set instance UID to identify data
|
||||
* @returns The appropriate data ID for the viewport type (volumeId for volume viewports, undefined for stack)
|
||||
*/
|
||||
private getDataIdForViewport(viewport, displaySetInstanceUID: string): string | undefined {
|
||||
// For volume viewports, find the matching volumeId
|
||||
if (viewport.getAllVolumeIds) {
|
||||
const volumeIds = viewport.getAllVolumeIds() || [];
|
||||
return volumeIds.length > 0
|
||||
? volumeIds.find(id => id.includes(displaySetInstanceUID)) || undefined
|
||||
: undefined;
|
||||
}
|
||||
|
||||
// For other viewports, no specific dataId is needed for now
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a colorbar to a specific viewport identified by `viewportId`, using the provided `displaySetInstanceUIDs` and `options`.
|
||||
* This method prepares the colorbar state that will be used by the ViewportColorbarsContainer component.
|
||||
@@ -92,7 +74,7 @@ export default class ColorbarService extends PubSubService {
|
||||
return;
|
||||
}
|
||||
|
||||
const dataId = this.getDataIdForViewport(viewport, displaySetInstanceUID);
|
||||
const dataId = getDataIdForViewport(viewport, displaySetInstanceUID);
|
||||
const properties = dataId ? viewport.getProperties(dataId) : viewport.getProperties();
|
||||
const colormap = properties?.colormap;
|
||||
|
||||
@@ -246,7 +228,7 @@ export default class ColorbarService extends PubSubService {
|
||||
}
|
||||
|
||||
// Get the appropriate dataId for this viewport/displaySet combination
|
||||
const dataId = this.getDataIdForViewport(viewport, displaySetInstanceUID);
|
||||
const dataId = getDataIdForViewport(viewport, displaySetInstanceUID);
|
||||
|
||||
// Set properties with or without dataId based on what the viewport supports
|
||||
viewport.setProperties({ colormap }, dataId);
|
||||
|
||||
+15
-6
@@ -1120,6 +1120,7 @@ describe('SegmentationService', () => {
|
||||
isDynamicVolume: false,
|
||||
SeriesNumber: 1,
|
||||
SeriesDescription: 'Series Description',
|
||||
Modality: 'SEG',
|
||||
} as unknown as AppTypes.DisplaySet;
|
||||
|
||||
jest
|
||||
@@ -1145,6 +1146,7 @@ describe('SegmentationService', () => {
|
||||
info: 'S1: Series Description',
|
||||
},
|
||||
label: 'Segmentation 2',
|
||||
fallbackLabel: 'S:1 SEG',
|
||||
segments: {
|
||||
'1': {
|
||||
active: true,
|
||||
@@ -1175,6 +1177,7 @@ describe('SegmentationService', () => {
|
||||
dynamicVolumeInfo: {
|
||||
timePoints: ['timePoint1', 'timePoint2', 'timePoint3'],
|
||||
},
|
||||
Modality: 'SEG',
|
||||
} as unknown as AppTypes.DisplaySet;
|
||||
|
||||
jest
|
||||
@@ -1212,6 +1215,7 @@ describe('SegmentationService', () => {
|
||||
info: 'S1: Series Description',
|
||||
},
|
||||
label: 'Segmentation 2',
|
||||
fallbackLabel: 'S:1 SEG',
|
||||
segments: {
|
||||
'1': {
|
||||
active: true,
|
||||
@@ -1320,6 +1324,8 @@ describe('SegmentationService', () => {
|
||||
},
|
||||
SeriesDate: '2025-01-01',
|
||||
SeriesDescription: 'Series Description',
|
||||
Modality: 'SEG',
|
||||
SeriesNumber: 1,
|
||||
};
|
||||
|
||||
const referencedDisplaySet = {
|
||||
@@ -1379,6 +1385,7 @@ describe('SegmentationService', () => {
|
||||
const expectedSegmentation = {
|
||||
config: {
|
||||
label: segDisplaySet.SeriesDescription,
|
||||
fallbackLabel: 'S:1 SEG',
|
||||
segments: {
|
||||
'1': {
|
||||
active: false,
|
||||
@@ -1534,7 +1541,7 @@ describe('SegmentationService', () => {
|
||||
it('should create a segmentation for a RTSTRUCT display set', async () => {
|
||||
const segmentationId = 'segmentationId';
|
||||
const rtStructDisplaySet = {
|
||||
modality: 'RTSTRUCT',
|
||||
Modality: 'RTSTRUCT',
|
||||
displaySetInstanceUID: 'display-set-uid',
|
||||
referencedDisplaySetInstanceUID: 'existent-display-set-uid',
|
||||
SeriesDate: '2025-01-01',
|
||||
@@ -1544,6 +1551,7 @@ describe('SegmentationService', () => {
|
||||
ROIContours: [{}, {}, {}],
|
||||
frameOfReferenceUID: 'frameOfReferenceUID',
|
||||
},
|
||||
SeriesNumber: 1,
|
||||
};
|
||||
|
||||
const referencedDisplaySet = {
|
||||
@@ -1650,6 +1658,7 @@ describe('SegmentationService', () => {
|
||||
const expectedSegmentation = {
|
||||
config: {
|
||||
label: rtStructDisplaySet.SeriesDescription,
|
||||
fallbackLabel: 'S:1 RTSTRUCT',
|
||||
segments: {
|
||||
'1': {
|
||||
active: false,
|
||||
@@ -2567,12 +2576,12 @@ describe('SegmentationService', () => {
|
||||
describe('clearSegmentationRepresentations', () => {
|
||||
it('should clear the segmentation representations', () => {
|
||||
const viewportId = 'viewportId';
|
||||
jest.spyOn(service, 'removeSegmentationRepresentations').mockReturnValue(undefined);
|
||||
jest.spyOn(service, 'removeRepresentationsFromViewport').mockReturnValue(undefined);
|
||||
|
||||
service.clearSegmentationRepresentations(viewportId);
|
||||
|
||||
expect(service.removeSegmentationRepresentations).toHaveBeenCalledTimes(1);
|
||||
expect(service.removeSegmentationRepresentations).toHaveBeenCalledWith(viewportId);
|
||||
expect(service.removeRepresentationsFromViewport).toHaveBeenCalledTimes(1);
|
||||
expect(service.removeRepresentationsFromViewport).toHaveBeenCalledWith(viewportId);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2600,7 +2609,7 @@ describe('SegmentationService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeSegmentationRepresentations', () => {
|
||||
describe('removeRepresentationsFromViewport', () => {
|
||||
it('should remove the segmentation representations', () => {
|
||||
const viewportId = 'viewportId';
|
||||
const specifier = {
|
||||
@@ -2609,7 +2618,7 @@ describe('SegmentationService', () => {
|
||||
};
|
||||
jest.spyOn(cstSegmentation, 'removeSegmentationRepresentations').mockReturnValue(undefined);
|
||||
|
||||
service.removeSegmentationRepresentations(viewportId, specifier);
|
||||
service.removeRepresentationsFromViewport(viewportId, specifier);
|
||||
|
||||
expect(cstSegmentation.removeSegmentationRepresentations).toHaveBeenCalledTimes(1);
|
||||
expect(cstSegmentation.removeSegmentationRepresentations).toHaveBeenCalledWith(
|
||||
|
||||
@@ -10,6 +10,10 @@ import {
|
||||
metaData,
|
||||
} from '@cornerstonejs/core';
|
||||
import { ViewportType } from '@cornerstonejs/core/enums';
|
||||
import {
|
||||
isVolume3DViewportType,
|
||||
isVolumeViewportType,
|
||||
} from '../../utils/getLegacyViewportType';
|
||||
|
||||
import {
|
||||
Enums as csToolsEnums,
|
||||
@@ -55,6 +59,7 @@ export type SegmentationRepresentation = cstTypes.SegmentationRepresentation & {
|
||||
viewportId: string;
|
||||
id: string;
|
||||
label: string;
|
||||
fallbackLabel?: string;
|
||||
styles: cstTypes.RepresentationStyle;
|
||||
segments: {
|
||||
[key: number]: SegmentRepresentation;
|
||||
@@ -247,7 +252,7 @@ class SegmentationService extends PubSubService {
|
||||
|
||||
eventTarget.removeEventListener(
|
||||
csToolsEnums.Events.SEGMENTATION_REMOVED,
|
||||
this._onSegmentationModifiedFromSource
|
||||
this._onSegmentationRemovedFromSource
|
||||
);
|
||||
|
||||
eventTarget.removeEventListener(
|
||||
@@ -267,7 +272,7 @@ class SegmentationService extends PubSubService {
|
||||
|
||||
eventTarget.removeEventListener(
|
||||
csToolsEnums.Events.SEGMENTATION_REPRESENTATION_REMOVED,
|
||||
this._onSegmentationRepresentationModifiedFromSource
|
||||
this._onSegmentationRepresentationRemovedFromSource
|
||||
);
|
||||
|
||||
eventTarget.removeEventListener(
|
||||
@@ -311,7 +316,7 @@ class SegmentationService extends PubSubService {
|
||||
let isConverted = false;
|
||||
|
||||
const defaultRepresentationType: csToolsEnums.SegmentationRepresentations =
|
||||
csViewport.type === ViewportType.VOLUME_3D ? SURFACE : LABELMAP;
|
||||
isVolume3DViewportType(csViewport) ? SURFACE : LABELMAP;
|
||||
let representationTypeToUse = type || defaultRepresentationType;
|
||||
|
||||
if (representationTypeToUse === LABELMAP) {
|
||||
@@ -430,6 +435,7 @@ class SegmentationService extends PubSubService {
|
||||
},
|
||||
config: {
|
||||
label,
|
||||
fallbackLabel: `S:${displaySet.SeriesNumber} ${displaySet.Modality}`,
|
||||
segments:
|
||||
options?.segments && Object.keys(options.segments).length > 0
|
||||
? options.segments
|
||||
@@ -583,6 +589,7 @@ class SegmentationService extends PubSubService {
|
||||
},
|
||||
config: {
|
||||
label: segDisplaySet.SeriesDescription,
|
||||
fallbackLabel: `S:${segDisplaySet.SeriesNumber} ${segDisplaySet.Modality}`,
|
||||
segments,
|
||||
},
|
||||
};
|
||||
@@ -664,6 +671,7 @@ class SegmentationService extends PubSubService {
|
||||
},
|
||||
config: {
|
||||
label: rtDisplaySet.SeriesDescription,
|
||||
fallbackLabel: `S:${rtDisplaySet.SeriesNumber} ${rtDisplaySet.Modality}`,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -892,6 +900,7 @@ class SegmentationService extends PubSubService {
|
||||
active?: boolean;
|
||||
color?: csTypes.Color; // Add color type
|
||||
visibility?: boolean; // Add visibility option
|
||||
cachedStats?: Record<string, unknown>;
|
||||
} = {}
|
||||
): void {
|
||||
if (config?.segmentIndex === 0) {
|
||||
@@ -1284,14 +1293,14 @@ class SegmentationService extends PubSubService {
|
||||
|
||||
/**
|
||||
* Clears segmentation representations from the viewport.
|
||||
* Unlike removeSegmentationRepresentations, this doesn't update
|
||||
* Unlike removeRepresentationsFromViewport, this doesn't update
|
||||
* removed display set and representation maps.
|
||||
* We track removed segmentations manually to avoid re-adding them
|
||||
* when the display set is added again.
|
||||
* @param viewportId - The viewport ID to clear segmentation representations from.
|
||||
*/
|
||||
public clearSegmentationRepresentations(viewportId: string): void {
|
||||
this.removeSegmentationRepresentations(viewportId);
|
||||
this.removeRepresentationsFromViewport(viewportId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1307,7 +1316,7 @@ class SegmentationService extends PubSubService {
|
||||
}
|
||||
|
||||
/**
|
||||
* It removes the segmentation representations from the viewport.
|
||||
* Removes segmentation representations from the viewport.
|
||||
* @param viewportId - The viewport id to remove the segmentation representations from.
|
||||
* @param specifier - The specifier to remove the segmentation representations.
|
||||
*
|
||||
@@ -1317,7 +1326,7 @@ class SegmentationService extends PubSubService {
|
||||
* If a type specifier is provided, only the segmentation representation with the specified type are removed.
|
||||
* If both a segmentationId and type specifier are provided, only the segmentation representation with the specified segmentationId and type are removed.
|
||||
*/
|
||||
public removeSegmentationRepresentations(
|
||||
public removeRepresentationsFromViewport(
|
||||
viewportId: string,
|
||||
specifier: {
|
||||
segmentationId?: string;
|
||||
@@ -1586,8 +1595,7 @@ class SegmentationService extends PubSubService {
|
||||
}
|
||||
|
||||
private determineViewportAndSegmentationType(csViewport, segmentation) {
|
||||
const isVolumeViewport =
|
||||
csViewport.type === ViewportType.ORTHOGRAPHIC || csViewport.type === ViewportType.VOLUME_3D;
|
||||
const isVolumeViewport = isVolumeViewportType(csViewport);
|
||||
const isVolumeSegmentation = 'volumeId' in segmentation.representationData[LABELMAP];
|
||||
return { isVolumeViewport, isVolumeSegmentation };
|
||||
}
|
||||
@@ -1618,7 +1626,7 @@ class SegmentationService extends PubSubService {
|
||||
}
|
||||
|
||||
private async handleVolumeViewportCase(csViewport, segmentation, isVolumeSegmentation) {
|
||||
if (csViewport.type === ViewportType.VOLUME_3D) {
|
||||
if (isVolume3DViewportType(csViewport)) {
|
||||
return {
|
||||
representationTypeToUse: SURFACE,
|
||||
isConverted: false,
|
||||
@@ -1842,6 +1850,7 @@ class SegmentationService extends PubSubService {
|
||||
id: id,
|
||||
segmentationId,
|
||||
label: segmentation.label,
|
||||
fallbackLabel: segmentation.fallbackLabel,
|
||||
active,
|
||||
type,
|
||||
visible,
|
||||
@@ -1861,7 +1870,7 @@ class SegmentationService extends PubSubService {
|
||||
|
||||
eventTarget.addEventListener(
|
||||
csToolsEnums.Events.SEGMENTATION_REMOVED,
|
||||
this._onSegmentationModifiedFromSource
|
||||
this._onSegmentationRemovedFromSource
|
||||
);
|
||||
|
||||
eventTarget.addEventListener(
|
||||
@@ -1881,7 +1890,7 @@ class SegmentationService extends PubSubService {
|
||||
|
||||
eventTarget.addEventListener(
|
||||
csToolsEnums.Events.SEGMENTATION_REPRESENTATION_REMOVED,
|
||||
this._onSegmentationRepresentationModifiedFromSource
|
||||
this._onSegmentationRepresentationRemovedFromSource
|
||||
);
|
||||
|
||||
eventTarget.addEventListener(
|
||||
@@ -2120,6 +2129,14 @@ class SegmentationService extends PubSubService {
|
||||
});
|
||||
};
|
||||
|
||||
private _onSegmentationRepresentationRemovedFromSource = evt => {
|
||||
const { segmentationId, viewportId } = evt.detail;
|
||||
this._broadcastEvent(this.EVENTS.SEGMENTATION_REPRESENTATION_REMOVED, {
|
||||
segmentationId,
|
||||
viewportId,
|
||||
});
|
||||
};
|
||||
|
||||
private _onSegmentationModifiedFromSource = (
|
||||
evt: cstTypes.EventTypes.SegmentationModifiedEventType
|
||||
) => {
|
||||
@@ -2140,6 +2157,16 @@ class SegmentationService extends PubSubService {
|
||||
});
|
||||
};
|
||||
|
||||
private _onSegmentationRemovedFromSource = (
|
||||
evt: cstTypes.EventTypes.SegmentationRemovedEventType
|
||||
) => {
|
||||
const { segmentationId } = evt.detail;
|
||||
|
||||
this._broadcastEvent(this.EVENTS.SEGMENTATION_REMOVED, {
|
||||
segmentationId,
|
||||
});
|
||||
};
|
||||
|
||||
private _onAnnotationCutMergeProcessCompletedFromSource = evt => {
|
||||
const { segmentationId } = evt.detail;
|
||||
this._broadcastEvent(this.EVENTS.SEGMENTATION_ANNOTATION_CUT_MERGE_PROCESS_COMPLETED, {
|
||||
|
||||
+11
-2
@@ -7,6 +7,7 @@ import {
|
||||
} from '@cornerstonejs/tools';
|
||||
|
||||
import { isAnyDisplaySetCommon } from '../../utils/isAnyDisplaySetCommon';
|
||||
import { isVolume3DViewportType } from '../../utils/getLegacyViewportType';
|
||||
|
||||
const { createSynchronizer } = SynchronizerManager;
|
||||
const { SEGMENTATION_REPRESENTATION_MODIFIED } = Enums.Events;
|
||||
@@ -66,7 +67,15 @@ const segmentationRepresentationModifiedCallback = async (
|
||||
|
||||
const sharedDisplaySetExists = isAnyDisplaySetCommon(sourceDisplaySetUIDs, targetDisplaySetUIDs);
|
||||
|
||||
if (!sharedDisplaySetExists && !viewport.getFrameOfReferenceUID()) {
|
||||
const targetFrameOfReferenceUID = viewport.getFrameOfReferenceUID();
|
||||
const sourceFrameOfReferenceUID =
|
||||
getEnabledElementByViewportId(sourceViewportId)?.viewport?.getFrameOfReferenceUID();
|
||||
|
||||
if (!sharedDisplaySetExists && !targetFrameOfReferenceUID) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sharedDisplaySetExists && targetFrameOfReferenceUID !== sourceFrameOfReferenceUID) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -81,7 +90,7 @@ const segmentationRepresentationModifiedCallback = async (
|
||||
|
||||
// Ensure the segmentation representation aligns with the target viewport type.
|
||||
const type: Enums.SegmentationRepresentations =
|
||||
viewport.type === CoreEnums.ViewportType.VOLUME_3D
|
||||
isVolume3DViewportType(viewport)
|
||||
? Enums.SegmentationRepresentations.Surface
|
||||
: ((segmentationRepresentationType as Enums.SegmentationRepresentations) ??
|
||||
Enums.SegmentationRepresentations.Labelmap);
|
||||
|
||||
@@ -23,6 +23,12 @@ type Tools = {
|
||||
disabled?: Tool[];
|
||||
};
|
||||
|
||||
type ToolBindings = Array<Record<string, unknown>>;
|
||||
type PersistedToolBindings = Record<string, Record<string, ToolBindings>>;
|
||||
type ApplyToolBindingsOptions = {
|
||||
replaceExisting?: boolean;
|
||||
};
|
||||
|
||||
export default class ToolGroupService {
|
||||
public static REGISTRATION = {
|
||||
name: 'toolGroupService',
|
||||
@@ -36,7 +42,10 @@ export default class ToolGroupService {
|
||||
cornerstoneViewportService: any;
|
||||
viewportGridService: any;
|
||||
uiNotificationService: any;
|
||||
customizationService: any;
|
||||
private toolGroupIds: Set<string> = new Set();
|
||||
private toolBindingsMap: Map<string, Map<string, Array<Record<string, unknown>>>> = new Map();
|
||||
private defaultToolBindingsMap: Map<string, Map<string, ToolBindings>> = new Map();
|
||||
/**
|
||||
* Service-specific
|
||||
*/
|
||||
@@ -44,11 +53,17 @@ export default class ToolGroupService {
|
||||
EVENTS: { [key: string]: string };
|
||||
|
||||
constructor(servicesManager: AppTypes.ServicesManager) {
|
||||
const { cornerstoneViewportService, viewportGridService, uiNotificationService } =
|
||||
const {
|
||||
cornerstoneViewportService,
|
||||
viewportGridService,
|
||||
uiNotificationService,
|
||||
customizationService,
|
||||
} =
|
||||
servicesManager.services;
|
||||
this.cornerstoneViewportService = cornerstoneViewportService;
|
||||
this.viewportGridService = viewportGridService;
|
||||
this.uiNotificationService = uiNotificationService;
|
||||
this.customizationService = customizationService;
|
||||
this.listeners = {};
|
||||
this.EVENTS = EVENTS;
|
||||
Object.assign(this, pubSubServiceInterface);
|
||||
@@ -122,6 +137,8 @@ export default class ToolGroupService {
|
||||
public destroy(): void {
|
||||
ToolGroupManager.destroy();
|
||||
this.toolGroupIds = new Set();
|
||||
this.toolBindingsMap.clear();
|
||||
this.defaultToolBindingsMap.clear();
|
||||
|
||||
eventTarget.removeEventListener(Enums.Events.TOOL_ACTIVATED, this._onToolActivated);
|
||||
}
|
||||
@@ -198,6 +215,7 @@ export default class ToolGroupService {
|
||||
// this.changeConfigurationIfNecessary(toolGroup, volumeId);
|
||||
this._addTools(toolGroup, tools, configs);
|
||||
this._setToolsMode(toolGroup, tools);
|
||||
this._loadPersistedBindings(toolGroupId);
|
||||
}
|
||||
|
||||
public createToolGroupAndAddTools(toolGroupId: string, tools: Array<Tool>): Types.IToolGroup {
|
||||
@@ -242,34 +260,159 @@ export default class ToolGroupService {
|
||||
return this.getToolGroup(toolGroupId)?.getActivePrimaryMouseButtonTool();
|
||||
}
|
||||
|
||||
public getToolBindings(
|
||||
toolGroupId: string,
|
||||
toolName: string
|
||||
): ToolBindings | undefined {
|
||||
return this.toolBindingsMap.get(toolGroupId)?.get(toolName);
|
||||
}
|
||||
|
||||
public setToolBindings(toolGroupId: string, toolName: string, bindings: ToolBindings): void {
|
||||
if (!this.toolBindingsMap.has(toolGroupId)) {
|
||||
this.toolBindingsMap.set(toolGroupId, new Map());
|
||||
}
|
||||
this.toolBindingsMap.get(toolGroupId).set(toolName, this._cloneToolBindings(bindings));
|
||||
}
|
||||
|
||||
public getDefaultToolBindings(toolGroupId: string, toolName: string): ToolBindings | undefined {
|
||||
const defaultBindings = this.defaultToolBindingsMap.get(toolGroupId)?.get(toolName);
|
||||
return defaultBindings ? this._cloneToolBindings(defaultBindings) : undefined;
|
||||
}
|
||||
|
||||
public persistToolBindings(toolGroupId: string, toolName: string, bindings: ToolBindings): void {
|
||||
const persistedBindings = this._readPersistedToolBindings();
|
||||
if (!persistedBindings[toolGroupId]) {
|
||||
persistedBindings[toolGroupId] = {};
|
||||
}
|
||||
|
||||
persistedBindings[toolGroupId][toolName] = bindings;
|
||||
this._writePersistedToolBindings(persistedBindings);
|
||||
}
|
||||
|
||||
public removePersistedToolBindings(toolGroupId: string, toolName?: string): void {
|
||||
const persistedBindings = this._readPersistedToolBindings();
|
||||
if (!persistedBindings[toolGroupId]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (toolName) {
|
||||
delete persistedBindings[toolGroupId][toolName];
|
||||
if (!Object.keys(persistedBindings[toolGroupId]).length) {
|
||||
delete persistedBindings[toolGroupId];
|
||||
}
|
||||
} else {
|
||||
delete persistedBindings[toolGroupId];
|
||||
}
|
||||
|
||||
this._writePersistedToolBindings(persistedBindings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the currently tracked bindings to the runtime tool instance.
|
||||
*
|
||||
* Note: this method may activate tools that are currently Passive or Enabled.
|
||||
* Assigning bindings is treated as making the tool interactable.
|
||||
*/
|
||||
public applyToolBindings(
|
||||
toolGroupId: string,
|
||||
toolName: string,
|
||||
options: ApplyToolBindingsOptions = {}
|
||||
): void {
|
||||
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId);
|
||||
if (!toolGroup || !toolGroup.hasTool(toolName)) {
|
||||
return;
|
||||
}
|
||||
const bindings = this.getToolBindings(toolGroupId, toolName);
|
||||
if (!bindings) {
|
||||
return;
|
||||
}
|
||||
const { mode } = toolGroup.getToolOptions(toolName);
|
||||
if (
|
||||
mode === Enums.ToolModes.Active ||
|
||||
mode === Enums.ToolModes.Passive ||
|
||||
mode === Enums.ToolModes.Enabled
|
||||
) {
|
||||
if (options.replaceExisting) {
|
||||
// Opt-in behavior for callers that need replacement semantics.
|
||||
toolGroup.setToolDisabled(toolName);
|
||||
}
|
||||
toolGroup.setToolActive(toolName, { bindings });
|
||||
}
|
||||
}
|
||||
|
||||
public getAllToolBindings(): Array<{
|
||||
toolGroupId: string;
|
||||
toolName: string;
|
||||
bindings: Array<Record<string, unknown>>;
|
||||
}> {
|
||||
const result = [];
|
||||
for (const [toolGroupId, toolMap] of this.toolBindingsMap) {
|
||||
for (const [toolName, bindings] of toolMap) {
|
||||
result.push({ toolGroupId, toolName, bindings });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private _setToolsMode(toolGroup, tools) {
|
||||
const { active, passive, enabled, disabled } = tools;
|
||||
|
||||
if (active) {
|
||||
active.forEach(({ toolName, bindings }) => {
|
||||
if (bindings) {
|
||||
this.setToolBindings(toolGroup.id, toolName, bindings);
|
||||
this._setDefaultToolBindingsIfMissing(toolGroup.id, toolName, bindings);
|
||||
}
|
||||
toolGroup.setToolActive(toolName, { bindings });
|
||||
});
|
||||
}
|
||||
|
||||
if (passive) {
|
||||
passive.forEach(({ toolName }) => {
|
||||
passive.forEach(({ toolName, bindings }) => {
|
||||
if (bindings) {
|
||||
this.setToolBindings(toolGroup.id, toolName, bindings);
|
||||
this._setDefaultToolBindingsIfMissing(toolGroup.id, toolName, bindings);
|
||||
}
|
||||
toolGroup.setToolPassive(toolName);
|
||||
});
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
enabled.forEach(({ toolName }) => {
|
||||
enabled.forEach(({ toolName, bindings }) => {
|
||||
if (bindings) {
|
||||
this.setToolBindings(toolGroup.id, toolName, bindings);
|
||||
this._setDefaultToolBindingsIfMissing(toolGroup.id, toolName, bindings);
|
||||
}
|
||||
toolGroup.setToolEnabled(toolName);
|
||||
});
|
||||
}
|
||||
|
||||
if (disabled) {
|
||||
disabled.forEach(({ toolName }) => {
|
||||
disabled.forEach(({ toolName, bindings }) => {
|
||||
if (bindings) {
|
||||
this.setToolBindings(toolGroup.id, toolName, bindings);
|
||||
this._setDefaultToolBindingsIfMissing(toolGroup.id, toolName, bindings);
|
||||
}
|
||||
toolGroup.setToolDisabled(toolName);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _setDefaultToolBindingsIfMissing(
|
||||
toolGroupId: string,
|
||||
toolName: string,
|
||||
bindings: ToolBindings
|
||||
): void {
|
||||
if (!this.defaultToolBindingsMap.has(toolGroupId)) {
|
||||
this.defaultToolBindingsMap.set(toolGroupId, new Map());
|
||||
}
|
||||
|
||||
const toolMap = this.defaultToolBindingsMap.get(toolGroupId);
|
||||
if (!toolMap.has(toolName)) {
|
||||
toolMap.set(toolName, this._cloneToolBindings(bindings));
|
||||
}
|
||||
}
|
||||
|
||||
private _addTools(toolGroup, tools) {
|
||||
const addTools = tools => {
|
||||
tools.forEach(({ toolName, parentTool, configuration }) => {
|
||||
@@ -300,6 +443,71 @@ export default class ToolGroupService {
|
||||
}
|
||||
}
|
||||
|
||||
private _loadPersistedBindings(toolGroupId: string): void {
|
||||
const toolGroupBindings = this._readPersistedToolBindings()[toolGroupId];
|
||||
if (!toolGroupBindings) {
|
||||
return;
|
||||
}
|
||||
|
||||
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId);
|
||||
|
||||
for (const [toolName, bindings] of Object.entries(toolGroupBindings)) {
|
||||
this.setToolBindings(toolGroupId, toolName, bindings as ToolBindings);
|
||||
|
||||
if (!toolGroup || !toolGroup.hasTool(toolName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { mode } = toolGroup.getToolOptions(toolName);
|
||||
if (mode === Enums.ToolModes.Active) {
|
||||
this.applyToolBindings(toolGroupId, toolName, { replaceExisting: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _readPersistedToolBindings(): PersistedToolBindings {
|
||||
try {
|
||||
const stored = localStorage.getItem(this._getToolBindingsStorageKey());
|
||||
if (!stored) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const parsed = JSON.parse(stored);
|
||||
if (!parsed || typeof parsed !== 'object') {
|
||||
return {};
|
||||
}
|
||||
|
||||
return parsed as PersistedToolBindings;
|
||||
} catch {
|
||||
// ignore corrupt localStorage
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
private _writePersistedToolBindings(bindings: PersistedToolBindings): void {
|
||||
const storageKey = this._getToolBindingsStorageKey();
|
||||
if (!Object.keys(bindings).length) {
|
||||
localStorage.removeItem(storageKey);
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem(storageKey, JSON.stringify(bindings));
|
||||
}
|
||||
|
||||
private _cloneToolBindings(bindings: ToolBindings): ToolBindings {
|
||||
return bindings.map(binding => ({ ...binding }));
|
||||
}
|
||||
|
||||
private _getToolBindingsStorageKey(): string {
|
||||
const customizationValue = this.customizationService?.getCustomization(
|
||||
'ohif.userPreferences.toolBindingsStorageKey'
|
||||
);
|
||||
|
||||
return typeof customizationValue === 'string' && customizationValue.length > 0
|
||||
? customizationValue
|
||||
: 'user-preferred-tool-bindings';
|
||||
}
|
||||
|
||||
private _onToolActivated = (evt: Types.EventTypes.ToolActivatedEventType) => {
|
||||
const { toolGroupId, toolName, toolBindingsOptions } = evt.detail;
|
||||
const isPrimaryTool = toolBindingsOptions.bindings?.some(
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import { PubSubService } from '@ohif/core';
|
||||
|
||||
export type ViewedDataPayload = {
|
||||
viewedDataId?: string;
|
||||
viewedDataCleared?: boolean;
|
||||
};
|
||||
|
||||
class ViewedDataService extends PubSubService {
|
||||
public static readonly EVENTS = {
|
||||
VIEWED_DATA_CHANGED: 'event::viewedDataChanged',
|
||||
};
|
||||
|
||||
public static REGISTRATION = {
|
||||
name: 'viewedDataService',
|
||||
altName: 'ViewedDataService',
|
||||
create: () => {
|
||||
return new ViewedDataService();
|
||||
},
|
||||
};
|
||||
|
||||
private viewedDataIds = new Set<string>();
|
||||
|
||||
constructor() {
|
||||
super(ViewedDataService.EVENTS);
|
||||
}
|
||||
|
||||
public markDataViewed(dataId: string): void {
|
||||
if (!dataId || this.viewedDataIds.has(dataId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.viewedDataIds.add(dataId);
|
||||
this._broadcastEvent(this.EVENTS.VIEWED_DATA_CHANGED, {
|
||||
viewedDataId: dataId,
|
||||
});
|
||||
}
|
||||
|
||||
public isDataViewed(dataId: string): boolean {
|
||||
if (!dataId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.viewedDataIds.has(dataId);
|
||||
}
|
||||
|
||||
public clearViewedData(): void {
|
||||
this.viewedDataIds.clear();
|
||||
this._broadcastEvent(this.EVENTS.VIEWED_DATA_CHANGED, {
|
||||
viewedDataCleared: true,
|
||||
});
|
||||
}
|
||||
|
||||
public subscribeViewedDataChanges(listener: (payload: ViewedDataPayload) => void) {
|
||||
return this.subscribe(this.EVENTS.VIEWED_DATA_CHANGED, listener);
|
||||
}
|
||||
}
|
||||
|
||||
export default ViewedDataService;
|
||||
@@ -0,0 +1,3 @@
|
||||
import ViewedDataService from './ViewedDataService';
|
||||
|
||||
export default ViewedDataService;
|
||||
+179
-60
@@ -3,15 +3,11 @@ import { PubSubService } from '@ohif/core';
|
||||
import { Types as OhifTypes } from '@ohif/core';
|
||||
import {
|
||||
RenderingEngine,
|
||||
StackViewport,
|
||||
Types,
|
||||
getRenderingEngine,
|
||||
utilities as csUtils,
|
||||
VolumeViewport,
|
||||
VolumeViewport3D,
|
||||
cache,
|
||||
Enums as csEnums,
|
||||
BaseVolumeViewport,
|
||||
} from '@cornerstonejs/core';
|
||||
|
||||
import { utilities as csToolsUtils, Enums as csToolsEnums } from '@cornerstonejs/tools';
|
||||
@@ -38,6 +34,12 @@ import { usePositionPresentationStore } from '../../stores/usePositionPresentati
|
||||
import { useSynchronizersStore } from '../../stores/useSynchronizersStore';
|
||||
import { useSegmentationPresentationStore } from '../../stores/useSegmentationPresentationStore';
|
||||
import getClosestOrientationFromIOP from '../../utils/isReferenceViewable';
|
||||
import {
|
||||
getLegacyViewportType,
|
||||
isStackViewportType,
|
||||
isVolume3DViewportType,
|
||||
isVolumeViewportType,
|
||||
} from '../../utils/getLegacyViewportType';
|
||||
import { BlendModes } from '@cornerstonejs/core/enums';
|
||||
|
||||
const EVENTS = {
|
||||
@@ -48,6 +50,56 @@ const EVENTS = {
|
||||
const MIN_STACK_VIEWPORTS_TO_ENQUEUE_RESIZE = 12;
|
||||
const MIN_VOLUME_VIEWPORTS_TO_ENQUEUE_RESIZE = 6;
|
||||
|
||||
// Actor class names that represent a primary volume binding in a viewport.
|
||||
// Legacy ORTHOGRAPHIC / VOLUME_3D render the source volume as a 'vtkVolume'
|
||||
// actor. Under the GenericViewport-backed compat path (useGenericViewport),
|
||||
// the MPR slice render path emits 'vtkImageSlice' actors instead, so the
|
||||
// volume-set-vs-add optimization below must recognize both. (3D still uses
|
||||
// 'vtkVolume'.) Without this, the optimization silently no-ops and a full
|
||||
// setVolumes() teardown blanks MPR during SEG hydration.
|
||||
const VOLUME_ACTOR_CLASS_NAMES = new Set(['vtkVolume', 'vtkImageSlice']);
|
||||
|
||||
function getVolumeActorReferencedIds(viewport: Types.IVolumeViewport): string[] {
|
||||
const actors = viewport.getActors?.() ?? [];
|
||||
return actors
|
||||
.filter(ac => VOLUME_ACTOR_CLASS_NAMES.has(ac.actor?.getClassName?.() ?? ''))
|
||||
.map(ac => ac.referencedId)
|
||||
.filter(Boolean) as string[];
|
||||
}
|
||||
|
||||
function volumeIdPrefixesMatch(
|
||||
existingIds: string[],
|
||||
prefixLen: number,
|
||||
targetIds: string[]
|
||||
): boolean {
|
||||
if (prefixLen > targetIds.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < prefixLen; i++) {
|
||||
if (existingIds[i] !== targetIds[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when the viewport type matches a volume-based presentation (ORTHOGRAPHIC or VOLUME_3D).
|
||||
*/
|
||||
function viewportMatchesDesiredVolumePresentation(
|
||||
viewport: Types.IViewport,
|
||||
desiredViewportInfo: ViewportInfo
|
||||
): boolean {
|
||||
const desiredType = desiredViewportInfo.getViewportType();
|
||||
if (getLegacyViewportType(viewport) !== desiredType) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
desiredType === csEnums.ViewportType.ORTHOGRAPHIC ||
|
||||
desiredType === csEnums.ViewportType.VOLUME_3D
|
||||
);
|
||||
}
|
||||
|
||||
export const WITH_NAVIGATION = { withNavigation: true, withOrientation: false };
|
||||
export const WITH_ORIENTATION = { withNavigation: true, withOrientation: true };
|
||||
|
||||
@@ -328,7 +380,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
|
||||
return {
|
||||
viewportType: viewportInfo.getViewportType(),
|
||||
viewReference: csViewport instanceof VolumeViewport3D ? null : csViewport.getViewReference(),
|
||||
viewReference: isVolume3DViewportType(csViewport) ? null : csViewport.getViewReference(),
|
||||
viewPresentation: csViewport.getViewPresentation({ pan: true, zoom: true }),
|
||||
viewportId,
|
||||
};
|
||||
@@ -356,10 +408,9 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
return properties;
|
||||
};
|
||||
|
||||
const properties =
|
||||
csViewport instanceof BaseVolumeViewport
|
||||
? new Map()
|
||||
: cleanProperties(csViewport.getProperties());
|
||||
const properties = isVolumeViewportType(csViewport)
|
||||
? new Map()
|
||||
: cleanProperties(csViewport.getProperties());
|
||||
|
||||
if (properties instanceof Map) {
|
||||
const volumeIds = (csViewport as Types.IBaseVolumeViewport).getAllVolumeIds();
|
||||
@@ -778,6 +829,19 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
/**
|
||||
* Sets the image data for the given viewport.
|
||||
*/
|
||||
private async _setEcgViewport(
|
||||
viewport: Types.IECGViewport,
|
||||
viewportData: StackViewportData
|
||||
): Promise<void> {
|
||||
const [displaySet] = viewportData.data;
|
||||
const imageId = displaySet.imageIds?.[0];
|
||||
if (!imageId) {
|
||||
console.error('[CornerstoneViewportService] ECG display set has no imageId');
|
||||
return;
|
||||
}
|
||||
return viewport.setEcg(imageId);
|
||||
}
|
||||
|
||||
private async _setOtherViewport(
|
||||
viewport: Types.IStackViewport,
|
||||
viewportData: StackViewportData,
|
||||
@@ -785,10 +849,14 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
_presentations: Presentations = {}
|
||||
): Promise<void> {
|
||||
const [displaySet] = viewportData.data;
|
||||
return viewport.setDataIds(displaySet.imageIds, {
|
||||
groupId: displaySet.displaySetInstanceUID,
|
||||
viewReference: viewportInfo.getViewReference(),
|
||||
});
|
||||
// CS3D's "redo viewports" replaced setDataIds with the generic
|
||||
// setDisplaySets({ displaySetId }) API; the legacy adapters key off
|
||||
// imageIds[0] as the displaySetId, so do the same here.
|
||||
await viewport.setDisplaySets({ displaySetId: displaySet.imageIds[0] });
|
||||
const viewReference = viewportInfo.getViewReference();
|
||||
if (viewReference) {
|
||||
viewport.setViewReference(viewReference);
|
||||
}
|
||||
}
|
||||
|
||||
private async _setStackViewport(
|
||||
@@ -856,28 +924,21 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
initialImageIndexToUse = this._getInitialImageIndexForViewport(viewportInfo, imageIds) || 0;
|
||||
}
|
||||
|
||||
return viewport.setStack(imageIds, initialImageIndexToUse).then(() => {
|
||||
viewport.setProperties({ ...properties });
|
||||
this.setPresentations(viewport.id, presentations, viewportInfo);
|
||||
await viewport.setStack(imageIds, initialImageIndexToUse);
|
||||
viewport.setProperties({ ...properties });
|
||||
this.setPresentations(viewport.id, presentations, viewportInfo);
|
||||
|
||||
if (overlayProcessingResults?.length) {
|
||||
overlayProcessingResults.forEach(overlayProcessingResult => {
|
||||
if (overlayProcessingResult?.addOverlayFn) {
|
||||
overlayProcessingResult.addOverlayFn();
|
||||
}
|
||||
});
|
||||
}
|
||||
await this._addOverlayRepresentations(overlayProcessingResults);
|
||||
|
||||
if (displayArea) {
|
||||
viewport.setDisplayArea(displayArea);
|
||||
}
|
||||
if (rotation) {
|
||||
viewport.setProperties({ rotation });
|
||||
}
|
||||
if (flipHorizontal) {
|
||||
viewport.setCamera({ flipHorizontal: true });
|
||||
}
|
||||
});
|
||||
if (displayArea) {
|
||||
viewport.setDisplayArea(displayArea);
|
||||
}
|
||||
if (rotation) {
|
||||
viewport.setProperties({ rotation });
|
||||
}
|
||||
if (flipHorizontal) {
|
||||
viewport.setCamera({ flipHorizontal: true });
|
||||
}
|
||||
}
|
||||
|
||||
private _getInitialImageIndexForViewport(
|
||||
@@ -1093,7 +1154,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
throw new Error('Background display set not found');
|
||||
}
|
||||
|
||||
if (viewport.type === csEnums.ViewportType.VOLUME_3D) {
|
||||
if (isVolume3DViewportType(viewport)) {
|
||||
timeoutViewportCallback(() => {
|
||||
viewportGridService.setDisplaySetsForViewport({
|
||||
viewportId: viewport.id,
|
||||
@@ -1105,15 +1166,45 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
});
|
||||
}
|
||||
|
||||
await viewport.setVolumes(volumeInputArray);
|
||||
const baseVolumeInputs = filteredVolumeInputArray.map(({ volumeInput }) => volumeInput);
|
||||
const nextBaseVolumeIds = baseVolumeInputs.map(v => v.volumeId);
|
||||
const existingVolumeIds = getVolumeActorReferencedIds(viewport);
|
||||
|
||||
if (overlayProcessingResults?.length) {
|
||||
overlayProcessingResults.forEach(({ addOverlayFn }) => {
|
||||
if (addOverlayFn) {
|
||||
addOverlayFn();
|
||||
let skippedIdenticalBaseVolumes = false;
|
||||
|
||||
if (baseVolumeInputs.length) {
|
||||
const singleBaseViewport = nextBaseVolumeIds.length === 1;
|
||||
|
||||
// Only skip setVolumes() when the viewport type already matches the desired OHIF type
|
||||
// (ORTHOGRAPHIC / VOLUME_3D); otherwise a stack → MPR switch with the same volumeId
|
||||
// would incorrectly skip rebuilding the viewport.
|
||||
if (
|
||||
singleBaseViewport &&
|
||||
existingVolumeIds.length >= nextBaseVolumeIds.length &&
|
||||
volumeIdPrefixesMatch(existingVolumeIds, nextBaseVolumeIds.length, nextBaseVolumeIds) &&
|
||||
viewportMatchesDesiredVolumePresentation(viewport, viewportInfo)
|
||||
) {
|
||||
// Same primary volume already loaded (e.g. labelmap / extra actors after it) — avoid
|
||||
// setVolumes(), which tears down all actors and blanks MPR during SEG hydrate.
|
||||
skippedIdenticalBaseVolumes = true;
|
||||
} else if (
|
||||
existingVolumeIds.length &&
|
||||
nextBaseVolumeIds.length > existingVolumeIds.length &&
|
||||
volumeIdPrefixesMatch(existingVolumeIds, existingVolumeIds.length, nextBaseVolumeIds) &&
|
||||
typeof viewport.addVolumes === 'function'
|
||||
) {
|
||||
const toAdd = baseVolumeInputs.slice(existingVolumeIds.length);
|
||||
if (toAdd.length) {
|
||||
await viewport.addVolumes(toAdd);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await viewport.setVolumes(baseVolumeInputs);
|
||||
}
|
||||
} else if (volumeInputArray.length) {
|
||||
await viewport.setVolumes(volumeInputArray);
|
||||
}
|
||||
|
||||
await this._addOverlayRepresentations(overlayProcessingResults);
|
||||
viewport.render();
|
||||
|
||||
volumesProperties.forEach(({ properties, volumeId }) => {
|
||||
@@ -1124,8 +1215,11 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
});
|
||||
|
||||
this.setPresentations(viewport.id, presentations);
|
||||
// Presentations apply segmentation (hydrated labelmap etc.) after the render above — redraw so
|
||||
// every orthographic/3D tile shows the updated scene (fixes MPR siblings blank after SEG hydrate).
|
||||
viewport.render();
|
||||
|
||||
if (!presentations.positionPresentation) {
|
||||
if (!presentations.positionPresentation && !skippedIdenticalBaseVolumes) {
|
||||
const imageIndex = this._getInitialImageIndexForViewport(viewportInfo);
|
||||
|
||||
if (imageIndex !== undefined) {
|
||||
@@ -1179,7 +1273,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
private addOverlayRepresentationForDisplaySet(
|
||||
displaySet: OhifTypes.DisplaySet,
|
||||
viewport: Types.IViewport
|
||||
) {
|
||||
): Promise<void> {
|
||||
const { segmentationService } = this.servicesManager.services;
|
||||
const segmentationId = displaySet.displaySetInstanceUID;
|
||||
|
||||
@@ -1189,18 +1283,36 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
: csToolsEnums.SegmentationRepresentations.Contour;
|
||||
|
||||
const { predecessorImageId } = displaySet;
|
||||
segmentationService.addSegmentationRepresentation(viewport.id, {
|
||||
segmentationId,
|
||||
predecessorImageId,
|
||||
type: representationType,
|
||||
config: {
|
||||
blendMode:
|
||||
viewport?.getBlendMode?.() === 1 ? BlendModes.LABELMAP_EDGE_PROJECTION_BLEND : undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const segmentationRepresentationPromise = segmentationService.addSegmentationRepresentation(
|
||||
viewport.id,
|
||||
{
|
||||
segmentationId,
|
||||
predecessorImageId,
|
||||
type: representationType,
|
||||
config: {
|
||||
blendMode:
|
||||
viewport?.getBlendMode?.() === 1
|
||||
? BlendModes.LABELMAP_EDGE_PROJECTION_BLEND
|
||||
: undefined,
|
||||
},
|
||||
}
|
||||
);
|
||||
// store the segmentation presentation id in the viewport info
|
||||
this.storePresentation({ viewportId: viewport.id });
|
||||
return segmentationRepresentationPromise;
|
||||
}
|
||||
|
||||
private async _addOverlayRepresentations(
|
||||
overlayProcessingResults?: Array<{ addOverlayFn?: () => Promise<void> }>
|
||||
): Promise<void> {
|
||||
if (!overlayProcessingResults?.length) {
|
||||
return;
|
||||
}
|
||||
for (const overlayProcessingResult of overlayProcessingResults) {
|
||||
if (overlayProcessingResult?.addOverlayFn) {
|
||||
await overlayProcessingResult.addOverlayFn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Todo: keepCamera is an interim solution until we have a better solution for
|
||||
@@ -1212,7 +1324,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
|
||||
let displaySetPromise;
|
||||
|
||||
if (viewport instanceof VolumeViewport || viewport instanceof VolumeViewport3D) {
|
||||
if (isVolumeViewportType(viewport)) {
|
||||
displaySetPromise = this._setVolumeViewport(viewport, viewportData, viewportInfo).then(() => {
|
||||
if (keepCamera) {
|
||||
viewport.setCamera(viewportCamera);
|
||||
@@ -1221,7 +1333,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
});
|
||||
}
|
||||
|
||||
if (viewport instanceof StackViewport) {
|
||||
if (isStackViewportType(viewport)) {
|
||||
displaySetPromise = this._setStackViewport(viewport, viewportData, viewportInfo);
|
||||
}
|
||||
|
||||
@@ -1239,7 +1351,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
viewportInfo: ViewportInfo,
|
||||
presentations: Presentations = {}
|
||||
): Promise<void> {
|
||||
if (viewport instanceof StackViewport) {
|
||||
if (isStackViewportType(viewport)) {
|
||||
return this._setStackViewport(
|
||||
viewport,
|
||||
viewportData as StackViewportData,
|
||||
@@ -1248,7 +1360,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
);
|
||||
}
|
||||
|
||||
if ([VolumeViewport, VolumeViewport3D].some(type => viewport instanceof type)) {
|
||||
if (isVolumeViewportType(viewport)) {
|
||||
return this._setVolumeViewport(
|
||||
viewport as Types.IVolumeViewport,
|
||||
viewportData as VolumeViewportData,
|
||||
@@ -1257,6 +1369,13 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
);
|
||||
}
|
||||
|
||||
if (getLegacyViewportType(viewport) === csEnums.ViewportType.ECG) {
|
||||
return this._setEcgViewport(
|
||||
viewport as unknown as Types.IECGViewport,
|
||||
viewportData as StackViewportData
|
||||
);
|
||||
}
|
||||
|
||||
return this._setOtherViewport(
|
||||
viewport,
|
||||
viewportData as StackViewportData,
|
||||
@@ -1308,8 +1427,8 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
return;
|
||||
}
|
||||
|
||||
if (displaySet.frameOfReferenceUID) {
|
||||
return displaySet.frameOfReferenceUID;
|
||||
if (displaySet.FrameOfReferenceUID) {
|
||||
return displaySet.FrameOfReferenceUID;
|
||||
}
|
||||
|
||||
if (displaySet.Modality === 'SEG') {
|
||||
@@ -1402,7 +1521,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
}
|
||||
|
||||
const { properties } = lutPresentation;
|
||||
if (viewport instanceof BaseVolumeViewport) {
|
||||
if (isVolumeViewportType(viewport)) {
|
||||
if (properties instanceof Map) {
|
||||
properties.forEach((propertiesEntry, volumeId) => {
|
||||
viewport.setProperties(propertiesEntry, volumeId);
|
||||
@@ -1451,7 +1570,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
||||
const { segmentationId, type, hydrated } = presentationItem;
|
||||
|
||||
const { Labelmap, Surface } = csToolsEnums.SegmentationRepresentations;
|
||||
const isVolume3D = viewport.type === csEnums.ViewportType.VOLUME_3D;
|
||||
const isVolume3D = isVolume3DViewportType(viewport);
|
||||
|
||||
// Determine the appropriate segmentation representation for the viewport.
|
||||
// If the current type is Surface but the viewport is not 3D, fallback to Labelmap.
|
||||
|
||||
@@ -2,10 +2,10 @@ import {
|
||||
Types,
|
||||
Enums,
|
||||
getEnabledElementByViewportId,
|
||||
VolumeViewport,
|
||||
utilities,
|
||||
} from '@cornerstonejs/core';
|
||||
import { StackViewportData, VolumeViewportData } from '../../types/CornerstoneCacheService';
|
||||
import { isOrthographicViewportType } from '../../utils/getLegacyViewportType';
|
||||
import getCornerstoneBlendMode from '../../utils/getCornerstoneBlendMode';
|
||||
import getCornerstoneOrientation from '../../utils/getCornerstoneOrientation';
|
||||
import getCornerstoneViewportType from '../../utils/getCornerstoneViewportType';
|
||||
@@ -105,7 +105,7 @@ const dataContains = ({ data, displaySetUID, imageId, viewport }): boolean => {
|
||||
return !!data.imageIds.find(dataId => dataId === imageId);
|
||||
}
|
||||
|
||||
if (imageId && (data.volumeId || viewport instanceof VolumeViewport)) {
|
||||
if (imageId && (data.volumeId || isOrthographicViewportType(viewport))) {
|
||||
const isAcquisition = !!viewport.getCurrentImageId();
|
||||
|
||||
if (!isAcquisition) {
|
||||
|
||||
@@ -135,16 +135,27 @@ const _getSegmentationPresentationId = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const { displaySetService } = servicesManager.services;
|
||||
const { displaySetInstanceUIDs, viewportOptions } = viewport;
|
||||
|
||||
// Match keys used by updateStoredSegmentationPresentation (referenced volume only).
|
||||
// Including overlay UIDs (e.g. SEG) produced ids like "MR&SEG" while the store
|
||||
// entry is under "MR", so hydrated segmentations never applied and viewports could mis-render.
|
||||
const nonOverlayUIDs = displaySetInstanceUIDs.filter(uid => {
|
||||
const ds = displaySetService.getDisplaySetByUID(uid);
|
||||
return ds && !ds.isOverlayDisplaySet;
|
||||
});
|
||||
|
||||
if (!nonOverlayUIDs.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let orientation = viewportOptions.orientation;
|
||||
|
||||
if (!orientation) {
|
||||
// Calculate orientation from the viewport sample image
|
||||
const displaySet = servicesManager.services.displaySetService.getDisplaySetByUID(
|
||||
displaySetInstanceUIDs[0]
|
||||
);
|
||||
const sampleImage = displaySet.images?.[0];
|
||||
const displaySet = displaySetService.getDisplaySetByUID(nonOverlayUIDs[0]);
|
||||
const sampleImage = displaySet?.images?.[0];
|
||||
const imageOrientationPatient = sampleImage?.ImageOrientationPatient;
|
||||
|
||||
orientation = getViewportOrientationFromImageOrientationPatient(imageOrientationPatient);
|
||||
@@ -152,7 +163,7 @@ const _getSegmentationPresentationId = ({
|
||||
|
||||
const segmentationPresentationArr = [];
|
||||
|
||||
segmentationPresentationArr.push(...displaySetInstanceUIDs);
|
||||
segmentationPresentationArr.push(...nonOverlayUIDs);
|
||||
|
||||
// Uncomment if unique indexing is needed
|
||||
// addUniqueIndex(
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { VolumeViewport, metaData, utilities } from '@cornerstonejs/core';
|
||||
import { metaData, utilities } from '@cornerstonejs/core';
|
||||
import { IStackViewport, IVolumeViewport } from '@cornerstonejs/core/types';
|
||||
import { AnnotationDisplayTool, drawing } from '@cornerstonejs/tools';
|
||||
import { guid, b64toBlob } from '@ohif/core/src/utils';
|
||||
import OverlayPlaneModuleProvider from './OverlayPlaneModuleProvider';
|
||||
import { isOrthographicViewportType } from '../utils/getLegacyViewportType';
|
||||
|
||||
interface CachedStat {
|
||||
color: number[]; // [r, g, b, a]
|
||||
@@ -49,7 +50,7 @@ class ImageOverlayViewerTool extends AnnotationDisplayTool {
|
||||
onSetToolDisabled = (): void => {};
|
||||
|
||||
protected getReferencedImageId(viewport: IStackViewport | IVolumeViewport): string {
|
||||
if (viewport instanceof VolumeViewport) {
|
||||
if (isOrthographicViewportType(viewport)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 660 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user