Skip to content

fix: Add display set split/store logic to metadata#2738

Open
wayfarer3130 wants to merge 9 commits into
mainfrom
fix/dwi-wrong-wl-split
Open

fix: Add display set split/store logic to metadata#2738
wayfarer3130 wants to merge 9 commits into
mainfrom
fix/dwi-wrong-wl-split

Conversation

@wayfarer3130

@wayfarer3130 wayfarer3130 commented May 19, 2026

Copy link
Copy Markdown
Collaborator

OHIF_REF: ohifohifupdateplaywightimgaes

Context

Changes & Results

Testing

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
    • Added display set mounting API to all viewport types (Stack, Volume, Video, ECG, WSI) for unified data loading.
    • Introduced display set metadata module for tracking and managing grouped DICOM series.
    • Added display set utilities for creating and splitting series into organized display sets.
    • Updated examples to demonstrate display set–based workflow for video, 4D volumes, and mixed-modality series.

@claude claude 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.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai

coderabbitai Bot commented Jun 8, 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: d3a618a7-7614-4139-9f34-640910850bdd

📥 Commits

Reviewing files that changed from the base of the PR and between 318f3ae and 71d2a3c.

📒 Files selected for processing (1)
  • packages/metadata/src/displayset/displayset.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/metadata/src/displayset/displayset.test.ts

📝 Walkthrough

Walkthrough

This PR introduces display-set metadata contracts for grouping DICOM series instances, implements split-rule-driven grouping, registers the metadata provider, adds viewport APIs for mounting display sets, builds demo helpers for display-set selection, and migrates multiple core and tools examples to use the new display-set-based flow alongside dynamic viewport type selection.

Changes

Display set metadata, viewport APIs, and example migration

Layer / File(s) Summary
Display set contracts, models, and modality helpers
packages/metadata/src/displayset/IDisplaySet.ts, packages/metadata/src/displayset/types.ts, packages/metadata/src/displayset/BaseDisplaySet.ts, packages/metadata/src/displayset/ImageStackDisplaySet.ts, packages/metadata/src/displayset/viewportTypes.ts, packages/metadata/src/displayset/isImageSopClass.ts, packages/metadata/src/displayset/isVideoInstance.ts, packages/metadata/src/displayset/isWsiInstance.ts, packages/metadata/src/displayset/isEcgInstance.ts
IDisplaySet interface defines required display-set metadata (instance UID, viewport type hints, instances, frame-level and SOP-level imageIds) plus optional multi-frame attributes. BaseDisplaySet implements this contract with deduplication and defaults. ImageStackDisplaySet extends BaseDisplaySet with helper factories (fromInstances, fromImageIds) and multiframe detection. Type definitions and instance-type guards provide modality detection (image, video, ECG, WSI).
Split/group pipeline and display-set creation
packages/metadata/src/displayset/resolveInstances.ts, packages/metadata/src/displayset/buildSeriesInfo.ts, packages/metadata/src/displayset/defaultDisplaySetSplitRules.ts, packages/metadata/src/displayset/groupInstancesBySplitRules.ts, packages/metadata/src/displayset/splitSeriesInstanceGroupsFromImageIds.ts, packages/metadata/src/displayset/createDisplaySetFromGroup.ts, packages/metadata/src/displayset/displayset.test.ts
resolveInstances maps imageIds to instances with configurable missing-id handling. buildSeriesInfo aggregates frame and object counts. defaultDisplaySetSplitRules defines ordered rules matching video, ECG, WSI, single-image, multiframe, mixed-B-value MR, and volumetric instances. groupInstancesBySplitRules assigns instances to matching rules and groups by computed split keys. splitSeriesInstanceGroupsFromImageIds orchestrates the pipeline. createDisplaySetFromGroup applies rule-driven custom attributes and selects appropriate display-set constructor. Comprehensive test suite validates split logic and viewport type selection.
Metadata module wiring, exports, and docs
packages/metadata/src/displayset/registerDisplaySetMetadata.ts, packages/metadata/src/displayset/displaySetProvider.ts, packages/metadata/src/enums/MetadataModules.ts, packages/metadata/src/types/MetadataModuleTypes.ts, packages/metadata/src/displayset/index.ts, packages/metadata/src/index.ts, packages/metadata/src/utilities/index.ts, packages/metadata/src/registerDefaultProviders.ts, packages/metadata/jest.config.js, packages/metadata/package.json, packages/docs/docs/concepts/cornerstone-metadata/index.md
registerDisplaySetMetadata registers display sets per imageId in the metadata cache. displaySetProvider initializes the metadata add-provider. MetadataModules enum gains DISPLAY_SET entry. MetadataModuleType interface includes displaySetModule. Barrel exports expose contracts, factories, split logic, helpers, and registration APIs. registerDefaultProviders calls display-set provider registration. Jest config and npm scripts enable package-level test discovery. Documentation section explains display-set attributes and augmentation patterns.
Viewport setDisplaySets support across viewport types
packages/core/src/RenderingEngine/Viewport.ts, packages/core/src/RenderingEngine/StackViewport.ts, packages/core/src/RenderingEngine/BaseVolumeViewport.ts, packages/core/src/RenderingEngine/VideoViewport.ts, packages/core/src/RenderingEngine/ECGViewport.ts, packages/core/src/RenderingEngine/WSIViewport.ts
Base Viewport class adds _displaySets field, setDisplaySets/getDisplaySets/clearDisplaySets methods for bookkeeping. setStack clears display sets before mounting. StackViewport.setDisplaySets resolves displaySetId to imageIds and delegates to setStack. BaseVolumeViewport.setDisplaySets resolves dataset, creates/caches volume, and loads it. VideoViewport.setDisplaySets resolves to video id and calls setVideo. ECGViewport.setDisplaySets resolves to ECG id and calls setEcg. WSIViewport.setDisplaySets resolves to WSI dataset with DICOMweb client and calls setWSI. All implementations call parent setDisplaySets to record mounted entries.
Demo helper library for display-set splitting and 4D selection
utils/demo/helpers/splitDisplaySetsFromImageIds.ts, utils/demo/helpers/index.js
getViewportTypeForDisplaySet maps preferred viewport hints to Cornerstone viewport types. getNaturalizedInstanceForDisplaySetSplit reads instance metadata and normalizes imageIds. splitDisplaySetsFromImageIds deduplicates at SOP level, groups via split rules, and creates display sets with filtered frame imageIds. createDisplaySets wraps metadata creation and splitting. Helper functions select video, primary stack, and volume frame imageIds with fallbacks. get4DDimensionGroupImageIds splits volume frames into DICOM dimension groups; get4DVolumeImageIds flattens and slices by group range or count. All helpers re-exported from index module.
New display sets showcase example
packages/core/examples/displaySets/index.ts
Comprehensive example loading series into display sets, registering per-hint source data (stack, video, ECG, whole-slide), building one viewport per display set with dropdown to switch viewport types, applying CT presets and video playback, and rendering per-row metadata and error messages. Demonstrates all major display-set mounting paths.
Example migrations to display-set and helper-based mounting
packages/core/examples/video/index.ts, packages/core/examples/dynamicVolume/index.ts, packages/tools/examples/dynamicCINETool/index.ts, packages/tools/examples/generateImageFromTimeData/index.ts, packages/tools/examples/localAdvanced/index.ts, packages/tools/examples/videoColor/index.ts, packages/tools/examples/videoContourSegmentation/index.ts, packages/tools/examples/videoGroup/index.ts, packages/tools/examples/videoNavigation/index.ts, packages/tools/examples/videoRange/index.ts, packages/tools/examples/videoSegmentation/index.ts, packages/tools/examples/videoSplineROITools/index.ts, packages/tools/examples/videoTools/index.ts, utils/ExampleRunner/example-runner-cli.js
Core and tools video examples now call createDisplaySets, select appropriate display sets, use getViewportTypeForDisplaySet for dynamic viewport type selection, and mount via viewport.setDisplaySets instead of direct setVideo. Dynamic volume and 4D examples use get4DVolumeImageIds instead of manual instance-number filtering. Dynamic CINE tool delegates dimension-group selection to get4DVolumeImageIds. Local advanced example uses getPrimaryStackFrameImageIds for stack frame selection. Example runner uses platform-aware shell handling for rspack subprocess. All helpers imported from updated demo helpers module.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Display sets bloom like carrots in rows,
Each viewport displays what the hint-map shows,
From video to stack, the pipeline flows clear,
Metadata grouped, and the frame IDs appear!
Four-dee dimension groups slice and align—
One rabbit's triumph, a schema so fine! 🥕✨

✨ 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/dwi-wrong-wl-split

@wayfarer3130 wayfarer3130 changed the base branch from main to beta June 8, 2026 17:41
@wayfarer3130 wayfarer3130 force-pushed the fix/dwi-wrong-wl-split branch from 0c48d0c to 5cfd79a Compare June 8, 2026 19:20
@wayfarer3130 wayfarer3130 changed the base branch from beta to main June 8, 2026 19:21
@wayfarer3130 wayfarer3130 changed the title [WIP] fix: Add display set split/store logic to metadata fix: Add display set split/store logic to metadata Jun 8, 2026
Comment thread packages/core/examples/displaySets/index.ts Dismissed

@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

🧹 Nitpick comments (5)
packages/core/examples/displaySets/index.ts (1)

225-231: ⚡ Quick win

Validate viewport type before casting.

Lines 227 and 230 cast viewport to specific types without runtime validation. If enableElement silently failed or returned an unexpected viewport type, the casts would succeed but method calls could throw at runtime.

♻️ Suggested defensive check
     if (row.hint === 'volume3d') {
       // 3D needs a preset to be visible; setDisplaySets already loaded the volume.
-      (viewport as Types.IVolumeViewport).setProperties({ preset: 'CT-Bone' });
+      if ('setProperties' in viewport) {
+        (viewport as Types.IVolumeViewport).setProperties({ preset: 'CT-Bone' });
+      }
     }
     if (row.hint === 'video') {
-      (viewport as Types.IVideoViewport).play();
+      if ('play' in viewport) {
+        (viewport as Types.IVideoViewport).play();
+      }
     }
🤖 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 `@packages/core/examples/displaySets/index.ts` around lines 225 - 231, The code
casts viewport to Types.IVolumeViewport and Types.IVideoViewport and calls
setProperties/play without runtime checks, which can throw if enableElement
returned a different viewport; update the branches handling row.hint ===
'volume3d' and 'video' to first validate the viewport type (e.g., check for
presence of expected methods/properties such as setProperties for volume and
play for video or use a type guard) before casting and calling setProperties or
play on the viewport instance to safely bail or log an error if the viewport is
not the expected type.
packages/metadata/src/displayset/ImageStackDisplaySet.ts (1)

13-37: 💤 Low value

Consider refactoring to eliminate code duplication.

The loops in collectUnderlyingImageIds (lines 15-19) and collectImageIds (lines 28-32) perform identical operations: iterating instances and collecting instance.imageId values. collectImageIds could delegate to collectUnderlyingImageIds and only handle the fallback logic.

♻️ Proposed refactor
 function collectImageIds(
   instances: NaturalizedInstance[],
   underlyingImageIds: string[]
 ): string[] {
-  const imageIds: string[] = [];
-  for (const instance of instances) {
-    if (instance.imageId) {
-      imageIds.push(instance.imageId);
-    }
-  }
+  const imageIds = collectUnderlyingImageIds(instances);
   if (imageIds.length === 0) {
     return [...underlyingImageIds];
   }
   return imageIds;
 }
🤖 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 `@packages/metadata/src/displayset/ImageStackDisplaySet.ts` around lines 13 -
37, Duplicate loops collectUnderlyingImageIds and collectImageIds both iterate
instances to gather instance.imageId; refactor by making collectImageIds call
collectUnderlyingImageIds(instances) to get imageIds, then if that result is
empty return [...underlyingImageIds] else return the collected ids;
update/remove the duplicated loop in collectImageIds and keep
collectUnderlyingImageIds as the single source of truth (refer to functions
collectUnderlyingImageIds and collectImageIds).
packages/metadata/src/displayset/displaySetProvider.ts (1)

5-11: ⚡ Quick win

Add type annotations to provider function parameters.

The displaySetAddProvider function has untyped parameters (next, _data, options). Adding type annotations would improve type safety and IDE autocomplete support.

🔧 Suggested typing improvement
-function displaySetAddProvider(next, query: string, _data, options) {
+function displaySetAddProvider(
+  next: (...args: unknown[]) => unknown,
+  query: string,
+  _data: unknown,
+  options?: { displaySet?: unknown }
+) {
   const displaySet = options?.displaySet;
   if (displaySet) {
     return displaySet;
   }
   return next(query, _data, options);
 }
🤖 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 `@packages/metadata/src/displayset/displaySetProvider.ts` around lines 5 - 11,
The provider function displaySetAddProvider should have explicit TypeScript
types added for its parameters: annotate next as a function type (e.g. (query:
string, data?: unknown, options?: DisplayOptions) => DisplaySetType) so callers
and returns are typed, type _data as unknown or a more specific payload type
used by callers, and type options as an interface with an optional displaySet?:
DisplaySetType (or use the existing DisplaySet/DisplayOptions types in the
codebase). Update the function signature of displaySetAddProvider to use these
types and import or declare DisplaySetType/DisplayOptions as needed so tooling
and autocomplete pick up the shapes of next, _data, and options.
packages/metadata/package.json (1)

1-1: Pipeline failures are unrelated CI configuration issues.

The reported pipeline failures concern a pnpm version conflict between packageManager (pnpm@11.5.2) and GitHub Action configuration (11.4.0). This is a CI/workflow configuration issue outside the scope of the code changes in this file. The packageManager field is not modified in this diff and likely resides in the repository root package.json or workflow files.

🤖 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 `@packages/metadata/package.json` at line 1, CI failures are caused by a pnpm
version mismatch between the repository/packageManager field and the GitHub
Actions workflow; do not change packages/metadata/package.json in this PR—either
update the workflow action that installs pnpm to use pnpm@11.5.2 (matching the
packageManager field) or update the root package.json packageManager field to
the version used by the workflow so they align; look for the packageManager
field in the root package.json and the pnpm install step in your GitHub Actions
workflow to make the change.
packages/metadata/src/displayset/buildSeriesInfo.ts (1)

16-19: ⚡ Quick win

Validate NumberOfFrames before numeric conversion.

If NumberOfFrames contains a malformed string, Number() returns NaN, silently corrupting the numberOfFrames total. Consider using parseInt() with validation or explicitly checking for valid numeric values.

🛡️ Proposed validation
     if (instance.NumberOfFrames) {
-      numberOfFrames += Number(instance.NumberOfFrames);
+      const frames = parseInt(String(instance.NumberOfFrames), 10);
+      if (!isNaN(frames)) {
+        numberOfFrames += frames;
+      }
     } else if (instance.Rows) {
🤖 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 `@packages/metadata/src/displayset/buildSeriesInfo.ts` around lines 16 - 19,
The code adds instance.NumberOfFrames to numberOfFrames without validating it,
so malformed strings yield NaN; change the branch in buildSeriesInfo (the logic
that reads instance.NumberOfFrames) to validate and parse the value first (e.g.,
use parseInt or Number and then test with Number.isFinite / Number.isInteger or
isNaN) and only add the parsed numeric value to numberOfFrames when valid,
otherwise treat it as zero or log/skip the invalid value; reference the
variables instance.NumberOfFrames and numberOfFrames and the function/build
block in buildSeriesInfo.ts when making this change.
🤖 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 `@package.json`:
- Line 183: package.json declares "packageManager": "pnpm@11.5.2" but CI
workflows pin pnpm to 11.4.0 causing ERR_PNPM_BAD_PM_VERSION; update the pnpm
version pin in the referenced GitHub Actions workflows
(.github/workflows/validate-codemod-registry.yml, test.yml, playwright.yml,
format-check.yml, docusaurus-build.yml, build-docs.yml) and the PNPM_VERSION env
in ohif-downstream.yml to 11.5.2 (or remove explicit pnpm version pins so the
runner respects packageManager), or alternatively change the packageManager
value back to "pnpm@11.4.0" to keep CI consistent. Ensure you update all
occurrences of pnpm@11.4.0 and PNPM_VERSION to 11.5.2 (or remove pins) so pnpm
install --frozen-lockfile no longer errors.

In `@packages/core/examples/displaySets/index.ts`:
- Around line 180-193: The loop that builds the details rows uses line.innerHTML
= `<strong>${label}:</strong> ${value}` which injects untrusted DICOM metadata
into HTML; change this to create elements and set textContent to avoid HTML
parsing: for each (label, value) create a container div, create a <strong>
element and set its textContent to `${label}:`, append it to the container, then
append a text node or set the container.textContent (or append a text node for
value) using the string `value` (not innerHTML); also replace
statusLine.innerText with statusLine.textContent for consistency. Update the
code paths that reference row.detailsElement, the loop over lines, and the
statusLine creation to use textContent-safe methods.

In `@packages/core/src/RenderingEngine/BaseVolumeViewport.ts`:
- Around line 1511-1513: The code casts dataSet.volumeId to string without
checking type before calling resolveViewportVolumeId, which can hide non-string
values; update the logic in BaseVolumeViewport (around the
resolveViewportVolumeId call) to validate dataSet.volumeId is a string (e.g.,
typeof dataSet.volumeId === 'string' && dataSet.volumeId.length > 0) before
using it, otherwise fall back to entry.displaySetId; ensure the computed
volumeId passed into resolveViewportVolumeId is guaranteed to be a string or
null/undefined so downstream code can rely on its type.
- Around line 1515-1520: The volume is being created with
createAndCacheVolume(...) but volume.load() is not awaited, causing potential
race conditions when the viewport mounts; change the flow to await the load
(e.g., await volume.load()) before proceeding to any mounting or calling
setVolumes, and wrap the await in a try/catch to handle and log load errors so
failures don’t leave the cache in an inconsistent state (refer to
cache.getVolume, createAndCacheVolume, and volume.load).

In `@packages/core/src/RenderingEngine/StackViewport.ts`:
- Around line 1998-2004: The code uses dataSet.initialImageIdIndex directly and
can pass invalid values (NaN, negative, out-of-range, non-integer) into
setStack; before calling setStack, validate and clamp initialImageIdIndex: read
dataSet.initialImageIdIndex, coerce to a finite integer (e.g., via
Number.isFinite and Math.floor), default to 0 on invalid input, then clamp it to
the range 0 .. Math.max(0, dataSet.imageIds.length - 1); pass that sanitized
value to setStack instead of the raw value so setStack always receives a valid
index.

In `@packages/metadata/src/displayset/displayset.test.ts`:
- Around line 56-57: The test assertions are out of sync with the `volume3d`
rule in defaultDisplaySetSplitRules.ts which sets viewportTypes: ['volume',
'volume3d', 'stack'] (so the first element is 'volume'); update the test in
displayset.test.ts to assert expect(displaySet.viewportTypes[0]).toBe('volume')
and adjust expect(displaySet.preferredViewportType) to match the actual
preferredViewportType produced by the rule (or, if the intent was to prefer
'volume3d', change the rule in defaultDisplaySetSplitRules.ts where the
'volume3d' rule is defined so its viewportTypes order and preferredViewportType
reflect that intent).

In `@packages/metadata/src/displayset/ImageStackDisplaySet.ts`:
- Around line 85-102: ImageStackDisplaySet.fromImageIds currently drops
unresolved imageIds silently; modify it to surface missing-ID handling by either
routing through the existing resolveInstances utility or by adding
options.skipMissing?: boolean and options.onMissing?: (imageId: string) => void
to the fromImageIds signature, then use those options to call onMissing for each
undefined instance and throw or skip based on skipMissing before calling
ImageStackDisplaySet.fromInstances; reference the method name
ImageStackDisplaySet.fromImageIds, the helper resolveInstances, and the
downstream ImageStackDisplaySet.fromInstances so reviewers can locate the
change.

In `@packages/metadata/src/displayset/resolveInstances.ts`:
- Line 4: Update the doc comment for the skipMissing parameter in
resolveInstances (or the top-level comment in resolveInstances.ts) to accurately
state that when skipMissing is true missing ids are skipped silently, and when
skipMissing is false the function throws an error (with optional warning
behavior removed), rather than "omitted with optional warn"; reference the
skipMissing parameter name and the resolveInstances function so readers can find
the behavior.

In `@packages/tools/examples/videoNavigation/index.ts`:
- Around line 259-261: Ensure you check that displaySet.instances exists and has
at least one element before using displaySet.instances[0].imageId; update the
code around the call to viewport.setDisplaySets to validate (e.g., if
(!displaySet || !Array.isArray(displaySet.instances) ||
displaySet.instances.length === 0) then handle the empty case or skip calling
viewport.setDisplaySets) so you never access instances[0] on an empty array and
include a clear fallback or error handling path.

In `@packages/tools/examples/videoSegmentation/index.ts`:
- Around line 193-204: The code assumes displaySet.instances has elements when
deriving videoId; update the block after createDisplaySets to validate that
displaySet.instances is an array with length > 0 (and that instances[0].imageId
exists) before accessing instances[0].imageId; if the check fails, throw a clear
Error (e.g., "No instances found in display set") or handle the empty case, and
only assign videoId once the guard passes—apply this change around the
displaySets/displaySet/videoId usage to prevent runtime crashes.

In `@packages/tools/examples/videoSplineROITools/index.ts`:
- Around line 286-290: The code assumes displaySet.instances has at least one
element before accessing instances[0]; update the logic around the displaySet
extraction to validate that displaySet.instances is an array with length > 0 (or
at least one element) before reading displaySet.instances[0].imageId and
assigning videoId; if empty, throw a clear Error (e.g., "No instances found in
display set") or handle the empty-case appropriately so videoId is not accessed
from an empty array. Ensure references to displaySet.instances and the videoId
assignment are updated accordingly.

In `@packages/tools/examples/videoTools/index.ts`:
- Around line 179-183: The code assumes displaySet.instances has elements before
accessing instances[0]; update the block that sets videoId to first verify
displaySet.instances is an array with length > 0 (e.g., check
Array.isArray(displaySet.instances) && displaySet.instances.length > 0) and
throw a clear Error if empty, then safely read displaySet.instances[0].imageId
to set videoId; reference the existing variables displaySets, displaySet, and
videoId when making this change.

---

Nitpick comments:
In `@packages/core/examples/displaySets/index.ts`:
- Around line 225-231: The code casts viewport to Types.IVolumeViewport and
Types.IVideoViewport and calls setProperties/play without runtime checks, which
can throw if enableElement returned a different viewport; update the branches
handling row.hint === 'volume3d' and 'video' to first validate the viewport type
(e.g., check for presence of expected methods/properties such as setProperties
for volume and play for video or use a type guard) before casting and calling
setProperties or play on the viewport instance to safely bail or log an error if
the viewport is not the expected type.

In `@packages/metadata/package.json`:
- Line 1: CI failures are caused by a pnpm version mismatch between the
repository/packageManager field and the GitHub Actions workflow; do not change
packages/metadata/package.json in this PR—either update the workflow action that
installs pnpm to use pnpm@11.5.2 (matching the packageManager field) or update
the root package.json packageManager field to the version used by the workflow
so they align; look for the packageManager field in the root package.json and
the pnpm install step in your GitHub Actions workflow to make the change.

In `@packages/metadata/src/displayset/buildSeriesInfo.ts`:
- Around line 16-19: The code adds instance.NumberOfFrames to numberOfFrames
without validating it, so malformed strings yield NaN; change the branch in
buildSeriesInfo (the logic that reads instance.NumberOfFrames) to validate and
parse the value first (e.g., use parseInt or Number and then test with
Number.isFinite / Number.isInteger or isNaN) and only add the parsed numeric
value to numberOfFrames when valid, otherwise treat it as zero or log/skip the
invalid value; reference the variables instance.NumberOfFrames and
numberOfFrames and the function/build block in buildSeriesInfo.ts when making
this change.

In `@packages/metadata/src/displayset/displaySetProvider.ts`:
- Around line 5-11: The provider function displaySetAddProvider should have
explicit TypeScript types added for its parameters: annotate next as a function
type (e.g. (query: string, data?: unknown, options?: DisplayOptions) =>
DisplaySetType) so callers and returns are typed, type _data as unknown or a
more specific payload type used by callers, and type options as an interface
with an optional displaySet?: DisplaySetType (or use the existing
DisplaySet/DisplayOptions types in the codebase). Update the function signature
of displaySetAddProvider to use these types and import or declare
DisplaySetType/DisplayOptions as needed so tooling and autocomplete pick up the
shapes of next, _data, and options.

In `@packages/metadata/src/displayset/ImageStackDisplaySet.ts`:
- Around line 13-37: Duplicate loops collectUnderlyingImageIds and
collectImageIds both iterate instances to gather instance.imageId; refactor by
making collectImageIds call collectUnderlyingImageIds(instances) to get
imageIds, then if that result is empty return [...underlyingImageIds] else
return the collected ids; update/remove the duplicated loop in collectImageIds
and keep collectUnderlyingImageIds as the single source of truth (refer to
functions collectUnderlyingImageIds and collectImageIds).
🪄 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: d98b3480-8b3c-4da7-a312-0acc2575fc1f

📥 Commits

Reviewing files that changed from the base of the PR and between d6f3fba and 318f3ae.

📒 Files selected for processing (52)
  • package.json
  • packages/core/examples/displaySets/index.ts
  • packages/core/examples/dynamicVolume/index.ts
  • packages/core/examples/video/index.ts
  • packages/core/src/RenderingEngine/BaseVolumeViewport.ts
  • packages/core/src/RenderingEngine/ECGViewport.ts
  • packages/core/src/RenderingEngine/StackViewport.ts
  • packages/core/src/RenderingEngine/VideoViewport.ts
  • packages/core/src/RenderingEngine/Viewport.ts
  • packages/core/src/RenderingEngine/WSIViewport.ts
  • packages/docs/docs/concepts/cornerstone-metadata/index.md
  • packages/metadata/jest.config.js
  • packages/metadata/package.json
  • packages/metadata/src/displayset/BaseDisplaySet.ts
  • packages/metadata/src/displayset/IDisplaySet.ts
  • packages/metadata/src/displayset/ImageStackDisplaySet.ts
  • packages/metadata/src/displayset/buildSeriesInfo.ts
  • packages/metadata/src/displayset/createDisplaySetFromGroup.ts
  • packages/metadata/src/displayset/defaultDisplaySetSplitRules.ts
  • packages/metadata/src/displayset/displaySetProvider.ts
  • packages/metadata/src/displayset/displayset.test.ts
  • packages/metadata/src/displayset/groupInstancesBySplitRules.ts
  • packages/metadata/src/displayset/index.ts
  • packages/metadata/src/displayset/isEcgInstance.ts
  • packages/metadata/src/displayset/isImageSopClass.ts
  • packages/metadata/src/displayset/isVideoInstance.ts
  • packages/metadata/src/displayset/isWsiInstance.ts
  • packages/metadata/src/displayset/registerDisplaySetMetadata.ts
  • packages/metadata/src/displayset/resolveInstances.ts
  • packages/metadata/src/displayset/splitSeriesInstanceGroupsFromImageIds.ts
  • packages/metadata/src/displayset/types.ts
  • packages/metadata/src/displayset/viewportTypes.ts
  • packages/metadata/src/enums/MetadataModules.ts
  • packages/metadata/src/index.ts
  • packages/metadata/src/registerDefaultProviders.ts
  • packages/metadata/src/types/MetadataModuleTypes.ts
  • packages/metadata/src/types/index.ts
  • packages/metadata/src/utilities/index.ts
  • packages/tools/examples/dynamicCINETool/index.ts
  • packages/tools/examples/generateImageFromTimeData/index.ts
  • packages/tools/examples/localAdvanced/index.ts
  • packages/tools/examples/videoColor/index.ts
  • packages/tools/examples/videoContourSegmentation/index.ts
  • packages/tools/examples/videoGroup/index.ts
  • packages/tools/examples/videoNavigation/index.ts
  • packages/tools/examples/videoRange/index.ts
  • packages/tools/examples/videoSegmentation/index.ts
  • packages/tools/examples/videoSplineROITools/index.ts
  • packages/tools/examples/videoTools/index.ts
  • utils/ExampleRunner/example-runner-cli.js
  • utils/demo/helpers/index.js
  • utils/demo/helpers/splitDisplaySetsFromImageIds.ts

Comment thread package.json Outdated
"not op_mini all"
],
"packageManager": "pnpm@11.4.0"
"packageManager": "pnpm@11.5.2"

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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find GitHub Actions workflows specifying pnpm version 11.4.0
rg -n "version.*11\.4\.0" .github/workflows/

Repository: cornerstonejs/cornerstone3D

Length of output: 460


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Confirm package.json packageManager value
echo "== package.json around packageManager =="
nl -ba package.json | sed -n '170,200p'

# 2) Inspect pnpm version usage in the workflows flagged by the initial search
echo
echo "== Workflow snippets containing version: 11.4.0 =="
for f in \
  .github/workflows/validate-codemod-registry.yml \
  .github/workflows/test.yml \
  .github/workflows/playwright.yml \
  .github/workflows/docusaurus-build.yml \
  .github/workflows/build-docs.yml \
  .github/workflows/format-check.yml
do
  echo "--- $f ---"
  rg -n "version:\s*11\.4\.0" "$f"
  # show a bit of surrounding context
  line=$(rg -n "version:\s*11\.4\.0" "$f" | head -n1 | cut -d: -f1)
  start=$((line-8)); end=$((line+8))
  nl -ba "$f" | sed -n "${start},${end}p"
done

Repository: cornerstonejs/cornerstone3D

Length of output: 173


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== package.json around packageManager =="
cat -n package.json | sed -n '170,200p'

echo
echo "== Workflow snippets containing version: 11.4.0 =="
for f in \
  .github/workflows/validate-codemod-registry.yml \
  .github/workflows/test.yml \
  .github/workflows/playwright.yml \
  .github/workflows/docusaurus-build.yml \
  .github/workflows/build-docs.yml \
  .github/workflows/format-check.yml
do
  echo "--- $f ---"
  rg -n "version:\s*11\.4\.0" "$f" || true
  line=$(rg -n "version:\s*11\.4\.0" "$f" | head -n1 | cut -d: -f1 || true)
  if [[ -n "${line:-}" ]]; then
    start=$((line-8)); end=$((line+8))
    cat -n "$f" | sed -n "${start},${end}p"
  fi
done

Repository: cornerstonejs/cornerstone3D

Length of output: 4060


🏁 Script executed:

#!/bin/bash
set -euo pipefail

for f in \
  .github/workflows/validate-codemod-registry.yml \
  .github/workflows/test.yml \
  .github/workflows/playwright.yml \
  .github/workflows/docusaurus-build.yml \
  .github/workflows/build-docs.yml \
  .github/workflows/format-check.yml
do
  echo "===== $f ====="
  # show workflow name and top-level jobs block headers + any mention of OHIF / Docusaurus / Format Check
  rg -n '^(name:|jobs:)' "$f" || true
  rg -n '(OHIF|Docusaurus|format check|Format Check|downstream)' "$f" || true
  echo
done

Repository: cornerstonejs/cornerstone3D

Length of output: 711


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== All occurrences of 11.4.0 in workflows =="
rg -n "11\.4\.0" .github/workflows/ || true

echo
echo "== OHIF / downstream mentions in workflows =="
rg -n "(OHIF|downstream validation|downstream)" .github/workflows/ || true

Repository: cornerstonejs/cornerstone3D

Length of output: 4877


🏁 Script executed:

#!/bin/bash
set -euo pipefail

cat -n .github/workflows/ohif-downstream.yml | sed -n '1,200p'

Repository: cornerstonejs/cornerstone3D

Length of output: 6556


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "== workflows using pnpm/action-setup =="
rg -n "pnpm/action-setup@" .github/workflows/

echo
echo "== pnpm versions pinned in workflows =="
rg -n "version:\s*11\.[0-9]+\.[0-9]+" .github/workflows/ || true

echo
echo "== explicit PNPM_VERSION env values =="
rg -n "PNPM_VERSION:\s*11\.[0-9]+\.[0-9]+" .github/workflows/ || true

Repository: cornerstonejs/cornerstone3D

Length of output: 1172


Fix CI pnpm version mismatch (packageManager pnpm@11.5.2 vs workflows pnpm@11.4.0)

package.json sets "packageManager": "pnpm@11.5.2", but GitHub Actions pins pnpm to 11.4.0 via pnpm/action-setup (and ohif-downstream.yml sets PNPM_VERSION: 11.4.0). These workflows run pnpm install --frozen-lockfile, so pnpm will fail with ERR_PNPM_BAD_PM_VERSION, blocking CI.

Update the pinned pnpm versions in:

  • .github/workflows/validate-codemod-registry.yml
  • .github/workflows/test.yml
  • .github/workflows/playwright.yml
  • .github/workflows/format-check.yml
  • .github/workflows/docusaurus-build.yml
  • .github/workflows/build-docs.yml
  • .github/workflows/ohif-downstream.yml (env.PNPM_VERSION)

Set them to 11.5.2 (or remove the explicit version pin to respect packageManager), or revert package.json back to pnpm@11.4.0.

🤖 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 `@package.json` at line 183, package.json declares "packageManager":
"pnpm@11.5.2" but CI workflows pin pnpm to 11.4.0 causing
ERR_PNPM_BAD_PM_VERSION; update the pnpm version pin in the referenced GitHub
Actions workflows (.github/workflows/validate-codemod-registry.yml, test.yml,
playwright.yml, format-check.yml, docusaurus-build.yml, build-docs.yml) and the
PNPM_VERSION env in ohif-downstream.yml to 11.5.2 (or remove explicit pnpm
version pins so the runner respects packageManager), or alternatively change the
packageManager value back to "pnpm@11.4.0" to keep CI consistent. Ensure you
update all occurrences of pnpm@11.4.0 and PNPM_VERSION to 11.5.2 (or remove
pins) so pnpm install --frozen-lockfile no longer errors.

Comment thread packages/core/examples/displaySets/index.ts
Comment thread packages/core/src/RenderingEngine/BaseVolumeViewport.ts
Comment thread packages/core/src/RenderingEngine/BaseVolumeViewport.ts
Comment thread packages/core/src/RenderingEngine/StackViewport.ts
Comment thread packages/metadata/src/displayset/resolveInstances.ts
Comment thread packages/tools/examples/videoNavigation/index.ts
Comment thread packages/tools/examples/videoSegmentation/index.ts
Comment thread packages/tools/examples/videoSplineROITools/index.ts
Comment thread packages/tools/examples/videoTools/index.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants