fix(measurement-tracking): restore tracked state on undo after Delete all (#5994)

* fix: always show delete confirmation when measurements exist
This commit is contained in:
Ghadeer Albattarni authored and GitHub committed 2026-05-12 13:22:25 -04:00
1 parent 8cd8ccc163
commit 397aa4d0e3
10 files changed
+238 -30

No files matched your search

@@ -159,7 +159,13 @@ function TrackedMeasurementsContextProvider(
}
},
clearAllMeasurements: (ctx, evt) => {
measurementService.clearMeasurements();
const trackingContext = evt.trackedStudy
? { StudyInstanceUID: evt.trackedStudy, SeriesInstanceUIDs: [...(evt.trackedSeries || [])] }
: undefined;
measurementService.clearMeasurements(
undefined,
trackingContext ? { trackingContext } : undefined
);
measurementService.setIsMeasurementDeletedIndividually(false);
},
clearDisplaySetHydratedState: (ctx, evt) => {
@@ -250,7 +256,7 @@ function TrackedMeasurementsContextProvider(
simplifiedAndLoadSR: (ctx, evt, condMeta) => {
return (
appConfig?.measurementTrackingMode === measurementTrackingMode.SIMPLIFIED &&
evt.data.isBackupSave === false
evt.data?.isBackupSave === false
);
},
hasDirtyAndSimplified: (ctx, evt, condMeta) => {
@@ -369,11 +375,22 @@ function TrackedMeasurementsContextProvider(
]);
useEffect(() => {
// The command needs to be bound to the context's sendTrackedMeasurementsEvent
// so the command has to be registered in a React component.
// These commands are bound to the context's sendTrackedMeasurementsEvent, so they have
// to be registered from inside this (React) component. Re-registration on each
// render is safe — registerCommand overwrites by key.
commandsManager.registerCommand('DEFAULT', 'loadTrackedSRMeasurements', {
commandFn: props => sendTrackedMeasurementsEvent('HYDRATE_SR', props),
});
commandsManager.registerCommand('DEFAULT', 'restoreTrackedSeries', {
commandFn: ({ StudyInstanceUID, SeriesInstanceUIDs }) =>
sendTrackedMeasurementsEvent('SET_TRACKED_SERIES', {
StudyInstanceUID,
SeriesInstanceUIDs,
}),
});
commandsManager.registerCommand('DEFAULT', 'clearTrackedSeries', {
commandFn: () => sendTrackedMeasurementsEvent('CLEAR_TRACKING_CONTEXT'),
});
}, [commandsManager, sendTrackedMeasurementsEvent]);
return (
@@ -43,6 +43,9 @@ const machineConfiguration = {
idle: {
entry: 'clearContext',
on: {
// No-op: idle entry already cleared context. Redo can still send
// CLEAR_TRACKING_CONTEXT (tracking memo); required when strict mode is on.
CLEAR_TRACKING_CONTEXT: {},
TRACK_SERIES: [
{
target: 'promptLabelAnnotation',
@@ -137,6 +140,14 @@ const machineConfiguration = {
],
},
],
// Redo of measurement clear: annotations are already deleted via Cornerstone memo;
// this only clears XState tracking context. UNTRACK_ALL would clear measurements again.
CLEAR_TRACKING_CONTEXT: [
{
target: 'tracking',
actions: ['clearContext', 'setIsDirtyToClean', 'clearDisplaySetHydratedState'],
},
],
SET_TRACKED_SERIES: [
{
target: 'tracking',
@@ -13,8 +13,7 @@ import {
import { useTrackedMeasurements } from '../getContextModule';
import { UntrackSeriesModal } from './PanelStudyBrowserTracking/untrackSeriesModal';
const { filterMeasurementsBySeriesUID, filterAny } =
utils.MeasurementFilters;
const { filterMeasurementsBySeriesUID, filterAny } = utils.MeasurementFilters;
function PanelMeasurementTableTracking(props) {
const [viewportGrid] = useViewportGrid();
@@ -23,28 +22,26 @@ function PanelMeasurementTableTracking(props) {
const [trackedMeasurements, sendTrackedMeasurementsEvent] = useTrackedMeasurements();
const { trackedStudy, trackedSeries } = trackedMeasurements.context;
const measurementFilter = trackedStudy
? filterMeasurementsBySeriesUID(trackedSeries)
: filterAny;
const measurementFilter = trackedStudy ? filterMeasurementsBySeriesUID(trackedSeries) : filterAny;
const onUntrackConfirm = () => {
sendTrackedMeasurementsEvent('UNTRACK_ALL', {});
sendTrackedMeasurementsEvent('UNTRACK_ALL', { trackedStudy, trackedSeries });
};
const onDelete = () => {
const hasDirtyMeasurements = measurementService
.getMeasurements()
.some(measurement => measurement.isDirty);
hasDirtyMeasurements
? uiModalService.show({
title: 'Untrack Study',
content: UntrackSeriesModal,
contentProps: {
onConfirm: onUntrackConfirm,
message: 'Are you sure you want to untrack study and delete all measurements?',
},
})
: onUntrackConfirm();
const hasMeasurements = measurementService.getMeasurements().length > 0;
if (hasMeasurements) {
uiModalService.show({
title: 'Untrack Study',
content: UntrackSeriesModal,
contentProps: {
onConfirm: onUntrackConfirm,
message: 'Are you sure you want to untrack study and delete all measurements?',
},
});
} else {
onUntrackConfirm();
}
};
const EmptyComponent = () => (