fix(overlay-menu): Adding, changing and removing segmentation overlays should update the overlay menu instantly (#5181)
This commit is contained in:
1 parent
b8b14b8940
commit
f08cc303e6
21 files changed
+164
-12
No files matched your search
+42
-3
@@ -36,6 +36,9 @@ function ViewportDataOverlayMenu({ viewportId }: withAppTypes<{ viewportId: stri
|
||||
foregroundDisplaySets,
|
||||
} = useViewportDisplaySets(viewportId);
|
||||
|
||||
const [optimisticOverlayDisplaySets, setOptimisticOverlayDisplaySets] =
|
||||
useState(overlayDisplaySets);
|
||||
|
||||
const [thresholdOpacityEnabled, setThresholdOpacityEnabled] = useState(false);
|
||||
|
||||
/**
|
||||
@@ -77,6 +80,18 @@ function ViewportDataOverlayMenu({ viewportId }: withAppTypes<{ viewportId: stri
|
||||
* Remove a display set layer
|
||||
*/
|
||||
const handleRemoveDisplaySetLayer = (displaySetInstanceUID: string) => {
|
||||
const optimisticOverlayDisplaySetsIndex = optimisticOverlayDisplaySets.findIndex(
|
||||
displaySet => displaySet.displaySetInstanceUID === displaySetInstanceUID
|
||||
);
|
||||
|
||||
if (optimisticOverlayDisplaySetsIndex !== -1) {
|
||||
setOptimisticOverlayDisplaySets(prevOptimisticOverlayDisplaySets => {
|
||||
return prevOptimisticOverlayDisplaySets.filter(
|
||||
displaySet => displaySet.displaySetInstanceUID !== displaySetInstanceUID
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
commandsManager.runCommand('removeDisplaySetLayer', {
|
||||
viewportId,
|
||||
displaySetInstanceUID,
|
||||
@@ -110,6 +125,17 @@ function ViewportDataOverlayMenu({ viewportId }: withAppTypes<{ viewportId: stri
|
||||
);
|
||||
|
||||
if (selectedDisplaySet) {
|
||||
setOptimisticOverlayDisplaySets(prevOptimisticOverlayDisplaySets => {
|
||||
const currentDisplaySetIndex = prevOptimisticOverlayDisplaySets.findIndex(
|
||||
displaySet => displaySet.displaySetInstanceUID === currentDisplaySet.displaySetInstanceUID
|
||||
);
|
||||
return [
|
||||
...prevOptimisticOverlayDisplaySets.slice(0, currentDisplaySetIndex),
|
||||
selectedDisplaySet,
|
||||
...prevOptimisticOverlayDisplaySets.slice(currentDisplaySetIndex + 1),
|
||||
];
|
||||
});
|
||||
|
||||
handleReplaceDisplaySetLayer(
|
||||
currentDisplaySet.displaySetInstanceUID,
|
||||
selectedDisplaySet.displaySetInstanceUID
|
||||
@@ -150,6 +176,10 @@ function ViewportDataOverlayMenu({ viewportId }: withAppTypes<{ viewportId: stri
|
||||
);
|
||||
|
||||
if (selectedDisplaySet) {
|
||||
setOptimisticOverlayDisplaySets(prevOptimisticOverlayDisplaySets => [
|
||||
...prevOptimisticOverlayDisplaySets,
|
||||
selectedDisplaySet,
|
||||
]);
|
||||
handleAddDisplaySetAsLayer(selectedDisplaySet.displaySetInstanceUID);
|
||||
// Remove this pending segmentation from the list
|
||||
setPendingSegmentations(pendingSegmentations.filter(id => id !== pendingId));
|
||||
@@ -184,7 +214,10 @@ function ViewportDataOverlayMenu({ viewportId }: withAppTypes<{ viewportId: stri
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-popover flex h-full w-[275px] flex-col rounded rounded-md p-1.5">
|
||||
<div
|
||||
className="bg-popover flex h-full w-[275px] flex-col rounded rounded-md p-1.5"
|
||||
data-cy={`viewport-data-overlay-menu-${viewportId}`}
|
||||
>
|
||||
{/* Top buttons row */}
|
||||
<div className={`flex`}>
|
||||
<Button
|
||||
@@ -216,7 +249,7 @@ function ViewportDataOverlayMenu({ viewportId }: withAppTypes<{ viewportId: stri
|
||||
<div className="">
|
||||
{/* Overlays Segmentation section */}
|
||||
<div className="my-2 ml-1">
|
||||
{overlayDisplaySets.map((displaySet, index) => (
|
||||
{optimisticOverlayDisplaySets.map(displaySet => (
|
||||
<div
|
||||
key={displaySet.displaySetInstanceUID}
|
||||
className="mb-1 flex items-center"
|
||||
@@ -227,7 +260,11 @@ function ViewportDataOverlayMenu({ viewportId }: withAppTypes<{ viewportId: stri
|
||||
onValueChange={value => handleOverlaySelectionChange(displaySet, value)}
|
||||
>
|
||||
<SelectTrigger className="flex-1">
|
||||
<SelectValue>{displaySet.label?.toUpperCase()}</SelectValue>
|
||||
<SelectValue
|
||||
data-cy={`overlay-ds-select-value-${displaySet.label?.toUpperCase()}`}
|
||||
>
|
||||
{displaySet.label?.toUpperCase()}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{/* Include both potential overlays and the current overlay */}
|
||||
@@ -255,12 +292,14 @@ function ViewportDataOverlayMenu({ viewportId }: withAppTypes<{ viewportId: stri
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="ml-2 flex-shrink-0"
|
||||
dataCY={`overlay-ds-more-button-${displaySet.label?.toUpperCase()}`}
|
||||
>
|
||||
<Icons.More className="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuItem
|
||||
data-cy={`overlay-ds-remove-button-${displaySet.label?.toUpperCase()}`}
|
||||
onClick={() => handleRemoveDisplaySetLayer(displaySet.displaySetInstanceUID)}
|
||||
>
|
||||
Remove
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useSystem, utils } from '@ohif/core';
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
import {
|
||||
@@ -122,12 +122,34 @@ export function useViewportDisplaySets(
|
||||
|
||||
// Get all available segmentations (only if needed)
|
||||
const needsSegmentations = includeOverlay;
|
||||
const segmentationRepresentations = useMemo(
|
||||
() =>
|
||||
needsSegmentations ? segmentationService.getSegmentationRepresentations(viewportIdToUse) : [],
|
||||
[segmentationService, viewportIdToUse, needsSegmentations]
|
||||
|
||||
const [segmentationRepresentations, setSegmentationRepresentations] = useState(
|
||||
needsSegmentations ? segmentationService.getSegmentationRepresentations(viewportIdToUse) : []
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setSegmentationRepresentations(
|
||||
needsSegmentations ? segmentationService.getSegmentationRepresentations(viewportIdToUse) : []
|
||||
);
|
||||
|
||||
const unsubscribeArr = needsSegmentations
|
||||
? [
|
||||
segmentationService.EVENTS.SEGMENTATION_REPRESENTATION_MODIFIED,
|
||||
segmentationService.EVENTS.SEGMENTATION_REPRESENTATION_REMOVED,
|
||||
].map(event =>
|
||||
segmentationService.subscribe(event, () => {
|
||||
setSegmentationRepresentations(
|
||||
segmentationService.getSegmentationRepresentations(viewportIdToUse)
|
||||
);
|
||||
})
|
||||
)
|
||||
: [];
|
||||
|
||||
return () => {
|
||||
unsubscribeArr.forEach(item => item.unsubscribe());
|
||||
};
|
||||
}, [segmentationService, viewportIdToUse, needsSegmentations]);
|
||||
|
||||
const overlayDisplaySets = useMemo(() => {
|
||||
if (!includeOverlay) {
|
||||
return [];
|
||||
|
||||
Reference in new issue
Block a user