-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
fix: Align GRID_STATE_CHANGED timing with viewport updates #5624
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
…ack support - Updated `setDisplaySetsForViewport` and `setDisplaySetsForViewports` methods to accept an options parameter, allowing for a preCallback function to be executed before updating viewports. - Refactored the viewport reducer to improve handling of display sets and viewport state management, ensuring better performance and reliability.
… improved state handling - Updated methods in `ViewportGridService` to return the state after setting active viewport, display sets, and layout, enhancing state management and consistency. - Refactored event broadcasting to ensure it occurs after state updates, improving responsiveness and reliability.
- Removed unnecessary setTimeout calls for event broadcasting in `ViewportGridService`, ensuring immediate event dispatch after state updates. - This change enhances code clarity and responsiveness by directly invoking event broadcasts without delay.
- Added the `state` parameter to the event broadcast for `ACTIVE_VIEWPORT_ID_CHANGED` in `ViewportGridService`, ensuring that the current state is included in the event payload. - This change improves the context of the event, allowing for better handling of viewport state changes.
…ge queuing - Added `notifyViewportUpdateCompleted` method in `ViewportGridService` to signal when a viewport has finished its data update, allowing for queued grid state changes to be published. - Introduced a mechanism to queue grid state changes until all dependent viewports have completed their updates, enhancing synchronization and responsiveness in viewport management. - Updated `CornerstoneViewportService` to utilize the new notification method, ensuring that viewport updates trigger the appropriate state changes in the grid service.
…ort grid state change timing details - Added a section explaining the new timing for the `GRID_STATE_CHANGED` event in `viewportGridService`, which now defers until all affected viewports complete their updates. - Included information on alternative hooks for earlier reactions and instructions for custom viewports to notify the grid service upon completion of their data changes.
✅ Deploy Preview for ohif-dev canceled.
|
Viewers
|
||||||||||||||||||||||||||||
| Project |
Viewers
|
| Branch Review |
fix/grid-state-changed
|
| Run status |
|
| Run duration | 02m 23s |
| Commit |
|
| Committer | Alireza |
| View all properties for this run ↗︎ | |
| Test results | |
|---|---|
|
|
0
|
|
|
0
|
|
|
0
|
|
|
0
|
|
|
37
|
| View all changes introduced in this branch ↗︎ | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request implements a deferred event broadcasting system for viewport grid state changes to address race conditions where listeners received incomplete viewport state. The grid service now queues state change events until all affected viewports complete their data updates, ensuring listeners always see the final, consistent state rather than intermediate updates.
Key Changes:
- Implemented viewport update notification system with queuing mechanism to defer
GRID_STATE_CHANGEDevents until all viewport data updates complete - Refactored ViewportGridProvider to use synchronous state application pattern with
applyReducerAndCommitfor immediate state access - Added
preCallbacksupport tosetDisplaySetsForViewportmethods for pre-update hooks
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| platform/core/src/services/ViewportGridService/ViewportGridService.ts | Implements pending state change queue with notifyViewportUpdateCompleted() tracking; adds preCallback parameter support; returns state from service methods |
| platform/ui-next/src/contextProviders/ViewportGridProvider.tsx | Refactors reducer to use useCallback and implements applyReducerAndCommit pattern for synchronous state updates via ref; replaces all dispatch calls |
| extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts | Adds notifyViewportUpdateCompleted() calls after viewport data change events to signal completion to grid service |
| platform/docs/docs/migration-guide/3p11-to-3p12/index.md | Documents timing changes for GRID_STATE_CHANGED event and migration path for custom viewports |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
platform/core/src/services/ViewportGridService/ViewportGridService.ts
Outdated
Show resolved
Hide resolved
platform/core/src/services/ViewportGridService/ViewportGridService.ts
Outdated
Show resolved
Hide resolved
platform/core/src/services/ViewportGridService/ViewportGridService.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the final PR Bugbot will review for you during this billing cycle
Your free Bugbot reviews will reset on January 30
Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
…anagement - Eliminated the `token` property from `PendingGridStateChange` and the `nextGridStateChangeToken` from `ViewportGridService`, streamlining state change handling. - Updated `setDisplaySetsForViewport` and `setDisplaySetsForViewports` methods to improve type definitions and ensure consistent options handling. - Refactored the viewport reducer to enhance clarity and maintainability, ensuring better state management during viewport updates.
- Introduced a flag to track updates to pending viewport IDs, ensuring that the flush of pending grid state changes only occurs when necessary. - This change improves performance by reducing unnecessary calls to `_flushPendingGridStateChanges`, enhancing the efficiency of viewport state management.
…ty viewport structure - Updated the ViewerViewportGrid component to return an empty viewport structure when no match details are found for a given viewport ID. This change ensures that the application can gracefully handle cases where viewport match details are unavailable, preventing potential errors in rendering.
- Replaced direct retrieval of viewport IDs with a new private method `_getViewportIdsWithDisplaySets`, which filters viewports based on their display set instance UIDs. This change enhances the clarity and efficiency of viewport ID management within the `ViewportGridService`.
| }); | ||
| }, | ||
| updatedViewports.map(viewport => viewport.viewportId) | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Empty viewport pending IDs block GRID_STATE_CHANGED events
In setDisplaySetsForViewports, the pendingViewportIds on line 245 includes ALL updated viewports via updatedViewports.map(viewport => viewport.viewportId), even those with empty displaySetInstanceUIDs. However, viewports without display sets render EmptyViewport (which never calls notifyViewportUpdateCompleted), and setViewportData returns early without calling notifyViewportUpdateCompleted when imageIds are empty. This causes the pending queue to never clear for such viewports, blocking all subsequent GRID_STATE_CHANGED events. The fix should filter to only include viewports with displaySetInstanceUIDs, similar to how setLayout and set use _getViewportIdsWithDisplaySets.
extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts
Show resolved
Hide resolved
- Added a call to `notifyViewportUpdateCompleted` in `CornerstoneViewportService` to handle cases where the `imageIds` array is empty for stack viewports. This ensures that the viewport grid service is informed of the update status, improving synchronization and state management.
| viewportData, | ||
| viewportId, | ||
| }); | ||
| viewportGridService?.notifyViewportUpdateCompleted?.(viewportId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Promise rejection prevents grid state change notification
The notifyViewportUpdateCompleted call is only placed inside .then() callbacks without any .catch() or .finally() handlers. If displaySetPromise rejects due to an error during viewport data loading, notifyViewportUpdateCompleted will never be called. This causes pendingGridStateChanges to wait indefinitely for that viewport, preventing GRID_STATE_CHANGED from ever being broadcast. Before this change, GRID_STATE_CHANGED would fire regardless of loading success (via setTimeout), but now the pending queue mechanism creates a dependency on successful completion.
Additional Locations (1)
| numCols, | ||
| numRows, | ||
| }); | ||
| // Use queueMicrotask to ensure the layout changed event is published after |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is published after the state has been updated/is available.
|
@sedghi - going to respond on slack about this PR - I have some real questions about the direction that this PR is taking |
|
There are some good internal changes/fixes, but I think the overall change doesn't agree with the general direction we are trying to go in for OHIF. I think we want to:
For the viewport grid state, what it is trying to enable is:
I think the viewport grid state also needs to be able to be listened to in order to discover overall load state - but this should be a part of the viewport grid state and listened to via the useViewportGrid with an appropriate method to get the specific state part. You can do all these things with the new listeners you've added, but it requires multiple ways of doing things, and I think the future is really about using the state management with state selection to choose exactly what updates you get. I'm thinking something like a listener that wants to do something on the state having settled and be displaying the updated display set uids using: Then, grid status could be used to show a spinny icon cursor or the like. Individual viewports might render something like: when the viewport finishes loading. Then the overall viewport state is defined internally to the store by the individual viewport states. |
|
Would it be possible to create a state transition diagram showing the state information and what causes those state transitions, along with who is listening to what part of the state? It probably needs a few related diagrams, for updates to the display set/initial state as well as for the overall grid state. I think having that would allow us to talk about how the state access methods would work. |
Summary
viewportGridServiceso GRID_STATE_CHANGED fires only after every affected viewport finishesviewport data changednotifyViewportUpdateCompletedand call it from Cornerstone’s viewport service after each data changex
Also fixing the viewport grid not properly doing empty viewports
To repro: add more rows and columns in the HP
Before

Note
Defers
GRID_STATE_CHANGEDuntil all affected viewports complete data updates, addsnotifyViewportUpdateCompleted(called by Cornerstone), handles empty panes in HP layouts, syncs provider state updates, and documents the timing change.ViewportGridServicenotifyViewportUpdateCompleted(viewportId); publishGRID_STATE_CHANGEDonly after all dependent viewports finishviewport data changed.setTimeoutemits with immediate events;ACTIVE_VIEWPORT_ID_CHANGEDnow includes and returnsstate._queueGridStateChanged,_flushPendingGridStateChanges,_getViewportIdsWithDisplaySets.setDisplaySetsForViewport(s)acceptspreCallback;set,setLayout, and display-set updates now queue grid-state changes; reset/onModeExit clear pending queue.viewportGridService.notifyViewportUpdateCompleted(viewportId)afterVIEWPORT_DATA_CHANGEDinsetViewportData/updateViewport; early notify and return for empty stackimageIds.ViewportGrid.tsx)findOrCreateViewportreturns an empty viewport definition when no HP match (instead of logging and skipping).APPLY_VIEWPORT_GRID_STATEandapplyReducerAndCommitto compute-and-commit reducer updates synchronously; guard missing viewport inVIEWPORT_IS_READY.GRID_STATE_CHANGEDtiming and requirement to callnotifyViewportUpdateCompletedfor custom viewports.Written by Cursor Bugbot for commit d2c2cdb. This will update automatically on new commits. Configure here.