feat: Start using group filtering to define measurements table layout (#4501)
This commit is contained in:
1 parent
bc73de9710
commit
82440e88d5
16 files changed
+357
-210
No files matched your search
@@ -1,8 +1,9 @@
|
||||
import { metaData, utilities } from '@cornerstonejs/core';
|
||||
|
||||
import OHIF, { DicomMetadataStore } from '@ohif/core';
|
||||
import OHIF, { DicomMetadataStore, utils } from '@ohif/core';
|
||||
import dcmjs from 'dcmjs';
|
||||
import { adaptersSR } from '@cornerstonejs/adapters';
|
||||
import { showLabelAnnotationPopup, colorPickerDialog } from '@ohif/extension-default';
|
||||
|
||||
import getFilteredCornerstoneToolState from './utils/getFilteredCornerstoneToolState';
|
||||
import hydrateStructuredReport from './utils/hydrateStructuredReport';
|
||||
@@ -11,7 +12,6 @@ const { MeasurementReport } = adaptersSR.Cornerstone3D;
|
||||
const { log } = OHIF;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param measurementData An array of measurements from the measurements service
|
||||
* that you wish to serialize.
|
||||
* @param additionalFindingTypes toolTypes that should be stored with labels as Findings
|
||||
@@ -43,8 +43,30 @@ const _generateReport = (measurementData, additionalFindingTypes, options = {})
|
||||
|
||||
const commandsModule = (props: withAppTypes) => {
|
||||
const { servicesManager, extensionManager, commandsManager } = props;
|
||||
const { customizationService, displaySetService, viewportGridService } = servicesManager.services;
|
||||
const { customizationService, measurementService, viewportGridService, uiDialogService } =
|
||||
servicesManager.services;
|
||||
|
||||
const actions = {
|
||||
changeColorMeasurement: ({ uid }) => {
|
||||
// When this gets supported, it probably belongs in cornerstone, not sr
|
||||
throw new Error('Unsupported operation: changeColorMeasurement');
|
||||
// const { color } = measurementService.getMeasurement(uid);
|
||||
// const rgbaColor = {
|
||||
// r: color[0],
|
||||
// g: color[1],
|
||||
// b: color[2],
|
||||
// a: color[3] / 255.0,
|
||||
// };
|
||||
// colorPickerDialog(uiDialogService, rgbaColor, (newRgbaColor, actionId) => {
|
||||
// if (actionId === 'cancel') {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const color = [newRgbaColor.r, newRgbaColor.g, newRgbaColor.b, newRgbaColor.a * 255.0];
|
||||
// segmentationService.setSegmentColor(viewportId, segmentationId, segmentIndex, color);
|
||||
// });
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param measurementData An array of measurements from the measurements service
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
annotation,
|
||||
} from '@cornerstonejs/tools';
|
||||
|
||||
import { Types as OhifTypes } from '@ohif/core';
|
||||
import { Types as OhifTypes, utils } from '@ohif/core';
|
||||
import i18n from '@ohif/i18n';
|
||||
import {
|
||||
callLabelAutocompleteDialog,
|
||||
@@ -295,6 +295,60 @@ function commandsModule({
|
||||
measurementService.update(updatedMeasurement.uid, updatedMeasurement, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Jumps to the specified (by uid) measurement in the active viewport.
|
||||
* Also marks any provided display measurements isActive value
|
||||
*/
|
||||
jumpToMeasurement: ({ uid, displayMeasurements = [] }) => {
|
||||
measurementService.jumpToMeasurement(viewportGridService.getActiveViewportId(), uid);
|
||||
for (const measurement of displayMeasurements) {
|
||||
measurement.isActive = measurement.uid === uid;
|
||||
}
|
||||
},
|
||||
|
||||
removeMeasurement: ({ uid }) => {
|
||||
measurementService.remove(uid);
|
||||
},
|
||||
|
||||
renameMeasurement: ({ uid }) => {
|
||||
const labelConfig = customizationService.get('measurementLabels');
|
||||
const measurement = measurementService.getMeasurement(uid);
|
||||
showLabelAnnotationPopup(measurement, uiDialogService, labelConfig).then(val => {
|
||||
measurementService.update(
|
||||
uid,
|
||||
{
|
||||
...val,
|
||||
},
|
||||
true
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
toggleLockMeasurement: ({ uid }) => {
|
||||
measurementService.toggleLockMeasurement(uid);
|
||||
},
|
||||
|
||||
toggleVisibilityMeasurement: ({ uid }) => {
|
||||
measurementService.toggleVisibilityMeasurement(uid);
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear the measurements
|
||||
*/
|
||||
clearMeasurements: options => {
|
||||
const { measurementFilter } = options;
|
||||
measurementService.clearMeasurements(
|
||||
measurementFilter ? measurementFilter.bind(options) : null
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Download the CSV report for the measurements.
|
||||
*/
|
||||
downloadCSVMeasurementsReport: ({ measurementFilter }) => {
|
||||
utils.downloadCSVReport(measurementService.getMeasurements(measurementFilter));
|
||||
},
|
||||
|
||||
// Retrieve value commands
|
||||
getActiveViewportEnabledElement: _getActiveViewportEnabledElement,
|
||||
|
||||
@@ -1281,6 +1335,27 @@ function commandsModule({
|
||||
updateMeasurement: {
|
||||
commandFn: actions.updateMeasurement,
|
||||
},
|
||||
clearMeasurements: {
|
||||
commandFn: actions.clearMeasurements,
|
||||
},
|
||||
jumpToMeasurement: {
|
||||
commandFn: actions.jumpToMeasurement,
|
||||
},
|
||||
removeMeasurement: {
|
||||
commandFn: actions.removeMeasurement,
|
||||
},
|
||||
renameMeasurement: {
|
||||
commandFn: actions.renameMeasurement,
|
||||
},
|
||||
toggleLockMeasurement: {
|
||||
commandFn: actions.toggleLockMeasurement,
|
||||
},
|
||||
toggleVisibilityMeasurement: {
|
||||
commandFn: actions.toggleVisibilityMeasurement,
|
||||
},
|
||||
downloadCSVMeasurementsReport: {
|
||||
commandFn: actions.downloadCSVMeasurementsReport,
|
||||
},
|
||||
setViewportWindowLevel: {
|
||||
commandFn: actions.setViewportWindowLevel,
|
||||
},
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import { DicomMetadataStore, utils } from '@ohif/core';
|
||||
import { StudySummary } from '@ohif/ui-next';
|
||||
|
||||
const { formatDate } = utils;
|
||||
|
||||
export function StudySummaryFromMetadata({ StudyInstanceUID }) {
|
||||
if (!StudyInstanceUID) {
|
||||
return null;
|
||||
}
|
||||
const studyMeta = DicomMetadataStore.getStudy(StudyInstanceUID);
|
||||
if (!studyMeta?.series?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const instanceMeta = studyMeta.series[0].instances[0];
|
||||
const { StudyDate, StudyDescription } = instanceMeta;
|
||||
|
||||
return (
|
||||
<StudySummary
|
||||
date={formatDate(StudyDate)}
|
||||
description={StudyDescription}
|
||||
></StudySummary>
|
||||
);
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import React from 'react';
|
||||
import { Toolbox } from '@ohif/ui-next';
|
||||
import PanelSegmentation from './panels/PanelSegmentation';
|
||||
import ActiveViewportWindowLevel from './components/ActiveViewportWindowLevel';
|
||||
import PanelMeasurementTable from './panels/PanelMeasurement';
|
||||
import PanelMeasurement from './panels/PanelMeasurement';
|
||||
|
||||
const getPanelModule = ({ commandsManager, servicesManager, extensionManager }: withAppTypes) => {
|
||||
const wrappedPanelSegmentation = ({ configuration }) => {
|
||||
@@ -59,7 +59,7 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
|
||||
|
||||
const wrappedPanelMeasurement = ({ configuration }) => {
|
||||
return (
|
||||
<PanelMeasurementTable
|
||||
<PanelMeasurement
|
||||
commandsManager={commandsManager}
|
||||
servicesManager={servicesManager}
|
||||
extensionManager={extensionManager}
|
||||
|
||||
@@ -62,10 +62,7 @@ export function useMeasurements(servicesManager, { measurementFilter }) {
|
||||
|
||||
useEffect(() => {
|
||||
const updateDisplayMeasurements = () => {
|
||||
let measurements = measurementService.getMeasurements();
|
||||
if (measurementFilter) {
|
||||
measurements = measurements.filter(measurementFilter);
|
||||
}
|
||||
let measurements = measurementService.getMeasurements(measurementFilter);
|
||||
const mappedMeasurements = measurements.map(m =>
|
||||
mapMeasurementToDisplay(m, displaySetService)
|
||||
);
|
||||
|
||||
@@ -53,6 +53,7 @@ import PanelSegmentation from './panels/PanelSegmentation';
|
||||
import PanelMeasurement from './panels/PanelMeasurement';
|
||||
import DicomUpload from './components/DicomUpload/DicomUpload';
|
||||
import { useSegmentations } from './hooks/useSegmentations';
|
||||
import { StudySummaryFromMetadata } from './components/StudySummaryFromMetadata';
|
||||
|
||||
const { imageRetrieveMetadataProvider } = cornerstone.utilities;
|
||||
|
||||
@@ -254,5 +255,6 @@ export {
|
||||
PanelSegmentation,
|
||||
PanelMeasurement,
|
||||
DicomUpload,
|
||||
StudySummaryFromMetadata,
|
||||
};
|
||||
export default cornerstoneExtension;
|
||||
@@ -1,19 +1,29 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { utils } from '@ohif/core';
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
import { MeasurementTable } from '@ohif/ui-next';
|
||||
import debounce from 'lodash.debounce';
|
||||
import { useMeasurements } from '../hooks/useMeasurements';
|
||||
import { showLabelAnnotationPopup, colorPickerDialog } from '@ohif/extension-default';
|
||||
|
||||
export default function PanelMeasurementTable({
|
||||
const {
|
||||
filterAdditionalFindings: filterAdditionalFinding,
|
||||
filterOr,
|
||||
filterAny,
|
||||
} = utils.MeasurementFilters;
|
||||
|
||||
export type withAppAndFilters = withAppTypes & {
|
||||
measurementFilter: (item) => boolean;
|
||||
};
|
||||
|
||||
export default function PanelMeasurement({
|
||||
servicesManager,
|
||||
commandsManager,
|
||||
customHeader,
|
||||
measurementFilter,
|
||||
}: withAppTypes): React.ReactNode {
|
||||
measurementFilter = filterAny,
|
||||
}: withAppAndFilters): React.ReactNode {
|
||||
const measurementsPanelRef = useRef(null);
|
||||
|
||||
const [viewportGrid] = useViewportGrid();
|
||||
const { measurementService, customizationService, uiDialogService } = servicesManager.services;
|
||||
const { measurementService } = servicesManager.services;
|
||||
|
||||
const displayMeasurements = useMeasurements(servicesManager, {
|
||||
measurementFilter,
|
||||
@@ -27,75 +37,37 @@ export default function PanelMeasurementTable({
|
||||
}
|
||||
}, [displayMeasurements.length]);
|
||||
|
||||
const onMeasurementItemClickHandler = (uid: string, isActive: boolean) => {
|
||||
if (isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
const measurements = [...displayMeasurements];
|
||||
const measurement = measurements.find(m => m.uid === uid);
|
||||
|
||||
measurements.forEach(m => (m.isActive = m.uid !== uid ? false : true));
|
||||
measurement.isActive = true;
|
||||
};
|
||||
|
||||
const jumpToImage = (uid: string) => {
|
||||
measurementService.jumpToMeasurement(viewportGrid.activeViewportId, uid);
|
||||
onMeasurementItemClickHandler(uid, true);
|
||||
};
|
||||
|
||||
const removeMeasurement = (uid: string) => {
|
||||
measurementService.remove(uid);
|
||||
};
|
||||
|
||||
const renameMeasurement = (uid: string) => {
|
||||
jumpToImage(uid);
|
||||
const labelConfig = customizationService.get('measurementLabels');
|
||||
const measurement = measurementService.getMeasurement(uid);
|
||||
showLabelAnnotationPopup(measurement, uiDialogService, labelConfig).then(val => {
|
||||
measurementService.update(
|
||||
uid,
|
||||
{
|
||||
...val,
|
||||
},
|
||||
true
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const changeColorMeasurement = (uid: string) => {
|
||||
const { color } = measurementService.getMeasurement(uid);
|
||||
const rgbaColor = {
|
||||
r: color[0],
|
||||
g: color[1],
|
||||
b: color[2],
|
||||
a: color[3] / 255.0,
|
||||
const bindCommand = (name: string | string[], options?) => {
|
||||
return (uid: string) => {
|
||||
commandsManager.run(name, { ...options, uid });
|
||||
};
|
||||
colorPickerDialog(uiDialogService, rgbaColor, (newRgbaColor, actionId) => {
|
||||
if (actionId === 'cancel') {
|
||||
return;
|
||||
}
|
||||
|
||||
const color = [newRgbaColor.r, newRgbaColor.g, newRgbaColor.b, newRgbaColor.a * 255.0];
|
||||
// segmentationService.setSegmentColor(viewportId, segmentationId, segmentIndex, color);
|
||||
});
|
||||
};
|
||||
|
||||
const toggleLockMeasurement = (uid: string) => {
|
||||
measurementService.toggleLockMeasurement(uid);
|
||||
};
|
||||
const jumpToImage = bindCommand('jumpToMeasurement', { displayMeasurements });
|
||||
const removeMeasurement = bindCommand('removeMeasurement');
|
||||
const renameMeasurement = bindCommand(['jumpToMeasurement', 'renameMeasurement'], {
|
||||
displayMeasurements,
|
||||
});
|
||||
const toggleLockMeasurement = bindCommand('toggleLockMeasurement');
|
||||
const toggleVisibilityMeasurement = bindCommand('toggleVisibilityMeasurement');
|
||||
|
||||
const toggleVisibilityMeasurement = (uid: string) => {
|
||||
measurementService.toggleVisibilityMeasurement(uid);
|
||||
};
|
||||
const additionalFilter = filterAdditionalFinding(measurementService);
|
||||
|
||||
const measurements = displayMeasurements.filter(
|
||||
dm => dm.measurementType !== measurementService.VALUE_TYPES.POINT && dm.referencedImageId
|
||||
item => !additionalFilter(item) && measurementFilter(item)
|
||||
);
|
||||
const additionalFindings = displayMeasurements.filter(
|
||||
dm => dm.measurementType === measurementService.VALUE_TYPES.POINT && dm.referencedImageId
|
||||
item => additionalFilter(item) && measurementFilter(item)
|
||||
);
|
||||
|
||||
const onArgs = {
|
||||
onClick: jumpToImage,
|
||||
onDelete: removeMeasurement,
|
||||
onToggleVisibility: toggleVisibilityMeasurement,
|
||||
onToggleLocked: toggleLockMeasurement,
|
||||
onRename: renameMeasurement,
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
@@ -104,13 +76,10 @@ export default function PanelMeasurementTable({
|
||||
data-cy={'trackedMeasurements-panel'}
|
||||
>
|
||||
<MeasurementTable
|
||||
key="tracked"
|
||||
title="Measurements"
|
||||
data={measurements}
|
||||
onClick={jumpToImage}
|
||||
onDelete={removeMeasurement}
|
||||
onToggleVisibility={toggleVisibilityMeasurement}
|
||||
onToggleLocked={toggleLockMeasurement}
|
||||
onRename={renameMeasurement}
|
||||
{...onArgs}
|
||||
// onColor={changeColorMeasurement}
|
||||
>
|
||||
<MeasurementTable.Header>
|
||||
@@ -129,14 +98,10 @@ export default function PanelMeasurementTable({
|
||||
</MeasurementTable>
|
||||
{additionalFindings.length > 0 && (
|
||||
<MeasurementTable
|
||||
key="additional"
|
||||
data={additionalFindings}
|
||||
title="Additional Findings"
|
||||
onClick={jumpToImage}
|
||||
onDelete={removeMeasurement}
|
||||
onToggleVisibility={toggleVisibilityMeasurement}
|
||||
onToggleLocked={toggleLockMeasurement}
|
||||
onRename={renameMeasurement}
|
||||
// onColor={changeColorMeasurement}
|
||||
{...onArgs}
|
||||
>
|
||||
<MeasurementTable.Body />
|
||||
</MeasurementTable>
|
||||
|
||||
@@ -562,27 +562,13 @@ const commandsModule = ({
|
||||
};
|
||||
|
||||
const definitions = {
|
||||
showContextMenu: {
|
||||
commandFn: actions.showContextMenu,
|
||||
},
|
||||
closeContextMenu: {
|
||||
commandFn: actions.closeContextMenu,
|
||||
},
|
||||
clearMeasurements: {
|
||||
commandFn: actions.clearMeasurements,
|
||||
},
|
||||
displayNotification: {
|
||||
commandFn: actions.displayNotification,
|
||||
},
|
||||
setHangingProtocol: {
|
||||
commandFn: actions.setHangingProtocol,
|
||||
},
|
||||
toggleHangingProtocol: {
|
||||
commandFn: actions.toggleHangingProtocol,
|
||||
},
|
||||
navigateHistory: {
|
||||
commandFn: actions.navigateHistory,
|
||||
},
|
||||
showContextMenu: actions.showContextMenu,
|
||||
closeContextMenu: actions.closeContextMenu,
|
||||
clearMeasurements: actions.clearMeasurements,
|
||||
displayNotification: actions.displayNotification,
|
||||
setHangingProtocol: actions.setHangingProtocol,
|
||||
toggleHangingProtocol: actions.toggleHangingProtocol,
|
||||
navigateHistory: actions.navigateHistory,
|
||||
nextStage: {
|
||||
commandFn: actions.deltaStage,
|
||||
options: { direction: 1 },
|
||||
@@ -591,18 +577,10 @@ const commandsModule = ({
|
||||
commandFn: actions.deltaStage,
|
||||
options: { direction: -1 },
|
||||
},
|
||||
setViewportGridLayout: {
|
||||
commandFn: actions.setViewportGridLayout,
|
||||
},
|
||||
toggleOneUp: {
|
||||
commandFn: actions.toggleOneUp,
|
||||
},
|
||||
openDICOMTagViewer: {
|
||||
commandFn: actions.openDICOMTagViewer,
|
||||
},
|
||||
updateViewportDisplaySet: {
|
||||
commandFn: actions.updateViewportDisplaySet,
|
||||
},
|
||||
setViewportGridLayout: actions.setViewportGridLayout,
|
||||
toggleOneUp: actions.toggleOneUp,
|
||||
openDICOMTagViewer: actions.openDICOMTagViewer,
|
||||
updateViewportDisplaySet: actions.updateViewportDisplaySet,
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { PanelMeasurement } from '@ohif/extension-cornerstone';
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
import { StudySummary } from '@ohif/ui-next';
|
||||
import { Button, Icons } from '@ohif/ui-next';
|
||||
import { DicomMetadataStore, utils } from '@ohif/core';
|
||||
import { useViewportGrid } from '@ohif/ui-next';
|
||||
import { Button, Icons } from '@ohif/ui-next';
|
||||
import { PanelMeasurement, StudySummaryFromMetadata } from '@ohif/extension-cornerstone';
|
||||
import { useTrackedMeasurements } from '../getContextModule';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const { downloadCSVReport, formatDate } = utils;
|
||||
|
||||
const DISPLAY_STUDY_SUMMARY_INITIAL_VALUE = {
|
||||
key: undefined, //
|
||||
date: '', // '07-Sep-2010',
|
||||
modality: '', // 'CT',
|
||||
description: '', // 'CHEST/ABD/PELVIS W CONTRAST',
|
||||
};
|
||||
const { filterAnd, filterPlanarMeasurement, filterAny, filterMeasurementsBySeriesUID } =
|
||||
utils.MeasurementFilters;
|
||||
|
||||
function PanelMeasurementTableTracking({
|
||||
servicesManager,
|
||||
@@ -22,52 +14,12 @@ function PanelMeasurementTableTracking({
|
||||
commandsManager,
|
||||
}: withAppTypes) {
|
||||
const [viewportGrid] = useViewportGrid();
|
||||
const { t } = useTranslation('MeasurementTable');
|
||||
const { measurementService, customizationService } = servicesManager.services;
|
||||
const { customizationService } = servicesManager.services;
|
||||
const [trackedMeasurements, sendTrackedMeasurementsEvent] = useTrackedMeasurements();
|
||||
const { trackedStudy, trackedSeries } = trackedMeasurements.context;
|
||||
const [displayStudySummary, setDisplayStudySummary] = useState(
|
||||
DISPLAY_STUDY_SUMMARY_INITIAL_VALUE
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const updateDisplayStudySummary = async () => {
|
||||
if (trackedMeasurements.matches('tracking') && trackedStudy) {
|
||||
const studyMeta = DicomMetadataStore.getStudy(trackedStudy);
|
||||
if (!studyMeta || !studyMeta.series || studyMeta.series.length === 0) {
|
||||
console.debug('Study metadata not available');
|
||||
return;
|
||||
}
|
||||
|
||||
const instanceMeta = studyMeta.series[0].instances[0];
|
||||
const { StudyDate, StudyDescription } = instanceMeta;
|
||||
|
||||
const modalities = new Set();
|
||||
studyMeta.series.forEach(series => {
|
||||
if (trackedSeries.includes(series.SeriesInstanceUID)) {
|
||||
modalities.add(series.instances[0].Modality);
|
||||
}
|
||||
});
|
||||
const modality = Array.from(modalities).join('/');
|
||||
|
||||
setDisplayStudySummary(prevSummary => {
|
||||
if (prevSummary.key !== trackedStudy) {
|
||||
return {
|
||||
key: trackedStudy,
|
||||
date: StudyDate,
|
||||
modality,
|
||||
description: StudyDescription,
|
||||
};
|
||||
}
|
||||
return prevSummary;
|
||||
});
|
||||
} else if (!trackedStudy) {
|
||||
setDisplayStudySummary(DISPLAY_STUDY_SUMMARY_INITIAL_VALUE);
|
||||
}
|
||||
};
|
||||
|
||||
updateDisplayStudySummary();
|
||||
}, [trackedMeasurements, trackedStudy, trackedSeries]);
|
||||
const measurementFilter = trackedStudy
|
||||
? filterAnd(filterPlanarMeasurement, filterMeasurementsBySeriesUID(trackedSeries))
|
||||
: filterPlanarMeasurement;
|
||||
|
||||
const { disableEditing } = customizationService.getCustomization(
|
||||
'PanelMeasurement.disableEditing',
|
||||
@@ -79,20 +31,12 @@ function PanelMeasurementTableTracking({
|
||||
|
||||
return (
|
||||
<>
|
||||
{displayStudySummary.key && (
|
||||
<StudySummary
|
||||
date={formatDate(displayStudySummary.date)}
|
||||
description={displayStudySummary.description}
|
||||
/>
|
||||
)}
|
||||
<StudySummaryFromMetadata StudyInstanceUID={trackedStudy} />
|
||||
<PanelMeasurement
|
||||
servicesManager={servicesManager}
|
||||
extensionManager={extensionManager}
|
||||
commandsManager={commandsManager}
|
||||
measurementFilter={measurement =>
|
||||
trackedStudy === measurement.referenceStudyUID &&
|
||||
trackedSeries.includes(measurement.referenceSeriesUID)
|
||||
}
|
||||
measurementFilter={measurementFilter}
|
||||
customHeader={({ additionalFindings, measurements }) => {
|
||||
const disabled = additionalFindings.length === 0 && measurements.length === 0;
|
||||
|
||||
@@ -108,14 +52,9 @@ function PanelMeasurementTableTracking({
|
||||
variant="ghost"
|
||||
className="pl-1.5"
|
||||
onClick={() => {
|
||||
const measurements = measurementService.getMeasurements();
|
||||
const trackedMeasurements = measurements.filter(
|
||||
m =>
|
||||
trackedStudy === m.referenceStudyUID &&
|
||||
trackedSeries.includes(m.referenceSeriesUID)
|
||||
);
|
||||
|
||||
downloadCSVReport(trackedMeasurements);
|
||||
commandsManager.runCommand('downloadCSVMeasurementsReport', {
|
||||
measurementFilter,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Icons.Download className="h-5 w-5" />
|
||||
@@ -140,7 +79,7 @@ function PanelMeasurementTableTracking({
|
||||
variant="ghost"
|
||||
className="pl-0.5"
|
||||
onClick={() => {
|
||||
measurementService.clearMeasurements();
|
||||
commandsManager.runCommand('clearMeasurements', { measurementFilter });
|
||||
}}
|
||||
>
|
||||
<Icons.Delete />
|
||||
|
||||
Reference in new issue
Block a user