feat(panel and auth): fix study panel to not rely on priors and add token param to url (#3381)

* fix: multiframe

* fix the unnecessary use of prior since some servers dont like it

* add authentication via token in url

* add data citation

* add resources

* upgrade packages

* yarn lock

* apply review comments
This commit is contained in:
Alireza authored and GitHub committed 2023-05-11 10:01:33 -04:00
1 parent cba57a1b65
commit 84cb709b44
24 files changed
+387 -211

No files matched your search

@@ -200,6 +200,7 @@ function createDicomLocalApi(dicomLocalConfig) {
displaySet.images.forEach(instance => {
const NumberOfFrames = instance.NumberOfFrames;
if (NumberOfFrames > 1) {
// in multiframe we start at frame 1
for (let i = 1; i <= NumberOfFrames; i++) {
const imageId = this.getImageIdsForInstance({
instance,
@@ -12,7 +12,7 @@ const { sortStudyInstances, formatDate } = utils;
function PanelStudyBrowser({
servicesManager,
getImageSrc,
getStudiesForPatientByStudyInstanceUID,
getStudiesForPatientByMRN,
requestDisplaySetCreationForStudy,
dataSource,
}) {
@@ -64,12 +64,24 @@ function PanelStudyBrowser({
useEffect(() => {
// Fetch all studies for the patient in each primary study
async function fetchStudiesForPatient(StudyInstanceUID) {
const qidoStudiesForPatient =
(await getStudiesForPatientByStudyInstanceUID(StudyInstanceUID)) || [];
// current study qido
const qidoForStudyUID = await dataSource.query.studies.search({
studyInstanceUid: StudyInstanceUID,
});
let qidoStudiesForPatient = qidoForStudyUID;
// try to fetch the prior studies based on the patientID if the
// server can respond.
try {
qidoStudiesForPatient = await getStudiesForPatientByMRN(
qidoForStudyUID
);
} catch (error) {
console.warn(error);
}
// TODO: This should be "naturalized DICOM JSON" studies
const mappedStudies = _mapDataSourceStudies(qidoStudiesForPatient);
const actuallyMappedStudies = mappedStudies.map(qidoStudy => {
return {
studyInstanceUid: qidoStudy.StudyInstanceUID,
@@ -77,29 +89,27 @@ function PanelStudyBrowser({
description: qidoStudy.StudyDescription,
modalities: qidoStudy.ModalitiesInStudy,
numInstances: qidoStudy.NumInstances,
// displaySets: []
};
});
if (isMounted.current) {
setStudyDisplayList(prevArray => {
const ret = [...prevArray];
for (const study of actuallyMappedStudies) {
if (
!prevArray.find(
it => it.studyInstanceUid === study.studyInstanceUid
)
) {
ret.push(study);
}
setStudyDisplayList(prevArray => {
const ret = [...prevArray];
for (const study of actuallyMappedStudies) {
if (
!prevArray.find(
it => it.studyInstanceUid === study.studyInstanceUid
)
) {
ret.push(study);
}
return ret;
});
}
}
return ret;
});
}
StudyInstanceUIDs.forEach(sid => fetchStudiesForPatient(sid));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [StudyInstanceUIDs, getStudiesForPatientByStudyInstanceUID]);
}, [StudyInstanceUIDs, getStudiesForPatientByMRN]);
// // ~~ Initial Thumbnails
useEffect(() => {
@@ -254,7 +264,7 @@ PanelStudyBrowser.propTypes = {
getImageIdsForDisplaySet: PropTypes.func.isRequired,
}).isRequired,
getImageSrc: PropTypes.func.isRequired,
getStudiesForPatientByStudyInstanceUID: PropTypes.func.isRequired,
getStudiesForPatientByMRN: PropTypes.func.isRequired,
requestDisplaySetCreationForStudy: PropTypes.func.isRequired,
};
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
//
import PanelStudyBrowser from './PanelStudyBrowser';
import getImageSrcFromImageId from './getImageSrcFromImageId';
import getStudiesForPatientByStudyInstanceUID from './getStudiesForPatientByStudyInstanceUID';
import getStudiesForPatientByMRN from './getStudiesForPatientByMRN';
import requestDisplaySetCreationForStudy from './requestDisplaySetCreationForStudy';
/**
@@ -21,7 +21,7 @@ function WrappedPanelStudyBrowser({
// TODO: This should be made available a different way; route should have
// already determined our datasource
const dataSource = extensionManager.getDataSources()[0];
const _getStudiesForPatientByStudyInstanceUID = getStudiesForPatientByStudyInstanceUID.bind(
const _getStudiesForPatientByMRN = getStudiesForPatientByMRN.bind(
null,
dataSource
);
@@ -38,9 +38,7 @@ function WrappedPanelStudyBrowser({
servicesManager={servicesManager}
dataSource={dataSource}
getImageSrc={_getImageSrcFromImageId}
getStudiesForPatientByStudyInstanceUID={
_getStudiesForPatientByStudyInstanceUID
}
getStudiesForPatientByMRN={_getStudiesForPatientByMRN}
requestDisplaySetCreationForStudy={_requestDisplaySetCreationForStudy}
/>
);
@@ -6,7 +6,7 @@ function getImageSrcFromImageId(cornerstone, imageId) {
return new Promise((resolve, reject) => {
const canvas = document.createElement('canvas');
cornerstone.utilities
.loadImageToCanvas(canvas, imageId)
.loadImageToCanvas({ canvas, imageId })
.then(imageId => {
resolve(canvas.toDataURL());
})
@@ -0,0 +1,11 @@
async function getStudiesForPatientByMRN(dataSource, qidoForStudyUID) {
if (qidoForStudyUID && qidoForStudyUID.length && qidoForStudyUID[0].mrn) {
return dataSource.query.studies.search({
patientId: qidoForStudyUID[0].mrn,
});
}
console.log('No mrn found for', qidoForStudyUID);
return qidoForStudyUID;
}
export default getStudiesForPatientByMRN;
@@ -1,29 +0,0 @@
async function getStudiesForPatientByStudyInstanceUID(
dataSource,
StudyInstanceUID
) {
if (StudyInstanceUID === undefined) {
return;
}
// TODO: The `DicomMetadataStore` should short-circuit both of these requests
// Data _could_ be here from route query, or if using JSON data source
// We could also force this to "await" these values being available in the DICOMStore?
// Kind of like promise fulfillment in @cornerstonejs/dicom-image-loader when there are multiple
// outgoing requests for the same data
const getStudyResult = await dataSource.query.studies.search({
studyInstanceUid: StudyInstanceUID,
});
// TODO: To Erik's point, the data source likely shouldn't deviate from
// Naturalized DICOM JSON when returning. It makes things like this awkward (mrn)
if (getStudyResult && getStudyResult.length && getStudyResult[0].mrn) {
return dataSource.query.studies.search({
patientId: getStudyResult[0].mrn,
});
}
console.log('No mrn found for', getStudyResult);
// The original study we KNOW belongs to the same set, so just return it
return getStudyResult;
}
export default getStudiesForPatientByStudyInstanceUID;
+7 -3
View File
@@ -7,7 +7,7 @@ import getSopClassHandlerModule from './getSopClassHandlerModule.js';
import getToolbarModule from './getToolbarModule';
import getCommandsModule from './commandsModule';
import getHangingProtocolModule from './getHangingProtocolModule';
import getStudiesForPatientByStudyInstanceUID from './Panels/getStudiesForPatientByStudyInstanceUID';
import getStudiesForPatientByMRN from './Panels/getStudiesForPatientByMRN';
import getCustomizationModule from './getCustomizationModule';
import { id } from './id.js';
import preRegistration from './init';
@@ -34,7 +34,7 @@ const defaultExtension: Types.Extensions.Extension = {
{
name: 'common',
exports: {
getStudiesForPatientByStudyInstanceUID,
getStudiesForPatientByMRN,
},
},
];
@@ -45,4 +45,8 @@ const defaultExtension: Types.Extensions.Extension = {
export default defaultExtension;
export { ContextMenuController, CustomizeableContextMenuTypes };
export {
ContextMenuController,
CustomizeableContextMenuTypes,
getStudiesForPatientByMRN,
};