fix(viewportDialog): viewportDialoge not appearing in non-tracked viewports (#3071)

* fix: viewportdialoge not appearing in non-tracked viewports

* feat(viewports): Introduce useViewportDialog and remove deprecated API

This commit introduces the `useViewportDialog` hook and replaces the deprecated `viewportDialogApi` with the new `viewportDialogState`. Additionally, the notifications in `OHIFCornerstoneRTViewport` and `OHIFCornerstoneViewport` have been removed. Finally, the `CinePlayer` component now accepts optional parameters.

* fix tests
This commit is contained in:
Alireza 2023-04-28 11:06:03 -04:00 committed by GitHub
parent c9d3c08cb6
commit f377153b60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 78 additions and 118 deletions

View File

@ -2,10 +2,8 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import OHIF, { utils } from '@ohif/core'; import OHIF, { utils } from '@ohif/core';
import { import {
Notification,
ViewportActionBar, ViewportActionBar,
useViewportGrid, useViewportGrid,
useViewportDialog,
LoadingIndicatorTotalPercent, LoadingIndicatorTotalPercent,
} from '@ohif/ui'; } from '@ohif/ui';
@ -47,7 +45,6 @@ function OHIFCornerstoneRTViewport(props) {
const rtDisplaySet = displaySets[0]; const rtDisplaySet = displaySets[0];
const [viewportGrid, viewportGridService] = useViewportGrid(); const [viewportGrid, viewportGridService] = useViewportGrid();
const [viewportDialogState, viewportDialogApi] = useViewportDialog();
// States // States
const [isToolGroupCreated, setToolGroupCreated] = useState(false); const [isToolGroupCreated, setToolGroupCreated] = useState(false);
@ -363,18 +360,6 @@ function OHIFCornerstoneRTViewport(props) {
/> />
)} )}
{getCornerstoneViewport()} {getCornerstoneViewport()}
<div className="absolute w-full">
{viewportDialogState.viewportIndex === viewportIndex && (
<Notification
id="viewport-notification"
message={viewportDialogState.message}
type={viewportDialogState.type}
actions={viewportDialogState.actions}
onSubmit={viewportDialogState.onSubmit}
onOutsideClick={viewportDialogState.onOutsideClick}
/>
)}
</div>
{childrenWithProps} {childrenWithProps}
</div> </div>
</> </>

View File

@ -4,8 +4,6 @@ import { useTranslation } from 'react-i18next';
import OHIF, { utils } from '@ohif/core'; import OHIF, { utils } from '@ohif/core';
import { import {
LoadingIndicatorTotalPercent, LoadingIndicatorTotalPercent,
Notification,
useViewportDialog,
useViewportGrid, useViewportGrid,
ViewportActionBar, ViewportActionBar,
} from '@ohif/ui'; } from '@ohif/ui';
@ -48,7 +46,6 @@ function OHIFCornerstoneSEGViewport(props) {
const segDisplaySet = displaySets[0]; const segDisplaySet = displaySets[0];
const [viewportGrid, viewportGridService] = useViewportGrid(); const [viewportGrid, viewportGridService] = useViewportGrid();
const [viewportDialogState, viewportDialogApi] = useViewportDialog();
// States // States
const [isToolGroupCreated, setToolGroupCreated] = useState(false); const [isToolGroupCreated, setToolGroupCreated] = useState(false);
@ -366,18 +363,6 @@ function OHIFCornerstoneSEGViewport(props) {
/> />
)} )}
{getCornerstoneViewport()} {getCornerstoneViewport()}
<div className="absolute w-full">
{viewportDialogState.viewportIndex === viewportIndex && (
<Notification
id="viewport-notification"
message={viewportDialogState.message}
type={viewportDialogState.type}
actions={viewportDialogState.actions}
onSubmit={viewportDialogState.onSubmit}
onOutsideClick={viewportDialogState.onOutsideClick}
/>
)}
</div>
{childrenWithProps} {childrenWithProps}
</div> </div>
</> </>

View File

@ -401,17 +401,6 @@ function OHIFCornerstoneSRViewport(props) {
<div className="relative flex flex-row w-full h-full overflow-hidden"> <div className="relative flex flex-row w-full h-full overflow-hidden">
{getCornerstoneViewport()} {getCornerstoneViewport()}
<div className="absolute w-full">
{viewportDialogState.viewportIndex === viewportIndex && (
<Notification
message={viewportDialogState.message}
type={viewportDialogState.type}
actions={viewportDialogState.actions}
onSubmit={viewportDialogState.onSubmit}
onOutsideClick={viewportDialogState.onOutsideClick}
/>
)}
</div>
{childrenWithProps} {childrenWithProps}
</div> </div>
</> </>

View File

@ -8,9 +8,14 @@ import {
getEnabledElement, getEnabledElement,
StackViewport, StackViewport,
utilities as csUtils, utilities as csUtils,
CONSTANTS,
} from '@cornerstonejs/core'; } from '@cornerstonejs/core';
import { CinePlayer, useCine, useViewportGrid } from '@ohif/ui'; import {
CinePlayer,
useCine,
useViewportGrid,
Notification,
useViewportDialog,
} from '@ohif/ui';
import { import {
IStackViewport, IStackViewport,
IVolumeViewport, IVolumeViewport,
@ -132,6 +137,8 @@ const OHIFCornerstoneViewport = React.memo(props => {
stateSyncService, stateSyncService,
} = servicesManager.services as CornerstoneServices; } = servicesManager.services as CornerstoneServices;
const [viewportDialogState] = useViewportDialog();
const cineHandler = () => { const cineHandler = () => {
if (!cines || !cines[viewportIndex] || !enabledVPElement) { if (!cines || !cines[viewportIndex] || !enabledVPElement) {
return; return;
@ -455,50 +462,64 @@ const OHIFCornerstoneViewport = React.memo(props => {
}, [displaySets, elementRef, viewportIndex]); }, [displaySets, elementRef, viewportIndex]);
return ( return (
<div className="viewport-wrapper"> <React.Fragment>
<ReactResizeDetector <div className="viewport-wrapper">
handleWidth <ReactResizeDetector
handleHeight handleWidth
skipOnMount={true} // Todo: make these configurable handleHeight
refreshMode={'debounce'} skipOnMount={true} // Todo: make these configurable
refreshRate={200} // transition amount in side panel refreshMode={'debounce'}
onResize={onResize} refreshRate={200} // transition amount in side panel
targetRef={elementRef.current} onResize={onResize}
/> targetRef={elementRef.current}
<div
className="cornerstone-viewport-element"
style={{ height: '100%', width: '100%' }}
onContextMenu={e => e.preventDefault()}
onMouseDown={e => e.preventDefault()}
ref={elementRef}
></div>
<CornerstoneOverlays
viewportIndex={viewportIndex}
toolbarService={toolbarService}
element={elementRef.current}
scrollbarHeight={scrollbarHeight}
servicesManager={servicesManager}
/>
{isCineEnabled && (
<CinePlayer
className="absolute left-1/2 -translate-x-1/2 bottom-3"
isPlaying={isPlaying}
onClose={handleCineClose}
onPlayPauseChange={isPlaying =>
cineService.setCine({
id: activeViewportIndex,
isPlaying,
})
}
onFrameRateChange={frameRate =>
cineService.setCine({
id: activeViewportIndex,
frameRate,
})
}
/> />
)} <div
</div> className="cornerstone-viewport-element"
style={{ height: '100%', width: '100%' }}
onContextMenu={e => e.preventDefault()}
onMouseDown={e => e.preventDefault()}
ref={elementRef}
></div>
<CornerstoneOverlays
viewportIndex={viewportIndex}
toolBarService={toolbarService}
element={elementRef.current}
scrollbarHeight={scrollbarHeight}
servicesManager={servicesManager}
/>
{isCineEnabled && (
<CinePlayer
className="absolute left-1/2 -translate-x-1/2 bottom-3"
isPlaying={isPlaying}
onClose={handleCineClose}
onPlayPauseChange={isPlaying =>
cineService.setCine({
id: activeViewportIndex,
isPlaying,
})
}
onFrameRateChange={frameRate =>
cineService.setCine({
id: activeViewportIndex,
frameRate,
})
}
/>
)}
</div>
<div className="absolute w-full">
{viewportDialogState.viewportIndex === viewportIndex && (
<Notification
id="viewport-notification"
message={viewportDialogState.message}
type={viewportDialogState.type}
actions={viewportDialogState.actions}
onSubmit={viewportDialogState.onSubmit}
onOutsideClick={viewportDialogState.onOutsideClick}
/>
)}
</div>
</React.Fragment>
); );
}, areEqual); }, areEqual);

View File

@ -159,18 +159,6 @@ function TrackedCornerstoneViewport(props) {
{/* TODO: Viewport interface to accept stack or layers of content like this? */} {/* TODO: Viewport interface to accept stack or layers of content like this? */}
<div className="relative flex flex-row w-full h-full overflow-hidden"> <div className="relative flex flex-row w-full h-full overflow-hidden">
{getCornerstoneViewport()} {getCornerstoneViewport()}
<div className="absolute w-full">
{viewportDialogState.viewportIndex === viewportIndex && (
<Notification
id={viewportDialogState.id}
message={viewportDialogState.message}
type={viewportDialogState.type}
actions={viewportDialogState.actions}
onSubmit={viewportDialogState.onSubmit}
onOutsideClick={viewportDialogState.onOutsideClick}
/>
)}
</div>
</div> </div>
</> </>
); );

View File

@ -9,10 +9,10 @@ import classNames from 'classnames';
export type CinePlayerProps = { export type CinePlayerProps = {
className: string; className: string;
isPlaying: boolean; isPlaying: boolean;
minFrameRate: number; minFrameRate?: number;
maxFrameRate: number; maxFrameRate?: number;
stepFrameRate: number; stepFrameRate?: number;
frameRate: number; frameRate?: number;
onFrameRateChange: (value: number) => void; onFrameRateChange: (value: number) => void;
onPlayPauseChange: (value: boolean) => void; onPlayPauseChange: (value: boolean) => void;
onClose: () => void; onClose: () => void;
@ -116,12 +116,12 @@ CinePlayer.defaultProps = {
CinePlayer.propTypes = { CinePlayer.propTypes = {
/** Minimum value for range slider */ /** Minimum value for range slider */
minFrameRate: PropTypes.number.isRequired, minFrameRate: PropTypes.number,
/** Maximum value for range slider */ /** Maximum value for range slider */
maxFrameRate: PropTypes.number.isRequired, maxFrameRate: PropTypes.number,
/** Increment range slider can "step" in either direction */ /** Increment range slider can "step" in either direction */
stepFrameRate: PropTypes.number.isRequired, stepFrameRate: PropTypes.number,
frameRate: PropTypes.number.isRequired, frameRate: PropTypes.number,
/** 'true' if playing, 'false' if paused */ /** 'true' if playing, 'false' if paused */
isPlaying: PropTypes.bool.isRequired, isPlaying: PropTypes.bool.isRequired,
onPlayPauseChange: PropTypes.func, onPlayPauseChange: PropTypes.func,

View File

@ -111,12 +111,8 @@ describe('OHIF Cornerstone Toolbar', () => {
it('checks if Length annotation can be added to viewport and shows up in the measurements panel', () => { it('checks if Length annotation can be added to viewport and shows up in the measurements panel', () => {
//Click on button and verify if icon is active on toolbar //Click on button and verify if icon is active on toolbar
cy.addLengthMeasurement(); cy.addLengthMeasurement();
cy.get('[data-cy="measurement-tracking-prompt-begin-tracking"]').should( cy.get('[data-cy="viewport-notification"]').should('exist');
'exist' cy.get('[data-cy="viewport-notification"]').should('be.visible');
);
cy.get('[data-cy="measurement-tracking-prompt-begin-tracking"]').should(
'be.visible'
);
cy.get('[data-cy="prompt-begin-tracking-yes"]').click(); cy.get('[data-cy="prompt-begin-tracking-yes"]').click();
//Verify the measurement exists in the table //Verify the measurement exists in the table

View File

@ -25,12 +25,8 @@ describe('OHIF Measurement Panel', function() {
it('checks if measurement item can be Relabeled under Measurements panel', function() { it('checks if measurement item can be Relabeled under Measurements panel', function() {
// Add length measurement // Add length measurement
cy.addLengthMeasurement(); cy.addLengthMeasurement();
cy.get('[data-cy="measurement-tracking-prompt-begin-tracking"]').should( cy.get('[data-cy="viewport-notification"]').should('exist');
'exist' cy.get('[data-cy="viewport-notification"]').should('be.visible');
);
cy.get('[data-cy="measurement-tracking-prompt-begin-tracking"]').should(
'be.visible'
);
cy.get('[data-cy="prompt-begin-tracking-yes"]').click(); cy.get('[data-cy="prompt-begin-tracking-yes"]').click();
cy.get('[data-cy="measurement-item"]').click(); cy.get('[data-cy="measurement-item"]').click();