IDC2345: implement thumbnails footnotes UI for segmentation series inconsistencies warning (#2364)
* IDC2345: implement thumbnails footnotes UI for segmentation series inconsistencies warning
This commit is contained in:
parent
a08caa9bdb
commit
07b272e024
@ -190,6 +190,11 @@ const SegmentationPanel = ({
|
||||
refreshSegmentations
|
||||
);
|
||||
|
||||
document.addEventListener(
|
||||
'extensiondicomsegmentationsegloadingfailed',
|
||||
cleanSegmentationComboBox
|
||||
);
|
||||
|
||||
/*
|
||||
* These are specific to each element;
|
||||
* Need to iterate cornerstone-tools tracked enabled elements?
|
||||
@ -207,6 +212,10 @@ const SegmentationPanel = ({
|
||||
'extensiondicomsegmentationsegloaded',
|
||||
refreshSegmentations
|
||||
);
|
||||
document.removeEventListener(
|
||||
'extensiondicomsegmentationsegloadingfailed',
|
||||
cleanSegmentationComboBox
|
||||
);
|
||||
cornerstoneTools.store.state.enabledElements.forEach(enabledElement =>
|
||||
enabledElement.removeEventListener(
|
||||
'cornerstonetoolslabelmapmodified',
|
||||
@ -216,6 +225,17 @@ const SegmentationPanel = ({
|
||||
};
|
||||
}, [activeIndex, viewports]);
|
||||
|
||||
const cleanSegmentationComboBox = () => {
|
||||
setState(state => ({
|
||||
...state,
|
||||
segmentsHidden: [],
|
||||
segmentNumbers: [],
|
||||
labelMapList: [],
|
||||
segmentList: [],
|
||||
isDisabled: true,
|
||||
}));
|
||||
}
|
||||
|
||||
const refreshSegmentations = () => {
|
||||
const activeViewport = getActiveViewport();
|
||||
const isDisabled = !activeViewport || !activeViewport.StudyInstanceUID;
|
||||
@ -277,7 +297,10 @@ const SegmentationPanel = ({
|
||||
activeViewport.SeriesInstanceUID
|
||||
);
|
||||
|
||||
return referencedSegDisplaysets.map((displaySet, index) => {
|
||||
const filteredReferencedSegDisplaysets = referencedSegDisplaysets.filter(
|
||||
(segDisplay => segDisplay.loadError !== true && segDisplay.isLoaded));
|
||||
|
||||
return filteredReferencedSegDisplaysets.map((displaySet, index) => {
|
||||
const {
|
||||
labelmapIndex,
|
||||
originLabelMapIndex,
|
||||
|
||||
@ -63,11 +63,12 @@ export default function getSopClassHandlerModule({ servicesManager }) {
|
||||
metadata,
|
||||
};
|
||||
|
||||
segDisplaySet.getSourceDisplaySet = function(studies) {
|
||||
return getSourceDisplaySet(studies, segDisplaySet);
|
||||
segDisplaySet.getSourceDisplaySet = function(studies, activateLabelMap = true, onDisplaySetLoadFailureHandler) {
|
||||
return getSourceDisplaySet(studies, segDisplaySet, activateLabelMap, onDisplaySetLoadFailureHandler);
|
||||
};
|
||||
|
||||
segDisplaySet.load = async function(referencedDisplaySet, studies) {
|
||||
segDisplaySet.isLoading = true;
|
||||
segDisplaySet.isLoaded = true;
|
||||
const { StudyInstanceUID } = referencedDisplaySet;
|
||||
const segArrayBuffer = await DicomLoaderService.findDicomDataPromise(
|
||||
@ -82,59 +83,53 @@ export default function getSopClassHandlerModule({ servicesManager }) {
|
||||
StudyInstanceUID,
|
||||
referencedDisplaySet.SeriesInstanceUID
|
||||
);
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let results;
|
||||
try {
|
||||
results = _parseSeg(segArrayBuffer, imageIds);
|
||||
} catch (error) {
|
||||
segDisplaySet.isLoaded = false;
|
||||
segDisplaySet.loadError = true;
|
||||
reject(error);
|
||||
}
|
||||
const {
|
||||
labelmapBufferArray,
|
||||
segMetadata,
|
||||
segmentsOnFrame,
|
||||
segmentsOnFrameArray,
|
||||
} = results;
|
||||
|
||||
let labelmapIndex;
|
||||
if (labelmapBufferArray.length > 1) {
|
||||
let labelmapIndexes = [];
|
||||
for (let i = 0; i < labelmapBufferArray.length; ++i) {
|
||||
labelmapIndexes.push(
|
||||
await loadSegmentation(
|
||||
imageIds,
|
||||
segDisplaySet,
|
||||
labelmapBufferArray[i],
|
||||
segMetadata,
|
||||
segmentsOnFrame,
|
||||
segmentsOnFrameArray[i]
|
||||
)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Since overlapping segmentations have virtual labelmaps,
|
||||
* originLabelMapIndex is used in the panel to select the correct dropdown value.
|
||||
*/
|
||||
segDisplaySet.hasOverlapping = true;
|
||||
segDisplaySet.originLabelMapIndex = labelmapIndexes[0];
|
||||
labelmapIndex = labelmapIndexes[0];
|
||||
console.warn('Overlapping segmentations!');
|
||||
} else {
|
||||
labelmapIndex = await loadSegmentation(
|
||||
imageIds,
|
||||
segDisplaySet,
|
||||
labelmapBufferArray[0],
|
||||
segMetadata,
|
||||
segmentsOnFrame,
|
||||
[]
|
||||
const results = await _parseSeg(segArrayBuffer, imageIds);
|
||||
if (results === undefined) {
|
||||
return;
|
||||
}
|
||||
const {
|
||||
labelmapBufferArray,
|
||||
segMetadata,
|
||||
segmentsOnFrame,
|
||||
segmentsOnFrameArray,
|
||||
} = results;
|
||||
let labelmapIndex;
|
||||
if (labelmapBufferArray.length > 1) {
|
||||
let labelmapIndexes = [];
|
||||
for (let i = 0; i < labelmapBufferArray.length; ++i) {
|
||||
labelmapIndexes.push(
|
||||
await loadSegmentation(
|
||||
imageIds,
|
||||
segDisplaySet,
|
||||
labelmapBufferArray[i],
|
||||
segMetadata,
|
||||
segmentsOnFrame,
|
||||
segmentsOnFrameArray[i]
|
||||
)
|
||||
);
|
||||
}
|
||||
resolve(labelmapIndex);
|
||||
});
|
||||
/**
|
||||
* Since overlapping segments have virtual labelmaps,
|
||||
* originLabelMapIndex is used in the panel to select the correct dropdown value.
|
||||
*/
|
||||
segDisplaySet.hasOverlapping = true;
|
||||
segDisplaySet.originLabelMapIndex = labelmapIndexes[0];
|
||||
labelmapIndex = labelmapIndexes[0];
|
||||
console.warn('Overlapping segments!');
|
||||
} else {
|
||||
labelmapIndex = await loadSegmentation(
|
||||
imageIds,
|
||||
segDisplaySet,
|
||||
labelmapBufferArray[0],
|
||||
segMetadata,
|
||||
segmentsOnFrame,
|
||||
[]
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
segDisplaySet.isLoading = false;
|
||||
return segDisplaySet;
|
||||
},
|
||||
};
|
||||
|
||||
@ -3,10 +3,12 @@ import { classes } from '@ohif/core';
|
||||
|
||||
const { ImageSet } = classes;
|
||||
|
||||
export default function getSourceDisplaySet(studies, segDisplaySet) {
|
||||
export default function getSourceDisplaySet(studies, segDisplaySet, activateLabelMap = true, onDisplaySetLoadFailureHandler) {
|
||||
const referencedDisplaySet = _getReferencedDisplaySet(segDisplaySet, studies);
|
||||
|
||||
setActiveLabelmap(referencedDisplaySet, studies, segDisplaySet);
|
||||
if (activateLabelMap) {
|
||||
setActiveLabelmap(referencedDisplaySet, studies, segDisplaySet, undefined, onDisplaySetLoadFailureHandler);
|
||||
}
|
||||
|
||||
return referencedDisplaySet;
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ export default async function setActiveLabelmap(
|
||||
displaySet,
|
||||
callback = () => {},
|
||||
onDisplaySetLoadFailure = err => {
|
||||
throw new Error(err.message);
|
||||
console.error(err.message);
|
||||
}
|
||||
) {
|
||||
const studyMetadata = studyMetadataManager.get(
|
||||
@ -47,17 +47,24 @@ export default async function setActiveLabelmap(
|
||||
return labelmapIndex;
|
||||
}
|
||||
|
||||
if (!displaySet.isLoaded) {
|
||||
const loadPromise = displaySet.load(referencedDisplaySet, studies);
|
||||
if (displaySet.isLoading) {
|
||||
return activeLabelmapIndex;
|
||||
}
|
||||
|
||||
loadPromise.catch(error => {
|
||||
if (!displaySet.isLoaded) {
|
||||
try {
|
||||
await displaySet.load(referencedDisplaySet, studies);
|
||||
} catch (error) {
|
||||
displaySet.isLoaded = false;
|
||||
displaySet.isLoading = false;
|
||||
displaySet.loadError = true;
|
||||
onDisplaySetLoadFailure(error);
|
||||
|
||||
// Return old index.
|
||||
return activeLabelmapIndex;
|
||||
});
|
||||
const event = new CustomEvent('extensiondicomsegmentationsegloadingfailed');
|
||||
document.dispatchEvent(event);
|
||||
|
||||
await loadPromise;
|
||||
return activeLabelmapIndex;
|
||||
}
|
||||
}
|
||||
|
||||
labelmapIndex =
|
||||
|
||||
@ -45,9 +45,11 @@ import studyMetadataManager from './studyMetadataManager';
|
||||
* @param {string} referencedDisplaySet.studyInstanceUid
|
||||
* @param {Array} referencedDisplaySet.sopClassUids
|
||||
* @param {Study[]} studies Collection of studies
|
||||
* @param {object} logger
|
||||
* @param {object} snackbar
|
||||
* @returns void
|
||||
*/
|
||||
const loadAndCacheDerivedDisplaySets = (referencedDisplaySet, studies) => {
|
||||
async function loadAndCacheDerivedDisplaySets(referencedDisplaySet, studies, logger, snackbar) {
|
||||
const { StudyInstanceUID, SeriesInstanceUID } = referencedDisplaySet;
|
||||
const promises = [];
|
||||
const studyMetadata = studyMetadataManager.get(StudyInstanceUID);
|
||||
@ -78,11 +80,10 @@ const loadAndCacheDerivedDisplaySets = (referencedDisplaySet, studies) => {
|
||||
});
|
||||
|
||||
// For each type, see if any are loaded, if not load the most recent.
|
||||
Object.keys(displaySetsPerModality).forEach(key => {
|
||||
await Promise.all(Object.keys(displaySetsPerModality).map(async (key) => {
|
||||
const displaySets = displaySetsPerModality[key];
|
||||
|
||||
const isLoaded = displaySets.some(displaySet => displaySet.isLoaded);
|
||||
|
||||
if (isLoaded) {
|
||||
return;
|
||||
}
|
||||
@ -107,20 +108,27 @@ const loadAndCacheDerivedDisplaySets = (referencedDisplaySet, studies) => {
|
||||
|
||||
recentDisplaySet.isLoading = true;
|
||||
|
||||
promises.push(recentDisplaySet.load(referencedDisplaySet, studies));
|
||||
});
|
||||
try {
|
||||
await recentDisplaySet.load(referencedDisplaySet, studies);
|
||||
} catch (error) {
|
||||
logger.error({ error, message: error.message });
|
||||
snackbar.show({
|
||||
title: 'Error loading derived display set:',
|
||||
message: error.message,
|
||||
type: 'error',
|
||||
error,
|
||||
autoClose: false,
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
Promise.all(promises).then(() => {
|
||||
/*
|
||||
* TODO: Improve the way we notify parts of the app
|
||||
* that depends on derived display sets to be loaded.
|
||||
* (Implement pubsub for better tracking of derived display sets)
|
||||
*/
|
||||
const event = new CustomEvent('deriveddisplaysetsloadedandcached');
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
|
||||
return promises;
|
||||
/*
|
||||
* TODO: Improve the way we notify parts of the app
|
||||
* that depends on derived display sets to be loaded.
|
||||
* (Implement pubsub for better tracking of derived display sets)
|
||||
*/
|
||||
const event = new CustomEvent('deriveddisplaysetsloadedandcached');
|
||||
document.dispatchEvent(event);
|
||||
};
|
||||
|
||||
export default loadAndCacheDerivedDisplaySets;
|
||||
|
||||
@ -41,19 +41,7 @@ const ViewportGrid = function(props) {
|
||||
useEffect(() => {
|
||||
if (isStudyLoaded) {
|
||||
viewportData.forEach(displaySet => {
|
||||
const promises = loadAndCacheDerivedDisplaySets(displaySet, studies);
|
||||
promises.forEach(promise => {
|
||||
promise.catch(error => {
|
||||
logger.error({ error, message: error.message });
|
||||
snackbar.show({
|
||||
title: 'Error loading derived display set:',
|
||||
message: error.message,
|
||||
type: 'error',
|
||||
error,
|
||||
autoClose: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
loadAndCacheDerivedDisplaySets(displaySet, studies, logger, snackbar);
|
||||
});
|
||||
}
|
||||
}, [studies, viewportData, isStudyLoaded, snackbar]);
|
||||
|
||||
@ -3,6 +3,7 @@ import { connect } from 'react-redux';
|
||||
import { StudyBrowser } from '@ohif/ui';
|
||||
import cloneDeep from 'lodash.clonedeep';
|
||||
import findDisplaySetByUID from './findDisplaySetByUID';
|
||||
import { servicesManager } from './../App.js';
|
||||
|
||||
const { studyMetadataManager } = OHIF.utils;
|
||||
|
||||
@ -48,8 +49,22 @@ const mapDispatchToProps = (dispatch, ownProps) => {
|
||||
|
||||
if (displaySet.isDerived) {
|
||||
const { Modality } = displaySet;
|
||||
if (Modality === 'SEG' && servicesManager) {
|
||||
const {LoggerService, UINotificationService} = servicesManager.services;
|
||||
const onDisplaySetLoadFailureHandler = error => {
|
||||
LoggerService.error({ error, message: error.message });
|
||||
UINotificationService.show({
|
||||
title: 'DICOM Segmentation Loader',
|
||||
message: error.message,
|
||||
type: 'error',
|
||||
autoClose: true,
|
||||
});
|
||||
};
|
||||
|
||||
displaySet = displaySet.getSourceDisplaySet(ownProps.studyMetadata);
|
||||
displaySet = displaySet.getSourceDisplaySet(ownProps.studyMetadata, true, onDisplaySetLoadFailureHandler);
|
||||
} else {
|
||||
displaySet = displaySet.getSourceDisplaySet(ownProps.studyMetadata);
|
||||
}
|
||||
|
||||
if (!displaySet) {
|
||||
throw new Error(
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { useLogger } from '@ohif/ui';
|
||||
|
||||
import OHIF, { MODULE_TYPES, DICOMSR } from '@ohif/core';
|
||||
import { withDialog } from '@ohif/ui';
|
||||
@ -13,6 +14,7 @@ import SidePanel from './../components/SidePanel.js';
|
||||
import ErrorBoundaryDialog from './../components/ErrorBoundaryDialog';
|
||||
import { extensionManager } from './../App.js';
|
||||
import { ReconstructionIssues } from './../../../core/src/enums.js';
|
||||
import dcmjs from 'dcmjs';
|
||||
|
||||
// Contexts
|
||||
import WhiteLabelingContext from '../context/WhiteLabelingContext.js';
|
||||
@ -21,6 +23,7 @@ import AppContext from '../context/AppContext';
|
||||
|
||||
import './Viewer.css';
|
||||
import { finished } from 'stream';
|
||||
import { cornerstoneWADOImageLoader } from 'cornerstone-wado-image-loader';
|
||||
|
||||
class Viewer extends Component {
|
||||
static propTypes = {
|
||||
@ -369,59 +372,144 @@ class Viewer extends Component {
|
||||
export default withDialog(Viewer);
|
||||
|
||||
/**
|
||||
* Async function to check if there are any inconsistences in the series
|
||||
* (i.e. reconstructable to a 3D volume). If not reconstructable MPR is disabled.
|
||||
* The actual computations are done in isDisplaySetReconstructable.
|
||||
* Async function to check if there are any inconsistences in the series.
|
||||
*
|
||||
* For segmentation checks that the geometry is consistent with the source images:
|
||||
* 1) no frames out of plane;
|
||||
* 2) have the same width and height.
|
||||
*
|
||||
* For reconstructable 3D volume:
|
||||
* 1) Is series multiframe?
|
||||
* 2) Do the frames have different dimensions/numer of components/orientations?
|
||||
* 2) Do the frames have different dimensions/number of components/orientations?
|
||||
* 3) Has the series any missing frames or irregular spacing?
|
||||
* 4) Is the series 4D?
|
||||
*
|
||||
* If not reconstructable, MPR is disabled.
|
||||
* The actual computations are done in isDisplaySetReconstructable.
|
||||
*
|
||||
* @param {*object} displaySet
|
||||
* @returns {[string]} an array of strings containing the warnings
|
||||
*/
|
||||
const _checkForSeriesInconsistencesWarnings = async function (displaySet) {
|
||||
// NOTE: at the moment this function is async even if it does not perfom any heavy calculation.
|
||||
// We may add or move here some of the computations
|
||||
// done when creating the displaySet (see makeDisplaySet and isDisplaySetReconstructable).
|
||||
// the thumbnail footnotes warning react element is already set up to handle a promise.
|
||||
const _checkForSeriesInconsistencesWarnings = async function (displaySet, studies) {
|
||||
const warningsList = [];
|
||||
if (displaySet.warningIssues && displaySet.warningIssues.length !== 0) {
|
||||
displaySet.warningIssues.forEach(warning => {
|
||||
switch (warning) {
|
||||
case ReconstructionIssues.DATASET_4D:
|
||||
warningsList.push("The dataset is 4D.");
|
||||
break;
|
||||
case ReconstructionIssues.VARYING_IMAGESDIMENSIONS:
|
||||
warningsList.push("The dataset frames have different dimensions (rows, columns).");
|
||||
break;
|
||||
case ReconstructionIssues.VARYING_IMAGESCOMPONENTS:
|
||||
warningsList.push("The dataset frames have different components (Sample per pixel).");
|
||||
break;
|
||||
case ReconstructionIssues.VARYING_IMAGESORIENTATION:
|
||||
warningsList.push("The dataset frames have different orientation.");
|
||||
break;
|
||||
case ReconstructionIssues.IRREGULAR_SPACING:
|
||||
warningsList.push("The dataset frames have different pixel spacing.");
|
||||
break;
|
||||
case ReconstructionIssues.MULTIFFRAMES:
|
||||
warningsList.push("The dataset is a multiframes.");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
if (displaySet.Modality !== 'SEG') {
|
||||
if (displaySet.warningIssues && displaySet.warningIssues.length !== 0) {
|
||||
displaySet.warningIssues.forEach(warning => {
|
||||
switch (warning) {
|
||||
case ReconstructionIssues.DATASET_4D:
|
||||
warningsList.push('The dataset is 4D.');
|
||||
break;
|
||||
case ReconstructionIssues.VARYING_IMAGESDIMENSIONS:
|
||||
warningsList.push('The dataset frames have different dimensions (rows, columns).');
|
||||
break;
|
||||
case ReconstructionIssues.VARYING_IMAGESCOMPONENTS:
|
||||
warningsList.push('The dataset frames have different components (Sample per pixel).');
|
||||
break;
|
||||
case ReconstructionIssues.VARYING_IMAGESORIENTATION:
|
||||
warningsList.push('The dataset frames have different orientation.');
|
||||
break;
|
||||
case ReconstructionIssues.IRREGULAR_SPACING:
|
||||
warningsList.push('The dataset frames have different pixel spacing.');
|
||||
break;
|
||||
case ReconstructionIssues.MULTIFFRAMES:
|
||||
warningsList.push('The dataset is a multiframes.');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
warningsList.push('The datasets is not a reconstructable 3D volume. MPR mode is not available.');
|
||||
}
|
||||
|
||||
if (displaySet.missingFrames &&
|
||||
(!displaySet.warningIssues ||
|
||||
(displaySet.warningIssues && !displaySet.warningIssues.find(warn => warn === ReconstructionIssues.DATASET_4D)))) {
|
||||
warningsList.push('The datasets is missing frames: ' + displaySet.missingFrames + '.');
|
||||
}
|
||||
} else {
|
||||
const segMetadata = displaySet.metadata;
|
||||
if (!segMetadata) {
|
||||
return warningsList;
|
||||
}
|
||||
|
||||
const sourceDisplaySet = displaySet.getSourceDisplaySet(studies, false);
|
||||
const imageIds = sourceDisplaySet.images.map(image => image.getImageId());
|
||||
if (!imageIds || imageIds.length === 0) {
|
||||
return warningsList;
|
||||
}
|
||||
|
||||
for (
|
||||
let i = 0, groupsLen = segMetadata.PerFrameFunctionalGroupsSequence.length;
|
||||
i < groupsLen;
|
||||
++i
|
||||
) {
|
||||
const PerFrameFunctionalGroups = segMetadata.PerFrameFunctionalGroupsSequence[i];
|
||||
if (!PerFrameFunctionalGroups) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let SourceImageSequence = undefined;
|
||||
if (segMetadata.SourceImageSequence) {
|
||||
SourceImageSequence = segMetadata.SourceImageSequence[i];
|
||||
} else if (PerFrameFunctionalGroups.DerivationImageSequence) {
|
||||
SourceImageSequence =
|
||||
PerFrameFunctionalGroups.DerivationImageSequence
|
||||
.SourceImageSequence;
|
||||
}
|
||||
if (!SourceImageSequence) {
|
||||
if (warningsList.length === 0) {
|
||||
const warningMessage = 'The segmentation ' +
|
||||
'has frames out of plane respect to the source images.';
|
||||
warningsList.push(warningMessage);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const {
|
||||
ReferencedSOPInstanceUID,
|
||||
} = SourceImageSequence;
|
||||
|
||||
const imageId = imageIds.find(imageId => {
|
||||
const sopCommonModule = cornerstone.metaData.get(
|
||||
"sopCommonModule",
|
||||
imageId
|
||||
);
|
||||
if (!sopCommonModule) {
|
||||
return;
|
||||
}
|
||||
|
||||
return sopCommonModule.sopInstanceUID === ReferencedSOPInstanceUID;
|
||||
});
|
||||
|
||||
if (!imageId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const sourceImageMetadata = cornerstone.metaData.get(
|
||||
"instance",
|
||||
imageId
|
||||
);
|
||||
if (
|
||||
segMetadata.Rows !== sourceImageMetadata.Rows ||
|
||||
segMetadata.Columns !== sourceImageMetadata.Columns
|
||||
) {
|
||||
const warningMessage = 'The segmentation ' +
|
||||
'has frames with different geometry ' +
|
||||
'dimensions (Rows and Columns) respect to the source images.';
|
||||
warningsList.push(warningMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (warningsList.length !== 0) {
|
||||
const warningMessage = 'The segmentation format is not supported yet. ' +
|
||||
'The segmentation data (segments) could not be loaded.';
|
||||
warningsList.push(warningMessage);
|
||||
}
|
||||
}
|
||||
|
||||
if (displaySet.missingFrames &&
|
||||
(!displaySet.warningIssues ||
|
||||
(displaySet.warningIssues && !displaySet.warningIssues.find(warn => warn === ReconstructionIssues.DATASET_4D)))) {
|
||||
warningsList.push('The datasets is missing frames: ' + displaySet.missingFrames + '.');
|
||||
}
|
||||
|
||||
return warningsList
|
||||
return warningsList;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -463,7 +551,7 @@ const _mapStudiesToThumbnails = function(studies) {
|
||||
altImageText = displaySet.Modality ? displaySet.Modality : 'UN';
|
||||
}
|
||||
|
||||
const hasWarnings = _checkForSeriesInconsistencesWarnings(displaySet)
|
||||
const hasWarnings = _checkForSeriesInconsistencesWarnings(displaySet, studies);
|
||||
|
||||
return {
|
||||
imageId,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import './ViewerMain.css';
|
||||
|
||||
import { servicesManager } from './../App.js';
|
||||
import { Component } from 'react';
|
||||
import { ConnectedViewportGrid } from './../components/ViewportGrid/index.js';
|
||||
import PropTypes from 'prop-types';
|
||||
@ -141,7 +141,22 @@ class ViewerMain extends Component {
|
||||
|
||||
if (displaySet.isDerived) {
|
||||
const { Modality } = displaySet;
|
||||
displaySet = displaySet.getSourceDisplaySet(this.props.studies);
|
||||
if (Modality === 'SEG' && servicesManager) {
|
||||
const {LoggerService, UINotificationService} = servicesManager.services;
|
||||
const onDisplaySetLoadFailureHandler = error => {
|
||||
LoggerService.error({ error, message: error.message });
|
||||
UINotificationService.show({
|
||||
title: 'DICOM Segmentation Loader',
|
||||
message: error.message,
|
||||
type: 'error',
|
||||
autoClose: true,
|
||||
});
|
||||
};
|
||||
|
||||
displaySet = displaySet.getSourceDisplaySet(this.props.studies, true, onDisplaySetLoadFailureHandler);
|
||||
} else {
|
||||
displaySet = displaySet.getSourceDisplaySet(this.props.studies);
|
||||
}
|
||||
|
||||
if (!displaySet) {
|
||||
throw new Error(
|
||||
|
||||
@ -301,7 +301,6 @@ function ViewerRetrieveStudyData({
|
||||
});
|
||||
|
||||
setStudies(studies);
|
||||
setIsStudyLoaded(true);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -6619,10 +6619,10 @@ dateformat@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
||||
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
|
||||
|
||||
dcmjs@0.18.3:
|
||||
version "0.18.3"
|
||||
resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.18.3.tgz#17d5a23d96b63264b8a1a859e4cb000b3e20495b"
|
||||
integrity sha512-nmG6wEBcIMnadXAZOTcXwacBv+lrh8bqPwIKZwdy7AkdihLEwI6/OnyP+PYjzcdltuPu9wOQcKZionvXuCteag==
|
||||
dcmjs@0.18.4:
|
||||
version "0.18.4"
|
||||
resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.18.4.tgz#70643e665dda373ed83bc7228981350f07dc3849"
|
||||
integrity sha512-iprngI79c6iAJRq16/K8JNVvUvrSzN7u6yGES8pl2/KvtbSIRP2LEXwbZ01bKtXz9syEtiQNvdtTR+gTZtd4Sw==
|
||||
dependencies:
|
||||
"@babel/polyfill" "^7.8.3"
|
||||
"@babel/runtime" "^7.8.4"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user