Skip to content

fix: New growcut (fill) implementation#5954

Open
wayfarer3130 wants to merge 12 commits into
masterfrom
fix/grow-cut-suv-pt
Open

fix: New growcut (fill) implementation#5954
wayfarer3130 wants to merge 12 commits into
masterfrom
fix/grow-cut-suv-pt

Conversation

@wayfarer3130

@wayfarer3130 wayfarer3130 commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Context

The old growcut implementation had fundamental issues working with PT type series because of the size/setup of the PT.
This is being replaced by a newer version that uses teh currently displayed image as the base image for determining the cutoff, and uses a flood fill algorithm that is bounded to give reasonable performance for clicking.

Changes & Results

CS3D_REF: fix/grow-cut-suv-pt

Checkout the referenced branch and link/build/run

Mostly changed the growcut version tag to reference the new growcut algorithm.

Testing

If you are using speckled areas (like CT brain matter), check the checkbox to use the full area, otherwise select a bright OR
dark are (high contrast with an edge), and click the circle so there is some inside, some outside regions, and you click on an included point.

Using the full area one click, just click so the circle is entirely within the mottled area.

Checklist

PR

  • [] My Pull Request title is descriptive, accurate and follows the
    semantic-release format and guidelines.

Code

  • [] My code has been well-documented (function documentation, inline comments,
    etc.)

Public Documentation Updates

  • [] The documentation page has been updated as necessary for any public API
    additions or removals.

Tested Environment

  • [] OS:
  • [] Node version:
  • [] Browser:

Summary by CodeRabbit

  • New Features

    • Enhanced RegionSegmentPlus tool with flood-fill segmentation capability.
    • Added configurable range sliders—"Max Delta K" and "Max Delta IJ"—to fine-tune flood-fill intensity thresholds.
  • Improvements

    • Improved measurement cancellation behavior for better user control.
    • Enhanced CI/E2E testing infrastructure with improved port management.

Greptile Summary

Replaces the old GrowCut (RegionSegmentPlusTool) implementation with a flood-fill variant (RegionSegmentPlusFloodFillTool) that operates on the currently displayed image slice and is bounded by configurable Max Delta K (slice direction) and Max Delta IJ (in-plane) parameters. The CI Playwright setup gains a cross-platform port-cleanup script (free-ohif-e2e-port.mjs) that runs before the dev server starts, and the config is refactored to drive the port from a single OHIF_PORT env var.

  • initCornerstoneTools.js / initToolGroups.ts — tool registration and initial configuration wired to the new flood-fill tool.
  • commandsModule.ts — adds _getRegionSegmentPlusLimits, cancelMeasurement (also hooked into rejectPreview for ESC cancellation), and setRegionSegmentPlusFloodFillConfiguration which updates both the toolbar sliders and the live tool configuration.
  • playwright.config.ts / free-ohif-e2e-port.mjs — CI improvements: parameterised port, reduced workers (18 → 6), and pre-server port cleanup on self-hosted runners.

Confidence Score: 5/5

Safe to merge; the core flood-fill tool swap is clean and the CI helper is well-guarded.

The tool replacement is mechanical (import swap + configuration block), and the new command logic is well-structured. Issues flagged in earlier review threads (imageData fallback, toolbar option mutation, Windows findstr substring match) are the only open concerns; no new blocking problems were found in this pass.

extensions/cornerstone/src/commandsModule.ts — open items from prior threads around the imageData fallback branch and toolbar option mutation remain unresolved.

Important Files Changed

Filename Overview
extensions/cornerstone/src/commandsModule.ts Adds _getRegionSegmentPlusLimits, cancelMeasurement, and setRegionSegmentPlusFloodFillConfiguration; rejectPreview now calls cancelMeasurement; all notable issues were flagged in prior review threads.
.scripts/ci/free-ohif-e2e-port.mjs New CI helper that finds and kills any process holding the Playwright e2e port; cross-platform (macOS lsof, Linux lsof/ss/fuser, Windows netstat+findstr); Windows findstr substring-match concern flagged in prior thread.
modes/segmentation/src/toolbarButtons.ts Updates RegionSegmentPlus button: new tooltip, evaluate toolNames updated to RegionSegmentPlusFloodFill, two range-slider options (Max Delta K/IJ) added, and setRegionSegmentPlusFloodFillConfiguration wired into commands.
playwright.config.ts Port parameterised via OHIF_PORT env var, workers reduced from 18 to 6, video switched to on-first-retry, --use-gl=egl removed, and port-cleanup command prepended in CI mode.
extensions/cornerstone/src/initCornerstoneTools.js Swaps RegionSegmentPlusTool for RegionSegmentPlusFloodFillTool in registration, addTool, and toolNames map — straightforward tool replacement with no logic changes.
modes/segmentation/src/initToolGroups.ts Adds initial configuration block for RegionSegmentPlus with flood-fill defaults (hoverPrecheckEnabled: false, canvasDiskTriClassLarge strategy, maxDeltaK/IJ); values match command-module defaults so first activation is consistent.

Reviews (7): Last reviewed commit: "Merge remote-tracking branch 'origin/mas..." | Re-trigger Greptile

@wayfarer3130 wayfarer3130 added the ohif-integration Causes a CS3D/OHIF integraiton build to be run label Apr 9, 2026
@netlify

netlify Bot commented Apr 9, 2026

Copy link
Copy Markdown

Deploy Preview for ohif-dev failed. Why did it fail? →

Name Link
🔨 Latest commit 35ca13f
🔍 Latest deploy log https://app.netlify.com/projects/ohif-dev/deploys/6a3c3825e68ac200087d7ab1

Comment thread extensions/cornerstone/src/commandsModule.ts
Comment thread extensions/cornerstone/src/commandsModule.ts
Comment thread extensions/cornerstone/src/commandsModule.ts
@cypress

cypress Bot commented Apr 16, 2026

Copy link
Copy Markdown

Viewers    Run #6429

Run Properties:  status check failed Failed #6429  •  git commit 35ca13fa54: Merge branch 'master' into fix/grow-cut-suv-pt
Project Viewers
Branch Review fix/grow-cut-suv-pt
Run status status check failed Failed #6429
Run duration 02m 24s
Commit git commit 35ca13fa54: Merge branch 'master' into fix/grow-cut-suv-pt
Committer Bill Wallace
View all properties for this run ↗︎

Test results
Tests that failed  Failures 12
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 16
Tests that passed  Passing 0
View all changes introduced in this branch ↗︎

Tests for review

Failed  OHIFVideoDisplay.spec.js • 2 failed tests

View Output Video

Test Artifacts
OHIF Video Display > checks if series thumbnails are being displayed Test Replay Screenshots Video
OHIF Video Display > performs double-click to load thumbnail in active viewport Test Replay Screenshots Video
Failed  measurement-tracking/OHIFCornerstoneToolbar.spec.js • 1 failed test

View Output Video

Test Artifacts
OHIF Cornerstone Toolbar > checks if all primary buttons are being displayed Test Replay Screenshots Video
Failed  measurement-tracking/OHIFMeasurementPanel.spec.js • 1 failed test

View Output Video

Test Artifacts
OHIF Measurement Panel > checks if Measurements right panel can be hidden/displayed Test Replay Screenshots Video
Failed  measurement-tracking/OHIFCornerstoneHotkeys.spec.js • 1 failed test

View Output Video

Test Artifacts
OHIF Cornerstone Hotkeys > checks if hotkeys "R" and "L" can rotate the image Test Replay Screenshots Video
Failed  customization/HangingProtocol.spec.js • 1 failed test

View Output Video

Test Artifacts
OHIF HP > Should display 3 up Test Replay Screenshots Video

The first 5 failed specs are shown, see all 11 specs in Cypress Cloud.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a0a78d5f-df48-4de6-9738-b2d6e749ce28

📥 Commits

Reviewing files that changed from the base of the PR and between 5f49a51 and 2dd6e11.

📒 Files selected for processing (2)
  • .scripts/ci/free-ohif-e2e-port.mjs
  • extensions/cornerstone/src/commandsModule.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • .scripts/ci/free-ohif-e2e-port.mjs
  • extensions/cornerstone/src/commandsModule.ts

📝 Walkthrough

Walkthrough

Adds a cross-platform CI utility script (.scripts/ci/free-ohif-e2e-port.mjs) that kills stale processes on the OHIF E2E port, integrates it into playwright.config.ts via dynamic port configuration. Separately, migrates RegionSegmentPlus to use RegionSegmentPlusFloodFillTool, adds viewport-aware delta limit commands, and exposes configurable flood-fill parameters in the toolbar.

Changes

Port-freeing CI Utility and Playwright Integration

Layer / File(s) Summary
Port-freeing utility script
.scripts/ci/free-ohif-e2e-port.mjs
Exports getOhifE2ePort() (validates OHIF_PORT integer) and freeOhifE2ePort(). Implements per-platform PID discovery via lsof/ss (macOS/Linux) and netstat (Windows), force-kills listener PIDs, adds a Linux fuser -k fallback, and auto-runs when executed directly.
Playwright dynamic port and CI command
playwright.config.ts
Derives E2E_PORT/E2E_BASE_URL from OHIF_PORT, prepends the port-freeing script to the dev server command in CI only, and updates use.baseURL and webServer.command/url to use the dynamic values.

RegionSegmentPlus Flood-Fill Migration

Layer / File(s) Summary
Tool registration switch
extensions/cornerstone/src/initCornerstoneTools.js
Replaces RegionSegmentPlusTool import/registration/toolNames mapping with RegionSegmentPlusFloodFillTool.
Tool group initial configuration
modes/segmentation/src/initToolGroups.ts
Adds a configuration block to the RegionSegmentPlus passive tool entry: disables hover prechecks, sets canvasDiskTriClassLarge intensity strategy, defines maxDeltaK/maxDeltaIJ thresholds, and disables preview.
Configuration commands and toolbar UI
extensions/cornerstone/src/commandsModule.ts, modes/segmentation/src/toolbarButtons.ts
Adds _clampToRange/_getRegionSegmentPlusLimits helpers; implements cancelMeasurement (replacing rejectPreview's inline logic) and setRegionSegmentPlusFloodFillConfiguration (applies clamped delta settings to tool group config and refreshes toolbar); registers both in definitions. Updates RegionSegmentPlus toolbar button to RegionSegmentPlusFloodFill evaluate target and exposes Max Delta K/Max Delta IJ slider options.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Suggested reviewers

  • sedghi

Poem

🐇 Hop, hop, I cleared the port with glee,
No stale process shall block thee!
The flood-fill tool now reigns supreme,
With Delta K and IJ as a team.
Cancel, configure, render anew—
A rabbit's CI magic, just for you! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: replacing the old GrowCut implementation with a new flood-fill variant, which directly addresses the core issue of PT-type series failures.
Description check ✅ Passed The description provides context (PT series issues with old implementation), explains the solution (new flood-fill algorithm), includes testing instructions, and references a branch; however, the Tested Environment section remains unchecked and the PR title checkbox is marked incomplete.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/grow-cut-suv-pt

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 OpenGrep (1.23.0)
extensions/cornerstone/src/commandsModule.ts

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

[00.13][ERROR]: unable to find a config; path .coderabbit-opengrep-fallback.yml does not exist


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread .scripts/ci/free-ohif-e2e-port.mjs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
modes/segmentation/src/toolbarButtons.ts (1)

766-822: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pass the flood-fill tool name explicitly when activating this button.

This button still uses id: 'RegionSegmentPlus', but setToolActiveToolbar resolves the target from toolName || itemId || value (extensions/cornerstone/src/commandsModule.ts, Line 1129). With the updated registration/evaluate path now using RegionSegmentPlusFloodFill, clicking the button can no-op because it still activates the legacy id instead of the registered tool name.

Suggested fix
       commands: [
-        'setToolActiveToolbar',
+        {
+          commandName: 'setToolActiveToolbar',
+          commandOptions: {
+            toolName: 'RegionSegmentPlusFloodFill',
+          },
+        },
         'setRegionSegmentPlusFloodFillConfiguration',
         {
           commandName: 'activateSelectedSegmentationOfType',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@modes/segmentation/src/toolbarButtons.ts` around lines 766 - 822, The toolbar
button currently uses id 'RegionSegmentPlus' but setToolActiveToolbar resolves
targets from toolName || itemId || value so it may activate the wrong legacy id;
update the commands for this button (the commands array that currently includes
'setToolActiveToolbar') to pass the flood-fill tool name explicitly (e.g.,
include a command entry invoking setToolActiveToolbar with toolName:
'RegionSegmentPlusFloodFill' or set the value to 'RegionSegmentPlusFloodFill')
so activation targets the registered tool; locate the button definition (id:
'RegionSegmentPlus') in modes/segmentation/src/toolbarButtons.ts and modify the
commands element to supply the explicit tool name when calling
setToolActiveToolbar.
🧹 Nitpick comments (1)
playwright.config.ts (1)

3-4: 💤 Low value

Consider validating OHIF_PORT to match the utility script's validation.

The port-freeing utility (free-ohif-e2e-port.mjs) validates that OHIF_PORT is an integer in range 1-65535 and throws a descriptive error if invalid. This config file uses Number(process.env.OHIF_PORT || 3335) without validation, which would produce NaN for non-numeric values like "abc", leading to a confusing http://localhost:NaN URL.

♻️ Suggested validation
-const E2E_PORT = Number(process.env.OHIF_PORT || 3335);
+const E2E_PORT = (() => {
+  const port = Number(process.env.OHIF_PORT || 3335);
+  if (!Number.isInteger(port) || port < 1 || port > 65535) {
+    throw new Error(`Invalid OHIF_PORT: ${process.env.OHIF_PORT}`);
+  }
+  return port;
+})();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@playwright.config.ts` around lines 3 - 4, E2E_PORT is set using Number(...)
without validation which can produce NaN for bad env values; replicate the
utility script's validation: read process.env.OHIF_PORT, if present parse it as
an integer (base 10), ensure it's an integer between 1 and 65535, and if invalid
throw a descriptive Error stating the invalid OHIF_PORT value and expected
range; if not present, use the default 3335. Then set E2E_PORT and E2E_BASE_URL
using the validated integer. Reference the constants E2E_PORT and E2E_BASE_URL
and mirror the validation behavior from free-ohif-e2e-port.mjs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@extensions/cornerstone/src/commandsModule.ts`:
- Around line 202-240: The function _getRegionSegmentPlusLimits uses direct
instanceof checks for StackViewport and VolumeViewport but those classes are not
imported and bypass the legacy GenericViewport adapters; replace the instanceof
checks by using the existing helper predicates isStackViewportType(viewport) and
isVolumeViewportType(viewport) (importing them if missing) to detect viewport
types, keep the same logic for computing maxDeltaK/maxDeltaIJ, and ensure
csUtils.getImageSliceDataForVolumeViewport(viewport) is only called when
isVolumeViewportType returns true; update imports to include the predicate
functions rather than StackViewport/VolumeViewport classes.

---

Outside diff comments:
In `@modes/segmentation/src/toolbarButtons.ts`:
- Around line 766-822: The toolbar button currently uses id 'RegionSegmentPlus'
but setToolActiveToolbar resolves targets from toolName || itemId || value so it
may activate the wrong legacy id; update the commands for this button (the
commands array that currently includes 'setToolActiveToolbar') to pass the
flood-fill tool name explicitly (e.g., include a command entry invoking
setToolActiveToolbar with toolName: 'RegionSegmentPlusFloodFill' or set the
value to 'RegionSegmentPlusFloodFill') so activation targets the registered
tool; locate the button definition (id: 'RegionSegmentPlus') in
modes/segmentation/src/toolbarButtons.ts and modify the commands element to
supply the explicit tool name when calling setToolActiveToolbar.

---

Nitpick comments:
In `@playwright.config.ts`:
- Around line 3-4: E2E_PORT is set using Number(...) without validation which
can produce NaN for bad env values; replicate the utility script's validation:
read process.env.OHIF_PORT, if present parse it as an integer (base 10), ensure
it's an integer between 1 and 65535, and if invalid throw a descriptive Error
stating the invalid OHIF_PORT value and expected range; if not present, use the
default 3335. Then set E2E_PORT and E2E_BASE_URL using the validated integer.
Reference the constants E2E_PORT and E2E_BASE_URL and mirror the validation
behavior from free-ohif-e2e-port.mjs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 936c80e0-989f-4e34-b998-c88d30ba5898

📥 Commits

Reviewing files that changed from the base of the PR and between 571c2b4 and 6a4ebe3.

📒 Files selected for processing (7)
  • .github/workflows/playwright.yml
  • .scripts/ci/free-ohif-e2e-port.mjs
  • extensions/cornerstone/src/commandsModule.ts
  • extensions/cornerstone/src/initCornerstoneTools.js
  • modes/segmentation/src/initToolGroups.ts
  • modes/segmentation/src/toolbarButtons.ts
  • playwright.config.ts

Comment thread extensions/cornerstone/src/commandsModule.ts
…anch

Squash of origin/feat/ohifpnpm2 (#6031) which converts the
monorepo build to pnpm + Rspack, node >=24, and adds the cs3d:* dev
helper scripts. Brought in onto fix/grow-cut-suv-pt ahead of the same
squash landing on origin/master.

Conflict in playwright.config.ts resolved by keeping the grow-cut
branch's CI port-cleanup wrapper (free-ohif-e2e-port.mjs) and parametrized
E2E_PORT/E2E_BASE_URL, while switching the underlying webServer command to
the pnpm/rspack invocation from the pnpm branch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/playwright.yml (1)

113-114: ⚠️ Potential issue | 🟠 Major

Fix Windows port cleanup to avoid substring-matching other ports.

Free OHIF e2e port (stale self-hosted processes) runs .scripts/ci/free-ohif-e2e-port.mjs before Playwright tests. On win32, the script uses netstat -ano | findstr :${port} | findstr LISTENING, which matches substrings (e.g., :3335 can also match :33350) and can kill unrelated listener processes on the runner.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/playwright.yml around lines 113 - 114, The Windows
port-cleanup is using netstat + findstr with a substring match (in
.scripts/ci/free-ohif-e2e-port.mjs), which can match ports like 33350 when you
meant 3335; update the win32 branch to match the exact port: either replace the
netstat|findstr pipeline with a PowerShell query (Get-NetTCPConnection
-LocalPort <port> | Where-Object State -eq 'Listen' to get exact listeners and
their PIDs) or change the findstr invocation to a strict regex (e.g., findstr /R
/C:":<port>\\b" or include the trailing space/column delimiter) so only the
exact port is matched before killing processes (adjust logic in the function
that builds the command in free-ohif-e2e-port.mjs).
platform/app/package.json (1)

4-4: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Duplicate productVersion key in JSON.

productVersion appears at both line 4 and line 103. JSON parsers will use the last occurrence, but this duplication is likely unintentional and confusing. Remove the duplicate at line 103.

   "tailwindcss": "3.2.4"
   },
-  "productVersion": "3.4.0",
   "proxy": "http://localhost:8042"
 }

Also applies to: 103-103

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@platform/app/package.json` at line 4, Remove the duplicate JSON key by
deleting the later occurrence of "productVersion" so only a single
"productVersion": "3.4.0" remains; locate the duplicate key named
"productVersion" (the second occurrence near the end of the file) and remove
that entry, then validate the package.json syntax (e.g., with JSON lint or npm
pack) to ensure no trailing commas or structural errors remain.
🧹 Nitpick comments (4)
platform/docs/docs/platform/modes/index.md (1)

454-459: ⚡ Quick win

Clarify "generating modes with an agent".

The note mentions the CLI "is being phased out in favour of generating modes with an agent" but doesn't specify which agent or link to documentation. Users reading this may not understand what "agent" means in this context (AI agent? build agent? custom tooling?). Consider adding a link or brief explanation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@platform/docs/docs/platform/modes/index.md` around lines 454 - 459, The note
in the "modes" documentation uses the ambiguous phrase "generating modes with an
agent" without specifying which agent or linking to relevant docs; update the
note in the index.md "modes" section to clarify what "agent" means (e.g.,
specify "AI agent", "automation agent", or the specific tool name) and add a
short parenthetical explanation plus a link to the appropriate documentation or
README for the agent (or to the development/agents page) so readers know which
agent to use and where to find usage/installation instructions; keep the
existing mention of the CLI but indicate it is being phased out in favor of the
named agent.
tests/SegmentationPanel.spec.ts (1)

23-29: ⚡ Quick win

Keep segment-count assertions on the page-object API.

Please switch these back to await panel.getSegmentCount() plus expect(count).toBe(...) rather than asserting on panel.rows directly. This project already standardized on the page-object count helper for segmentation tests, so bypassing it here makes the suite less consistent and harder to evolve if the underlying locator changes.

Based on learnings: "In OHIF/Viewers Playwright tests, prefer asserting segment counts via the relevant page object’s getSegmentCount() method ... Do not suggest replacing these getSegmentCount() + expect(...).toBe(...) assertions with Playwright locator-based expect(locator).toHaveCount(n) for this project."

Also applies to: 40-41

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/SegmentationPanel.spec.ts` around lines 23 - 29, Replace direct locator
count assertions on panel.rows with the page-object API: call
panel.getSegmentCount() and assert using expect(count).toBe(expected).
Specifically, change the two places where the test uses await
expect(panel.rows).toHaveCount(1) (and the similar assertion at lines 40-41) to
use const count = await panel.getSegmentCount(); await expect(count).toBe(1) (or
expect(count).toBe(...)), while keeping the segment text check via
panel.nthSegment(0).locator; this preserves the standardized page-object
abstraction (panel.getSegmentCount, panel.nthSegment).

Source: Learnings

extensions/measurement-tracking/package.json (2)

42-42: 💤 Low value

webpack-merge is declared in both peerDependencies and devDependencies.

This duplication is redundant. If it's needed for build configuration, keeping it only in devDependencies is sufficient for development, and it doesn't need to be a peer dependency unless external consumers must provide it.

   "peerDependencies": {
     ...
     "react-dom": "18.3.1",
-    "webpack-merge": "5.10.0"
   },

Also applies to: 50-52

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extensions/measurement-tracking/package.json` at line 42, The package.json
declares "webpack-merge" in both peerDependencies and devDependencies which is
redundant; remove the duplicate entry from peerDependencies and keep
"webpack-merge" only in devDependencies (or vice-versa if you intentionally
require consumers to provide it) and update the peerDependencies block
accordingly; also check and remove the duplicate occurrences referenced around
the other reported lines (50-52) so "webpack-merge" appears only once in the
manifest.

35-35: 💤 Low value

@ohif/ui is declared in both peerDependencies and dependencies.

Having the same package in both sections creates ambiguity about resolution. Typically, if it's a peer dependency, it should not also be in direct dependencies. Consider removing it from one section (likely dependencies if the consuming app is expected to provide it).

   "dependencies": {
     "`@babel/runtime`": "7.29.7",
-    "`@ohif/ui`": "workspace:*",
     "`@xstate/react`": "3.2.2",
     "xstate": "4.38.3"
   },

Also applies to: 44-49

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extensions/measurement-tracking/package.json` at line 35, The package.json
currently lists "`@ohif/ui`" in both dependencies and peerDependencies which
causes ambiguity; remove the duplicate by keeping it only in peerDependencies
(so the host app provides it) and delete the "`@ohif/ui`" entry from dependencies
(also remove any duplicate entries around lines 44-49 mentioned in the review)
to ensure a single source of truth for resolution.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-docs.yml:
- Line 81: The gh run download step uses the unvalidated expression `${{
steps.find_pr_run.outputs.run_id }}` which could be abused if its format
changes; fix by validating that `steps.find_pr_run.outputs.run_id` contains only
digits before invoking `gh run download` (e.g., add a prior step that checks
`/^\d+$/` and fails if not) and then use the validated value (or a sanitized
output variable) in the `gh run download` command (also wrap the injected value
in quotes or pass it via a safe flag) so the `run_id` is guaranteed numeric and
cannot be used for command injection.

In `@extensions/cornerstone-dicom-sr/package.json`:
- Around line 23-25: The dev script in modes/segmentation's package.json calls
rspack with .webpack/webpack.dev.js but that file is missing; add a
.webpack/webpack.dev.js for modes/segmentation (or change the dev script) so the
dev build works. Fix by creating modes/segmentation/.webpack/webpack.dev.js that
mirrors the pattern used in extensions/cornerstone-dicom-sr and
modes/usAnnotation: require or import the shared .webpack/webpack.base.js, set
mode to "development" and export the config (ensuring compatibility with
`@rspack/core`), or alternatively change the dev script to point to the existing
.webpack/webpack.prod.js if that is intentional.

In `@modes/tmtv/package.json`:
- Around line 31-38: The peerDependencies block in modes/tmtv/package.json (and
likewise in extensions/cornerstone/package.json) currently uses monorepo-only
"workspace:*" ranges for entries like "`@ohif/core`",
"`@ohif/extension-cornerstone`", "`@ohif/extension-default`", etc.; replace every
"workspace:*" with an appropriate semver range (e.g. ^<version> or a range
matching the published package versions) so the published package exposes real
semver peer ranges; ensure you update each dependency key in the
"peerDependencies" object to the chosen semver (matching the root/monorepo
published versions) and run npm pack / npm publish dry-run to verify no
workspace protocol remains.

In `@platform/cli/src/commands/utils/getYarnInfo.js`:
- Around line 4-5: getYarnInfo currently returns JSON.parse(stdout) directly
from execa('npm', ['info', packageName, '--json']) which can be either an object
or an array; normalize the parsed result to preserve the previous return shape
by detecting if the parsed value is an array and selecting the appropriate
element (e.g., first item or the one matching packageName) or converting an
array into a single object with expected fields (peerDependencies, version,
etc.), and ensure getYarnInfo always returns an object with those fields; update
getYarnInfo to handle null/undefined stdout and throw or return a consistent
empty shape, and add a small unit test that simulates npm info returning both an
object and an array for the same package spec to assert the normalized shape is
returned.

In `@platform/core/package.json`:
- Line 21: The package.json currently sets "sideEffects" as a string ("false")
which can be misinterpreted by bundlers; change the value to the boolean false
(i.e., sideEffects: false) in the package.json so bundlers correctly treat the
package as side-effect-free and enable proper tree-shaking, ensuring the JSON
remains valid.

In `@platform/docs/docs/migration-guide/3p12-to-3p13/node-version.md`:
- Line 59: Update the CI reference line to use the proper product name and
capitalization: replace the lowercase "GitHub" occurrence in the phrase "CI
config (`.github/workflows/*`, `.circleci/config.yml`, " with the correctly
capitalized product name "GitHub Actions" so the line reads something like "CI
config (GitHub Actions `.github/workflows/*`, `.circleci/config.yml`, ..."
ensuring consistent capitalization and explicit mention of "GitHub Actions".
- Line 25: The doc string in node-version.md lists the pnpm engine as "pnpm":
"11.1.1" but templates now declare "pnpm": ">=11" in dependencies.json; update
node-version.md to match the generated manifest (change the documented pnpm
requirement to ">=11" or otherwise mirror the exact engine string used in
platform/cli/templates/mode/dependencies.json) and check the other occurrences
noted (lines 56–58) for the same mismatch so the documentation and template stay
consistent.

In `@platform/docs/docs/migration-guide/3p12-to-3p13/package-manager.md`:
- Around line 156-162: The package.json script examples contain malformed pnpm
invocations: update the script values for "dev:my-extension" and "start" from
"pnpm rundev" to "pnpm run dev", and update "build:package" from "pnpm runbuild"
to "pnpm run build" so the "pnpm run <script>" form is used correctly (look for
the "dev:my-extension", "build:package", and "start" entries to locate and fix
the strings).

In `@platform/ui-next/package.json`:
- Around line 9-17: The package.json currently exposes subpath exports (e.g.,
"./tailwind.config", "./lib/*", "./components/*", ".") that point at source
files (tailwind.config.js and src/**) but the "files" array only includes "dist"
and "README.md", causing published consumers to miss those exported paths; fix
by updating the "exports" entries to reference built outputs under dist (for
example change "./tailwind.config" and the "./lib/*" and "./components/*"
mappings to point at the corresponding files in dist) or alternatively add
"tailwind.config.js" and the relevant "src" paths to the "files" array so those
exported subpaths are included in the package. Ensure changes touch the
package.json keys "exports" and/or "files" so exports and published content
align.

In `@platform/ui/package.json`:
- Line 13: Update the repo documentation to state Node 24 is the new supported
baseline: make sure the package.json engines.node entry (engines.node) and
.node-version align with Node 24, then add a clear note in the README and
release notes/changelog indicating "Node >=24 (Node 24 LTS)" as the minimum
supported version, call out breaking compatibility with Node 18/20/22, and add a
short migration snippet (recommended upgrade steps and an nvm/snippet
suggestion) so consumers know how to upgrade; also mention where CI/Docker were
updated (CI node-version and Docker FROM node:24-slim) so readers understand the
change is repo-wide.

In `@publish-version.mjs`:
- Around line 88-95: The push of the tag (the execa call that currently runs
execa('git', ['push', 'origin', tagName'])) can fail if the remote already has
that tag because you only force the local tag (git tag -f) but not the remote
push; update the tag push to either include --force (execa('git', ['push',
'--force', 'origin', tagName'])) to match the local behavior or wrap the
existing execa call in a try/catch and on failure delete the remote tag (git
push origin :refs/tags/<tagName> or git tag -d <tagName> remote deletion) then
retry pushing tagName; locate the occurrences of tagName and branchName and the
execa('git', ...) calls to implement the change.

In `@tests/pages/RightPanelPageObject.ts`:
- Around line 227-231: The `rows` locator and getSegmentCount use a global
page.getByTestId('data-row'), causing flaky counts; scope them to the
segmentation panel root instead. Define a segmentation-panel-scoped locator
(e.g., segmentationRoot = page.getByTestId('segmentation-panel') or the existing
segmentation panel locator) and replace occurrences so rows =
segmentationRoot.getByTestId('data-row'); update getSegmentCount and any helpers
that reference rows/index/text to reuse that scoped rows locator.

---

Outside diff comments:
In @.github/workflows/playwright.yml:
- Around line 113-114: The Windows port-cleanup is using netstat + findstr with
a substring match (in .scripts/ci/free-ohif-e2e-port.mjs), which can match ports
like 33350 when you meant 3335; update the win32 branch to match the exact port:
either replace the netstat|findstr pipeline with a PowerShell query
(Get-NetTCPConnection -LocalPort <port> | Where-Object State -eq 'Listen' to get
exact listeners and their PIDs) or change the findstr invocation to a strict
regex (e.g., findstr /R /C:":<port>\\b" or include the trailing space/column
delimiter) so only the exact port is matched before killing processes (adjust
logic in the function that builds the command in free-ohif-e2e-port.mjs).

In `@platform/app/package.json`:
- Line 4: Remove the duplicate JSON key by deleting the later occurrence of
"productVersion" so only a single "productVersion": "3.4.0" remains; locate the
duplicate key named "productVersion" (the second occurrence near the end of the
file) and remove that entry, then validate the package.json syntax (e.g., with
JSON lint or npm pack) to ensure no trailing commas or structural errors remain.

---

Nitpick comments:
In `@extensions/measurement-tracking/package.json`:
- Line 42: The package.json declares "webpack-merge" in both peerDependencies
and devDependencies which is redundant; remove the duplicate entry from
peerDependencies and keep "webpack-merge" only in devDependencies (or vice-versa
if you intentionally require consumers to provide it) and update the
peerDependencies block accordingly; also check and remove the duplicate
occurrences referenced around the other reported lines (50-52) so
"webpack-merge" appears only once in the manifest.
- Line 35: The package.json currently lists "`@ohif/ui`" in both dependencies and
peerDependencies which causes ambiguity; remove the duplicate by keeping it only
in peerDependencies (so the host app provides it) and delete the "`@ohif/ui`"
entry from dependencies (also remove any duplicate entries around lines 44-49
mentioned in the review) to ensure a single source of truth for resolution.

In `@platform/docs/docs/platform/modes/index.md`:
- Around line 454-459: The note in the "modes" documentation uses the ambiguous
phrase "generating modes with an agent" without specifying which agent or
linking to relevant docs; update the note in the index.md "modes" section to
clarify what "agent" means (e.g., specify "AI agent", "automation agent", or the
specific tool name) and add a short parenthetical explanation plus a link to the
appropriate documentation or README for the agent (or to the development/agents
page) so readers know which agent to use and where to find usage/installation
instructions; keep the existing mention of the CLI but indicate it is being
phased out in favor of the named agent.

In `@tests/SegmentationPanel.spec.ts`:
- Around line 23-29: Replace direct locator count assertions on panel.rows with
the page-object API: call panel.getSegmentCount() and assert using
expect(count).toBe(expected). Specifically, change the two places where the test
uses await expect(panel.rows).toHaveCount(1) (and the similar assertion at lines
40-41) to use const count = await panel.getSegmentCount(); await
expect(count).toBe(1) (or expect(count).toBe(...)), while keeping the segment
text check via panel.nthSegment(0).locator; this preserves the standardized
page-object abstraction (panel.getSegmentCount, panel.nthSegment).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 24d573f6-1c2d-43d0-aa22-d8df0d4590c6

📥 Commits

Reviewing files that changed from the base of the PR and between 6a4ebe3 and 5f49a51.

⛔ Files ignored due to path filters (42)
  • .webpack/resolveConfig.js is excluded by !**/.webpack/**
  • .webpack/rules/cssToJavaScript.js is excluded by !**/.webpack/**
  • .webpack/rules/transpileJavaScript.js is excluded by !**/.webpack/**
  • .webpack/webpack.base.js is excluded by !**/.webpack/**
  • bun.lock is excluded by !**/*.lock
  • extensions/cornerstone-dicom-pmap/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • extensions/cornerstone-dicom-rt/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • extensions/cornerstone-dicom-seg/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • extensions/cornerstone-dicom-sr/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • extensions/cornerstone-dynamic-volume/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • extensions/cornerstone/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • extensions/default/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • extensions/dicom-microscopy/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • extensions/dicom-pdf/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • extensions/dicom-video/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • extensions/measurement-tracking/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • extensions/test-extension/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • extensions/tmtv/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • extensions/usAnnotation/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • modes/basic-dev-mode/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • modes/basic-test-mode/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • modes/basic/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • modes/longitudinal/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • modes/microscopy/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • modes/preclinical-4d/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • modes/segmentation/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • modes/tmtv/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • modes/usAnnotation/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • platform/app/.webpack/rules/extractStyleChunks.js is excluded by !**/.webpack/**
  • platform/app/.webpack/webpack.pwa.js is excluded by !**/.webpack/**
  • platform/app/.webpack/writePluginImportsFile.js is excluded by !**/.webpack/**
  • platform/cli/templates/extension/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • platform/cli/templates/mode/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • platform/core/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • platform/docs/bun.lockb is excluded by !**/bun.lockb
  • platform/docs/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
  • platform/i18n/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • platform/ui-next/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • platform/ui/.webpack/webpack.prod.js is excluded by !**/.webpack/**
  • platform/ui/a34f9d1faa5f3315.woff2 is excluded by !**/*.woff2
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (84)
  • .circleci/config.yml
  • .github/.dependabot.yaml
  • .github/workflows/build-docs.yml
  • .github/workflows/codeql.yml
  • .github/workflows/playwright.yml
  • .gitignore
  • .netlify/build-deploy-preview.sh
  • .netlify/package.json
  • .node-version
  • .npmrc
  • .scripts/dev.sh
  • Dockerfile
  • addOns/README.md
  • addOns/externals/devDependencies/CHANGELOG.md
  • addOns/externals/devDependencies/package.json
  • addOns/externals/dicom-microscopy-viewer/CHANGELOG.md
  • addOns/externals/dicom-microscopy-viewer/package.json
  • addOns/package.json
  • bunfig.toml
  • bunfig.update-lockfile.toml
  • extensions/cornerstone-dicom-pmap/package.json
  • extensions/cornerstone-dicom-rt/package.json
  • extensions/cornerstone-dicom-seg/package.json
  • extensions/cornerstone-dicom-sr/package.json
  • extensions/cornerstone-dynamic-volume/package.json
  • extensions/cornerstone/package.json
  • extensions/default/package.json
  • extensions/default/src/ViewerLayout/index.tsx
  • extensions/dicom-microscopy/package.json
  • extensions/dicom-pdf/package.json
  • extensions/dicom-video/package.json
  • extensions/measurement-tracking/package.json
  • extensions/test-extension/package.json
  • extensions/tmtv/package.json
  • extensions/usAnnotation/package.json
  • lerna.json
  • modes/basic-dev-mode/package.json
  • modes/basic-test-mode/package.json
  • modes/basic/package.json
  • modes/longitudinal/package.json
  • modes/microscopy/package.json
  • modes/preclinical-4d/package.json
  • modes/segmentation/package.json
  • modes/tmtv/package.json
  • modes/usAnnotation/package.json
  • netlify-lerna-cache.sh
  • netlify-lerna-restore.sh
  • netlify.toml
  • nx.json
  • package.json
  • platform/app/cypress.config.ts
  • platform/app/cypress/integration/measurement-tracking/OHIFSaveMeasurements.spec.js
  • platform/app/cypress/support/commands.js
  • platform/app/package.json
  • platform/app/tailwind.config.js
  • platform/cli/package.json
  • platform/cli/src/commands/createPackage.js
  • platform/cli/src/commands/utils/getYarnInfo.js
  • platform/cli/src/commands/utils/uninstallNPMPackage.js
  • platform/cli/src/index.js
  • platform/cli/templates/extension/dependencies.json
  • platform/cli/templates/mode/dependencies.json
  • platform/core/package.json
  • platform/docs/docs/migration-guide/3p12-to-3p13/build-tooling.md
  • platform/docs/docs/migration-guide/3p12-to-3p13/index.md
  • platform/docs/docs/migration-guide/3p12-to-3p13/node-version.md
  • platform/docs/docs/migration-guide/3p12-to-3p13/package-manager.md
  • platform/docs/docs/platform/extensions/index.md
  • platform/docs/docs/platform/extensions/pluginConfig.md
  • platform/docs/docs/platform/modes/index.md
  • platform/docs/package.json
  • platform/i18n/package.json
  • platform/ui-next/package.json
  • platform/ui/package.json
  • playwright.config.ts
  • pnpm-workspace.yaml
  • publish-package.mjs
  • publish-version.mjs
  • rsbuild.config.ts
  • tests/FreehandROI.spec.ts
  • tests/SegmentationPanel.spec.ts
  • tests/globalSetup.ts
  • tests/pages/RightPanelPageObject.ts
  • version.mjs
💤 Files with no reviewable changes (11)
  • addOns/package.json
  • nx.json
  • netlify-lerna-cache.sh
  • addOns/externals/dicom-microscopy-viewer/package.json
  • addOns/README.md
  • platform/app/cypress/integration/measurement-tracking/OHIFSaveMeasurements.spec.js
  • lerna.json
  • bunfig.toml
  • netlify-lerna-restore.sh
  • addOns/externals/devDependencies/package.json
  • bunfig.update-lockfile.toml
✅ Files skipped from review due to trivial changes (6)
  • .netlify/package.json
  • .npmrc
  • platform/docs/docs/migration-guide/3p12-to-3p13/index.md
  • platform/docs/docs/platform/extensions/index.md
  • platform/docs/docs/platform/extensions/pluginConfig.md
  • platform/docs/docs/migration-guide/3p12-to-3p13/build-tooling.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • playwright.config.ts

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate run_id format to prevent potential command injection.

The static analyzer flagged a potential template injection risk where ${{ steps.find_pr_run.outputs.run_id }} is used in the shell command. While run_id comes from GitHub's API (via gh run list) and should be a numeric database ID, it's best practice to validate or quote the variable to prevent any theoretical command injection if the output format changes.

🛡️ Recommended fix to add validation or quoting
       - name: Download coverage artifact from PR run
         if: steps.find_pr_run.outputs.coverage_found == 'true'
         env:
           GH_TOKEN: ${{ github.token }}
         run: |
+          RUN_ID="${{ steps.find_pr_run.outputs.run_id }}"
+          # Validate run_id is numeric
+          if ! [[ "$RUN_ID" =~ ^[0-9]+$ ]]; then
+            echo "Invalid run_id format: $RUN_ID"
+            exit 1
+          fi
           mkdir -p ./coverage-artifact
-          gh run download ${{ steps.find_pr_run.outputs.run_id }} -n coverage-report-pr --dir ./coverage-artifact
+          gh run download "$RUN_ID" -n coverage-report-pr --dir ./coverage-artifact
🧰 Tools
🪛 zizmor (1.25.2)

[info] 81-81: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-docs.yml at line 81, The gh run download step uses
the unvalidated expression `${{ steps.find_pr_run.outputs.run_id }}` which could
be abused if its format changes; fix by validating that
`steps.find_pr_run.outputs.run_id` contains only digits before invoking `gh run
download` (e.g., add a prior step that checks `/^\d+$/` and fails if not) and
then use the validated value (or a sanitized output variable) in the `gh run
download` command (also wrap the injected value in quotes or pass it via a safe
flag) so the `run_id` is guaranteed numeric and cannot be used for command
injection.

Comment thread extensions/cornerstone-dicom-sr/package.json
Comment thread modes/tmtv/package.json
Comment thread platform/cli/src/commands/utils/getYarnInfo.js
Comment thread platform/core/package.json
Comment thread platform/docs/docs/migration-guide/3p12-to-3p13/package-manager.md
Comment thread platform/ui-next/package.json
Comment thread platform/ui/package.json
Comment thread publish-version.mjs
Comment thread tests/pages/RightPanelPageObject.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ohif-integration Causes a CS3D/OHIF integraiton build to be run

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant