capture changes
This commit is contained in:
parent
64f9c4a387
commit
a323157c62
5
.vscode/extensions.json
vendored
5
.vscode/extensions.json
vendored
@ -5,6 +5,9 @@
|
|||||||
"dbaeumer.vscode-eslint",
|
"dbaeumer.vscode-eslint",
|
||||||
"mikestead.dotenv",
|
"mikestead.dotenv",
|
||||||
"bungcip.better-toml",
|
"bungcip.better-toml",
|
||||||
"silvenon.mdx"
|
"silvenon.mdx",
|
||||||
|
"gruntfuggly.todo-tree",
|
||||||
|
"wayou.vscode-todo-highlight",
|
||||||
|
"bradlc.vscode-tailwindcss"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -87,6 +87,9 @@ function createDicomWebApi(dicomWebConfig) {
|
|||||||
},
|
},
|
||||||
retrieve: {
|
retrieve: {
|
||||||
series: {
|
series: {
|
||||||
|
// TODO: change queryParams to `StudyInstanceUID` for now?
|
||||||
|
// Conduct query, return a promise like others
|
||||||
|
// Await this call and add to dicomMetadataStore after receiving result
|
||||||
metadata: (queryParams, callback) => {
|
metadata: (queryParams, callback) => {
|
||||||
let { StudyInstanceUIDs } = urlUtil.parse(queryParams, true);
|
let { StudyInstanceUIDs } = urlUtil.parse(queryParams, true);
|
||||||
|
|
||||||
@ -125,6 +128,32 @@ function createDicomWebApi(dicomWebConfig) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
retrieveSeriesMetadata: async ({ StudyInstanceUID } = {}) => {
|
||||||
|
if (!StudyInstanceUID) {
|
||||||
|
throw new Error(
|
||||||
|
'Unable to query for SeriesMetadata without StudyInstanceUID'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Series
|
||||||
|
const seriesPromises = await retrieveStudyMetadata(
|
||||||
|
naturalizeDataset,
|
||||||
|
StudyInstanceUID,
|
||||||
|
enableStudyLazyLoad
|
||||||
|
);
|
||||||
|
|
||||||
|
// Async load series, store as retrieved
|
||||||
|
function storeInstances(instances) {
|
||||||
|
const naturalizedInstances = instances.map(naturalizeDataset);
|
||||||
|
|
||||||
|
dicomMetadataStore.addInstances(naturalizedInstances);
|
||||||
|
}
|
||||||
|
|
||||||
|
seriesPromises.forEach(async seriesPromise => {
|
||||||
|
const instances = await seriesPromise;
|
||||||
|
storeInstances(instances);
|
||||||
|
});
|
||||||
|
},
|
||||||
getImageIdsForDisplaySet(displaySet) {
|
getImageIdsForDisplaySet(displaySet) {
|
||||||
const images = displaySet.images;
|
const images = displaySet.images;
|
||||||
const imageIds = [];
|
const imageIds = [];
|
||||||
|
|||||||
@ -1,42 +1,53 @@
|
|||||||
import React, { useState, useEffect, useCallback } from 'react';
|
import React, { useState, useEffect, useCallback } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { StudyBrowser } from '@ohif/ui';
|
//
|
||||||
|
import { StudyBrowser, useImageViewer } from '@ohif/ui';
|
||||||
import { dicomMetadataStore } from '@ohif/core';
|
import { dicomMetadataStore } from '@ohif/core';
|
||||||
|
// This has to import from somewhere else...
|
||||||
|
|
||||||
function PanelStudyBrowser({
|
function PanelStudyBrowser({
|
||||||
servicesManager,
|
DisplaySetService,
|
||||||
getImageSrc,
|
getImageSrc,
|
||||||
getStudiesByPatientId,
|
getStudiesForPatientByStudyInstanceUID,
|
||||||
|
requestDisplaySetCreationForStudy,
|
||||||
dataSource,
|
dataSource,
|
||||||
}) {
|
}) {
|
||||||
const { DisplaySetService } = servicesManager.services;
|
|
||||||
const currentDisplaySets = DisplaySetService.activeDisplaySets || [];
|
const currentDisplaySets = DisplaySetService.activeDisplaySets || [];
|
||||||
// TODO: Deep copy? Or By IDs?
|
// TODO: Deep copy? Or By IDs?
|
||||||
// TODO: May need to be mapped to a different shape?
|
// TODO: May need to be mapped to a different shape?
|
||||||
|
|
||||||
const [displaySets, setDisplaySets] = useState(currentDisplaySets);
|
const [displaySets, setDisplaySets] = useState(currentDisplaySets);
|
||||||
// TODO: Grab from URL, or pass in as part of contract to panels
|
|
||||||
const [primaryStudyInstanceUID, setPrimaryStudyInstanceUID] = useState();
|
|
||||||
const [activeTabName, setActiveTabName] = useState('primary');
|
const [activeTabName, setActiveTabName] = useState('primary');
|
||||||
const [studyData, setStudyData] = useState([]);
|
|
||||||
const [studiesForPatient, setStudiesForPatient] = useState([]);
|
|
||||||
const [thumbnailImageSrcMap, setThumbnailImageSrcMap] = useState(new Map());
|
const [thumbnailImageSrcMap, setThumbnailImageSrcMap] = useState(new Map());
|
||||||
|
const [{ StudyInstanceUIDs }, dispatch] = useImageViewer();
|
||||||
|
// vv What we want to render
|
||||||
|
const [studyDisplayList, setStudyDisplayList] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const mappedStudiesFromDataSource = _mapDataSourceStudies(
|
// Fetch all studies for the patient in each primary study
|
||||||
studiesForPatient
|
async function fetchStudiesForPatient(StudyInstanceUID) {
|
||||||
);
|
const qidoStudiesForPatient =
|
||||||
|
(await getStudiesForPatientByStudyInstanceUID(StudyInstanceUID)) || [];
|
||||||
|
|
||||||
const newStudyData = _mergeStudyDataAndDataSourceStudies(
|
const mappedStudies = _mapDataSourceStudies(qidoStudiesForPatient);
|
||||||
studyData,
|
|
||||||
mappedStudiesFromDataSource,
|
const updatedStudyDisplayList = _mergeStudyDisplayListAndDataSourceStudies(
|
||||||
|
studyDisplayList,
|
||||||
|
mappedStudies,
|
||||||
displaySets
|
displaySets
|
||||||
);
|
);
|
||||||
|
|
||||||
addDisplaySetsToStudyData(newStudyData, displaySets, thumbnailImageSrcMap);
|
addDisplaySetsToStudyDisplayList(
|
||||||
|
updatedStudyDisplayList,
|
||||||
|
displaySets,
|
||||||
|
thumbnailImageSrcMap
|
||||||
|
);
|
||||||
|
|
||||||
|
setStudyDisplayList(updatedStudyDisplayList);
|
||||||
|
}
|
||||||
|
|
||||||
|
StudyInstanceUIDs.forEach(sid => fetchStudiesForPatient(sid));
|
||||||
|
}, [StudyInstanceUIDs, getStudiesForPatientByStudyInstanceUID]);
|
||||||
|
|
||||||
setStudyData(newStudyData);
|
|
||||||
}, [studiesForPatient, thumbnailImageSrcMap]);
|
|
||||||
|
|
||||||
const updateThumbnailMap = (displaySetInstanceUID, imageSrc) => {
|
const updateThumbnailMap = (displaySetInstanceUID, imageSrc) => {
|
||||||
setThumbnailImageSrcMap(
|
setThumbnailImageSrcMap(
|
||||||
@ -68,7 +79,7 @@ function PanelStudyBrowser({
|
|||||||
setDisplaySets(displaySetsUI);
|
setDisplaySets(displaySetsUI);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addDisplaySetsToStudyData(
|
function addDisplaySetsToStudyDisplayList(
|
||||||
studies,
|
studies,
|
||||||
displaySets,
|
displaySets,
|
||||||
thumbnailImageSrcMap
|
thumbnailImageSrcMap
|
||||||
@ -101,40 +112,9 @@ function PanelStudyBrowser({
|
|||||||
const imageSrc = await getImageSrc(imageId);
|
const imageSrc = await getImageSrc(imageId);
|
||||||
updateThumbnailMap(uid, imageSrc);
|
updateThumbnailMap(uid, imageSrc);
|
||||||
});
|
});
|
||||||
|
|
||||||
const firstDisplaySet = newDisplaySets[0];
|
|
||||||
if (!studiesForPatient.length && firstDisplaySet) {
|
|
||||||
async function doAsyncStuff() {
|
|
||||||
const qidoStuff = await _getStudiesByPatientId(
|
|
||||||
firstDisplaySet,
|
|
||||||
getStudiesByPatientId
|
|
||||||
);
|
|
||||||
|
|
||||||
setStudiesForPatient(qidoStuff);
|
|
||||||
setPrimaryStudyInstanceUID(firstDisplaySet.StudyInstanceUID);
|
|
||||||
}
|
|
||||||
|
|
||||||
doAsyncStuff();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// TODO: IF WE HAVE OUR FIRST DISPLAY SET...
|
|
||||||
// QIDO AWAY
|
|
||||||
// IF WE DO NOT, WAIT FOR FIRST DISPLAY_SETS_ADDED
|
|
||||||
const firstDisplaySet = displaySets[0];
|
|
||||||
if (firstDisplaySet) {
|
|
||||||
async function doAsyncStuff() {
|
|
||||||
const qidoStuff = await _getStudiesByPatientId(
|
|
||||||
firstDisplaySet,
|
|
||||||
getStudiesByPatientId
|
|
||||||
);
|
|
||||||
setPrimaryStudyInstanceUID(firstDisplaySet.StudyInstanceUID);
|
|
||||||
setStudiesForPatient(qidoStuff);
|
|
||||||
}
|
|
||||||
doAsyncStuff();
|
|
||||||
}
|
|
||||||
|
|
||||||
const subscriptions = [
|
const subscriptions = [
|
||||||
DisplaySetService.subscribe(
|
DisplaySetService.subscribe(
|
||||||
DisplaySetService.EVENTS.DISPLAY_SETS_ADDED,
|
DisplaySetService.EVENTS.DISPLAY_SETS_ADDED,
|
||||||
@ -151,12 +131,12 @@ function PanelStudyBrowser({
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const primary = studyData.find(
|
const primaryStudies = studyDisplayList.filter(study =>
|
||||||
study => study.studyInstanceUid === primaryStudyInstanceUID
|
StudyInstanceUIDs.includes(study.studyInstanceUid)
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: Filter allStudies to dates within one year of current date
|
// TODO: Filter allStudies to dates within one year of current date
|
||||||
const recentStudies = studyData.filter(study => {
|
const recentStudies = studyDisplayList.filter(study => {
|
||||||
return true; // TODO: check study.date
|
return true; // TODO: check study.date
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -164,7 +144,7 @@ function PanelStudyBrowser({
|
|||||||
{
|
{
|
||||||
name: 'primary',
|
name: 'primary',
|
||||||
label: 'Primary',
|
label: 'Primary',
|
||||||
studies: primary ? [primary] : [],
|
studies: primaryStudies || [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'recent',
|
name: 'recent',
|
||||||
@ -174,63 +154,42 @@ function PanelStudyBrowser({
|
|||||||
{
|
{
|
||||||
name: 'all',
|
name: 'all',
|
||||||
label: 'All',
|
label: 'All',
|
||||||
studies: studyData,
|
studies: studyDisplayList,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
function onClickStudy(StudyInstanceUID) {
|
// TODO: Should "expand" appropriate study (already handled by component?)
|
||||||
const study = studyData.find(a => a.studyInstanceUid === StudyInstanceUID);
|
// TODO: Should not fire this on "close"
|
||||||
if (study && study.displaySets && study.displaySets.length) {
|
function _handleStudyClick(StudyInstanceUID) {
|
||||||
return;
|
requestDisplaySetCreationForStudy(DisplaySetService, StudyInstanceUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.warn(`onClickStudy: ${StudyInstanceUID}`);
|
|
||||||
// TODO: This is weird, why can't the data source just be used as
|
|
||||||
// as function that doesn't expect a query string?
|
|
||||||
const queryParams = `?StudyInstanceUIDs=${StudyInstanceUID}`;
|
|
||||||
|
|
||||||
dataSource.retrieve.series.metadata(
|
|
||||||
queryParams,
|
|
||||||
DisplaySetService.makeDisplaySets
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const memoOnClickStudy = useCallback(
|
|
||||||
StudyInstanceUID => {
|
|
||||||
onClickStudy(StudyInstanceUID);
|
|
||||||
},
|
|
||||||
[studyData]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StudyBrowser
|
<StudyBrowser
|
||||||
activeTabName={activeTabName}
|
activeTabName={activeTabName}
|
||||||
tabs={tabs}
|
tabs={tabs}
|
||||||
onClickStudy={memoOnClickStudy}
|
onClickStudy={_handleStudyClick}
|
||||||
onSetTabActive={setActiveTabName}
|
onSetTabActive={setActiveTabName}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelStudyBrowser.propTypes = {
|
PanelStudyBrowser.propTypes = {
|
||||||
|
DisplaySetService: PropTypes.shape({
|
||||||
|
EVENTS: PropTypes.object.isRequired,
|
||||||
|
hasDisplaySetsForStudy: PropTypes.func.isRequired,
|
||||||
|
subscribe: PropTypes.func.isRequired,
|
||||||
|
}).isRequired,
|
||||||
dataSource: PropTypes.shape({
|
dataSource: PropTypes.shape({
|
||||||
getImageIdsForDisplaySet: PropTypes.func.isRequired,
|
getImageIdsForDisplaySet: PropTypes.func.isRequired,
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
getImageSrc: PropTypes.func.isRequired,
|
getImageSrc: PropTypes.func.isRequired,
|
||||||
getStudiesByPatientId: PropTypes.func.isRequired,
|
getStudiesForPatientByStudyInstanceUID: PropTypes.func.isRequired,
|
||||||
|
requestDisplaySetCreationForStudy: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PanelStudyBrowser;
|
export default PanelStudyBrowser;
|
||||||
|
|
||||||
async function _getStudiesByPatientId(displaySet, getStudiesByPatientId) {
|
|
||||||
const study = dicomMetadataStore.getStudy(displaySet.StudyInstanceUID);
|
|
||||||
const instance = study.series[0].instances[0];
|
|
||||||
const PatientID = instance.PatientID;
|
|
||||||
const studiesByPatientId = await getStudiesByPatientId(PatientID);
|
|
||||||
|
|
||||||
return studiesByPatientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps from the DataSource's format to a naturalized object
|
* Maps from the DataSource's format to a naturalized object
|
||||||
*
|
*
|
||||||
@ -253,11 +212,14 @@ function _mapDataSourceStudies(studies) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function _mergeStudyDataAndDataSourceStudies(studyData, mappedQidoStudies) {
|
function _mergeStudyDisplayListAndDataSourceStudies(
|
||||||
|
studyDisplayList,
|
||||||
|
mappedQidoStudies
|
||||||
|
) {
|
||||||
return mappedQidoStudies.map(qidoStudy => {
|
return mappedQidoStudies.map(qidoStudy => {
|
||||||
const { StudyInstanceUID } = qidoStudy;
|
const { StudyInstanceUID } = qidoStudy;
|
||||||
const existing =
|
const existing =
|
||||||
studyData.find(a => a.studyInstanceUid === StudyInstanceUID) || {};
|
studyDisplayList.find(a => a.studyInstanceUid === StudyInstanceUID) || {};
|
||||||
|
|
||||||
return Object.assign(
|
return Object.assign(
|
||||||
{},
|
{},
|
||||||
@ -275,39 +237,3 @@ function _mergeStudyDataAndDataSourceStudies(studyData, mappedQidoStudies) {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function _mergeStudyDataAndInstanceStudies(studyData, mappedInstanceStudies) {
|
|
||||||
const merged = [];
|
|
||||||
mappedInstanceStudies.map(studyFromInstances => {
|
|
||||||
const existing = studyData.find(
|
|
||||||
a => a.studyInstanceUid === studyFromInstances.studyInstanceUid
|
|
||||||
);
|
|
||||||
|
|
||||||
if (existing) {
|
|
||||||
merged.push(
|
|
||||||
Object.assign({}, existing, {
|
|
||||||
displaySets: studyFromInstances.displaySets,
|
|
||||||
modalities: studyFromInstances.modalities,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
merged.push(studyFromInstances);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return merged;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _mapStudyFromInstance(StudyInstanceUID) {
|
|
||||||
const study = dicomMetadataStore.getStudy(StudyInstanceUID);
|
|
||||||
const anInstance = study.series[0].instances[0];
|
|
||||||
|
|
||||||
return {
|
|
||||||
studyInstanceUid: StudyInstanceUID,
|
|
||||||
date: anInstance.StudyDate, // TODO: Format this date to DD-MMM-YYYY
|
|
||||||
description: anInstance.StudyDescription,
|
|
||||||
displaySets: [],
|
|
||||||
numInstances: 0,
|
|
||||||
modalitiesSet: new Set(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
|
|||||||
//
|
//
|
||||||
import PanelStudyBrowser from './PanelStudyBrowser';
|
import PanelStudyBrowser from './PanelStudyBrowser';
|
||||||
import getImageSrcFromImageId from './getImageSrcFromImageId';
|
import getImageSrcFromImageId from './getImageSrcFromImageId';
|
||||||
|
import getStudiesForPatientByStudyInstanceUID from './getStudiesForPatientByStudyInstanceUID';
|
||||||
|
import requestDisplaySetCreationForStudy from './requestDisplaySetCreationForStudy';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps the PanelStudyBrowser and provides features afforded by managers/services
|
* Wraps the PanelStudyBrowser and provides features afforded by managers/services
|
||||||
@ -16,20 +18,30 @@ function WrappedPanelStudyBrowser({
|
|||||||
extensionManager,
|
extensionManager,
|
||||||
servicesManager,
|
servicesManager,
|
||||||
}) {
|
}) {
|
||||||
// Note: this feels odd
|
// TODO: This should be made available a different way; route should have
|
||||||
|
// already determined our datasource
|
||||||
const dataSource = extensionManager.getDataSources('dicomweb')[0];
|
const dataSource = extensionManager.getDataSources('dicomweb')[0];
|
||||||
const getStudiesByPatientId = patientId =>
|
const _getStudiesForPatientByStudyInstanceUID = getStudiesForPatientByStudyInstanceUID.bind(
|
||||||
dataSource.query.studies.search({ patientId });
|
null,
|
||||||
|
dataSource
|
||||||
|
);
|
||||||
const _getImageSrcFromImageId = _createGetImageSrcFromImageIdFn(
|
const _getImageSrcFromImageId = _createGetImageSrcFromImageIdFn(
|
||||||
commandsManager.getCommand.bind(commandsManager)
|
commandsManager.getCommand.bind(commandsManager)
|
||||||
);
|
);
|
||||||
|
const _requestDisplaySetCreationForStudy = requestDisplaySetCreationForStudy.bind(
|
||||||
|
null,
|
||||||
|
dataSource
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PanelStudyBrowser
|
<PanelStudyBrowser
|
||||||
servicesManager={servicesManager}
|
DisplaySetService={servicesManager.services.DisplaySetService}
|
||||||
dataSource={dataSource}
|
dataSource={dataSource}
|
||||||
getImageSrc={_getImageSrcFromImageId}
|
getImageSrc={_getImageSrcFromImageId}
|
||||||
getStudiesByPatientId={getStudiesByPatientId}
|
getStudiesForPatientByStudyInstanceUID={
|
||||||
|
_getStudiesForPatientByStudyInstanceUID
|
||||||
|
}
|
||||||
|
requestDisplaySetCreationForStudy={_requestDisplaySetCreationForStudy}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -60,6 +72,7 @@ function _createGetImageSrcFromImageIdFn(getCommand) {
|
|||||||
WrappedPanelStudyBrowser.propTypes = {
|
WrappedPanelStudyBrowser.propTypes = {
|
||||||
commandsManager: PropTypes.object.isRequired,
|
commandsManager: PropTypes.object.isRequired,
|
||||||
extensionManager: PropTypes.object.isRequired,
|
extensionManager: PropTypes.object.isRequired,
|
||||||
|
servicesManager: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default WrappedPanelStudyBrowser;
|
export default WrappedPanelStudyBrowser;
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
async function getStudiesForPatientByStudyInstanceUID(
|
||||||
|
dataSource,
|
||||||
|
StudyInstanceUID
|
||||||
|
) {
|
||||||
|
// 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 cornerstone-wado-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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getStudiesForPatientByStudyInstanceUID;
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
function requestDisplaySetCreationForStudy(
|
||||||
|
dataSource,
|
||||||
|
DisplaySetService,
|
||||||
|
StudyInstanceUID
|
||||||
|
) {
|
||||||
|
// TODO: is this already short-circuited by the map of Retrieve promises?
|
||||||
|
if (DisplaySetService.hasDisplaySetsForStudy(StudyInstanceUID)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataSource.retrieveSeriesMetadata({ StudyInstanceUID });
|
||||||
|
|
||||||
|
// 1. Update DICOMStore
|
||||||
|
// 2. DICOMStore shoots out events
|
||||||
|
// 3. IFF instance is in study/series that is "active" (being viewed?), displaySet is created?
|
||||||
|
// 4. IFF not, just store is updated
|
||||||
|
// 5. IFF active studies change, splitting logic is refired?
|
||||||
|
|
||||||
|
// DisplaySetService.makeDisplaySets
|
||||||
|
}
|
||||||
|
|
||||||
|
export default requestDisplaySetCreationForStudy;
|
||||||
@ -107,6 +107,12 @@ export default class DisplaySetService {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
hasDisplaySetsForStudy(StudyInstanceUID) {
|
||||||
|
return displaySetCache.some(
|
||||||
|
displaySet => displaySet.StudyInstanceUID === StudyInstanceUID
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
makeDisplaySetForInstances(instances) {
|
makeDisplaySetForInstances(instances) {
|
||||||
const instance = instances[0];
|
const instance = instances[0];
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,9 @@ export {
|
|||||||
withModal,
|
withModal,
|
||||||
ViewportDialogProvider,
|
ViewportDialogProvider,
|
||||||
useViewportDialog,
|
useViewportDialog,
|
||||||
|
ImageViewerContext,
|
||||||
|
ImageViewerProvider,
|
||||||
|
useImageViewer,
|
||||||
} from './src/contextProviders';
|
} from './src/contextProviders';
|
||||||
|
|
||||||
/** COMPONENTS */
|
/** COMPONENTS */
|
||||||
|
|||||||
18
platform/ui/src/contextProviders/ImageViewerProvider.jsx
Normal file
18
platform/ui/src/contextProviders/ImageViewerProvider.jsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import React, { createContext, useContext, useReducer } from 'react';
|
||||||
|
|
||||||
|
// export const IMAGE_VIEWER_DEFAULT_VALUE = {
|
||||||
|
// StudyInstanceUIDs: [],
|
||||||
|
// setImageViewer: () => {},
|
||||||
|
// };
|
||||||
|
|
||||||
|
export const ImageViewerContext = createContext();
|
||||||
|
|
||||||
|
export function ImageViewerProvider({ reducer, initialState, children }) {
|
||||||
|
return (
|
||||||
|
<ImageViewerContext.Provider value={useReducer(reducer, initialState)}>
|
||||||
|
{children}
|
||||||
|
</ImageViewerContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useImageViewer = () => useContext(ImageViewerContext);
|
||||||
@ -10,4 +10,10 @@ export {
|
|||||||
useViewportDialog,
|
useViewportDialog,
|
||||||
} from './ViewportDialogProvider';
|
} from './ViewportDialogProvider';
|
||||||
|
|
||||||
|
export {
|
||||||
|
ImageViewerContext,
|
||||||
|
ImageViewerProvider,
|
||||||
|
useImageViewer,
|
||||||
|
} from './ImageViewerProvider';
|
||||||
|
|
||||||
export { default as DragAndDropProvider } from './DragAndDropProvider';
|
export { default as DragAndDropProvider } from './DragAndDropProvider';
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
import React, { useEffect, useCallback } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
//
|
//
|
||||||
import { ToolBarManager } from '@ohif/core';
|
import { ToolBarManager } from '@ohif/core';
|
||||||
import { DragAndDropProvider } from '@ohif/ui';
|
import { DragAndDropProvider, ImageViewerProvider } from '@ohif/ui';
|
||||||
//
|
//
|
||||||
import { useQuery } from '@hooks';
|
import { useQuery } from '@hooks';
|
||||||
import ViewportGrid from '@components/ViewportGrid';
|
import ViewportGrid from '@components/ViewportGrid';
|
||||||
import Compose from './Compose';
|
import Compose from './Compose';
|
||||||
//import DisplaySetCreator from './DisplaySetCreator';
|
|
||||||
|
|
||||||
export default function ModeRoute({
|
export default function ModeRoute({
|
||||||
location,
|
location,
|
||||||
@ -22,6 +21,10 @@ export default function ModeRoute({
|
|||||||
const queryStudyInstanceUIDs = query.get('StudyInstanceUIDs');
|
const queryStudyInstanceUIDs = query.get('StudyInstanceUIDs');
|
||||||
const { StudyInstanceUIDs: paramsStudyInstanceUIDs } = useParams();
|
const { StudyInstanceUIDs: paramsStudyInstanceUIDs } = useParams();
|
||||||
const StudyInstanceUIDs = queryStudyInstanceUIDs || paramsStudyInstanceUIDs;
|
const StudyInstanceUIDs = queryStudyInstanceUIDs || paramsStudyInstanceUIDs;
|
||||||
|
const StudyInstanceUIDsAsArray =
|
||||||
|
StudyInstanceUIDs && Array.isArray(StudyInstanceUIDs)
|
||||||
|
? StudyInstanceUIDs
|
||||||
|
: [StudyInstanceUIDs];
|
||||||
|
|
||||||
const { extensions, sopClassHandlers } = mode;
|
const { extensions, sopClassHandlers } = mode;
|
||||||
// TODO:
|
// TODO:
|
||||||
@ -89,7 +92,15 @@ export default function ModeRoute({
|
|||||||
);
|
);
|
||||||
}, [mode, dataSourceName, location]);
|
}, [mode, dataSourceName, location]);
|
||||||
|
|
||||||
|
const reducer = (state, action) => {
|
||||||
|
console.log(state, action);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<ImageViewerProvider
|
||||||
|
initialState={{ StudyInstanceUIDs: StudyInstanceUIDsAsArray }}
|
||||||
|
reducer={reducer}
|
||||||
|
>
|
||||||
<CombinedContextProvider>
|
<CombinedContextProvider>
|
||||||
{/* TODO: extensionManager is already provided to the extension module.
|
{/* TODO: extensionManager is already provided to the extension module.
|
||||||
* Use it from there instead of passing as a prop here.
|
* Use it from there instead of passing as a prop here.
|
||||||
@ -102,6 +113,7 @@ export default function ModeRoute({
|
|||||||
/>
|
/>
|
||||||
</DragAndDropProvider>
|
</DragAndDropProvider>
|
||||||
</CombinedContextProvider>
|
</CombinedContextProvider>
|
||||||
|
</ImageViewerProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,4 +129,5 @@ ModeRoute.propTypes = {
|
|||||||
mode: PropTypes.object.isRequired,
|
mode: PropTypes.object.isRequired,
|
||||||
dataSourceName: PropTypes.string,
|
dataSourceName: PropTypes.string,
|
||||||
extensionManager: PropTypes.object,
|
extensionManager: PropTypes.object,
|
||||||
|
servicesManager: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user