OHIF-285/OHIF-274: Fix default hanging of display sets into the ViewportGrid (#1917)
* OHIF-285/OHIF-274: Fix default hanging of display sets into the ViewportGrid Co-authored-by: James A. Petts <jamesapetts@gmail.com>
This commit is contained in:
1 parent
9df57e7f7f
commit
55cf9f2306
33 files changed
+548
-208
No files matched your search
@@ -42,7 +42,7 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
wadoRoot,
|
||||
enableStudyLazyLoad,
|
||||
supportsFuzzyMatching,
|
||||
supportsWildcard
|
||||
supportsWildcard,
|
||||
} = dicomWebConfig;
|
||||
|
||||
const qidoConfig = {
|
||||
@@ -63,9 +63,12 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
query: {
|
||||
studies: {
|
||||
mapParams: mapParams.bind(),
|
||||
search: async function (origParams) {
|
||||
search: async function(origParams) {
|
||||
const { studyInstanceUid, seriesInstanceUid, ...mappedParams } =
|
||||
mapParams(origParams, { supportsFuzzyMatching, supportsWildcard }) || {};
|
||||
mapParams(origParams, {
|
||||
supportsFuzzyMatching,
|
||||
supportsWildcard,
|
||||
}) || {};
|
||||
|
||||
const results = await qidoSearch(
|
||||
qidoDicomWebClient,
|
||||
@@ -80,7 +83,7 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
},
|
||||
series: {
|
||||
// mapParams: mapParams.bind(),
|
||||
search: async function (studyInstanceUid) {
|
||||
search: async function(studyInstanceUid) {
|
||||
const results = await seriesInStudy(
|
||||
qidoDicomWebClient,
|
||||
studyInstanceUid
|
||||
@@ -133,7 +136,8 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
);
|
||||
|
||||
studyPromises.forEach(studyPromise => {
|
||||
studyPromise.then(seriesPromises => {
|
||||
studyPromise.then(data => {
|
||||
const { seriesPromises } = data;
|
||||
seriesPromises.forEach(seriesPromise => {
|
||||
seriesPromise.then(instances => {
|
||||
storeInstances(instances);
|
||||
@@ -178,7 +182,10 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
}
|
||||
|
||||
// Get Series
|
||||
const seriesPromises = await retrieveStudyMetadata(
|
||||
const {
|
||||
seriesSummaryMetadata,
|
||||
seriesPromises,
|
||||
} = await retrieveStudyMetadata(
|
||||
wadoDicomWebClient,
|
||||
StudyInstanceUID,
|
||||
enableStudyLazyLoad
|
||||
@@ -191,6 +198,8 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
DicomMetadataStore.addInstances(naturalizedInstances);
|
||||
}
|
||||
|
||||
DicomMetadataStore.addSeriesMetadata(seriesSummaryMetadata);
|
||||
|
||||
seriesPromises.forEach(async seriesPromise => {
|
||||
const instances = await seriesPromise;
|
||||
storeInstances(instances);
|
||||
|
||||
@@ -29,9 +29,12 @@ async function RetrieveMetadata(
|
||||
studyInstanceUid,
|
||||
filters
|
||||
);
|
||||
const studyMetadata = retrieveMetadataLoader.execLoad();
|
||||
const { preLoadData, promises } = await retrieveMetadataLoader.execLoad();
|
||||
|
||||
return studyMetadata;
|
||||
return {
|
||||
seriesSummaryMetadata: preLoadData,
|
||||
seriesPromises: promises,
|
||||
};
|
||||
}
|
||||
|
||||
export default RetrieveMetadata;
|
||||
@@ -1,15 +1,9 @@
|
||||
import dcmjs from 'dcmjs';
|
||||
import { studies } from '@ohif/core';
|
||||
import RetrieveMetadataLoader from './retrieveMetadataLoader';
|
||||
//import { sortStudySeries, sortingCriteria } from '../../sortStudy';
|
||||
import getSeriesInfo from './utils/getSeriesInfo';
|
||||
|
||||
/**
|
||||
* Map seriesList to an array of seriesInstanceUid
|
||||
* @param {Arrays} seriesList list of Series Instance UIDs
|
||||
* @returns {Arrays} A list of Series Instance UIDs
|
||||
*/
|
||||
function mapStudySeries(seriesList) {
|
||||
return seriesList.map(series => getSeriesInfo(series).seriesInstanceUid);
|
||||
}
|
||||
const { sortStudySeries, sortingCriteria } = studies;
|
||||
|
||||
|
||||
/**
|
||||
* Creates an immutable series loader object which loads each series sequentially using the iterator interface
|
||||
@@ -33,7 +27,6 @@ function makeSeriesAsyncLoader(
|
||||
studyInstanceUID,
|
||||
seriesInstanceUID,
|
||||
});
|
||||
// return { studyInstanceUID, seriesInstanceUID, sopInstances };
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -73,56 +66,42 @@ export default class RetrieveMetadataLoaderAsync extends RetrieveMetadataLoader
|
||||
const preLoaders = this.getPreLoaders();
|
||||
const result = await this.runLoaders(preLoaders);
|
||||
|
||||
// const seriesSorted = sortStudySeries(
|
||||
// result,
|
||||
// sortingCriteria.seriesSortCriteria.seriesInfoSortingCriteria
|
||||
// );
|
||||
const { naturalizeDataset } = dcmjs.data.DicomMetaDictionary;
|
||||
const naturalized = result.map(naturalizeDataset);
|
||||
|
||||
//const seriesInstanceUidsMap = mapStudySeries(seriesSorted);
|
||||
|
||||
const seriesInstanceUidsMap = mapStudySeries(result);
|
||||
|
||||
return seriesInstanceUidsMap;
|
||||
return sortStudySeries(
|
||||
naturalized,
|
||||
sortingCriteria.seriesSortCriteria.seriesInfoSortingCriteria
|
||||
);
|
||||
}
|
||||
|
||||
async load(preLoadData) {
|
||||
const { client, studyInstanceUID } = this;
|
||||
|
||||
const seriesInstanceUIDs = preLoadData.map(s => s.SeriesInstanceUID);
|
||||
|
||||
const seriesAsyncLoader = makeSeriesAsyncLoader(
|
||||
client,
|
||||
studyInstanceUID,
|
||||
preLoadData
|
||||
seriesInstanceUIDs
|
||||
);
|
||||
|
||||
// const firstSeries = await seriesAsyncLoader.next();
|
||||
|
||||
// return {
|
||||
// sopInstances: firstSeries.sopInstances,
|
||||
// asyncLoader: seriesAsyncLoader,
|
||||
// };
|
||||
|
||||
const promises = [];
|
||||
|
||||
while (seriesAsyncLoader.hasNext()) {
|
||||
promises.push(seriesAsyncLoader.next());
|
||||
}
|
||||
|
||||
return promises;
|
||||
|
||||
// if (asyncLoader.hasNext()) {
|
||||
return {
|
||||
preLoadData,
|
||||
promises,
|
||||
};
|
||||
}
|
||||
|
||||
async posLoad(promises) {
|
||||
return promises;
|
||||
// const { client } = this;
|
||||
// const { sopInstances, asyncLoader } = loadData;
|
||||
|
||||
// const study = await createStudyFromSOPInstanceList(server, sopInstances);
|
||||
|
||||
// if (asyncLoader.hasNext()) {
|
||||
// attachSeriesLoader(server, study, asyncLoader);
|
||||
// }
|
||||
|
||||
// return study;
|
||||
async posLoad({ preLoadData, promises }) {
|
||||
return {
|
||||
preLoadData,
|
||||
promises,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { DICOMWeb } from '@ohif/core';
|
||||
// import isLowPriorityModality from '../utils/isLowPriorityModality';
|
||||
|
||||
const INFO = Symbol('INFO');
|
||||
|
||||
/**
|
||||
* Creates an object with processed series information and saves its reference
|
||||
* inside the series object itself.
|
||||
* @param {Object} series The raw series object
|
||||
* @returns {Object} object containing some useful info from given series
|
||||
*/
|
||||
export default function getSeriesInfo(series) {
|
||||
let info = series[INFO];
|
||||
if (!info) {
|
||||
const modality = DICOMWeb.getString(series['00080060'], '').toUpperCase();
|
||||
info = Object.freeze({
|
||||
modality,
|
||||
// isLowPriority: isLowPriorityModality(modality), // TODO -> We should do this in the series list level, not here.
|
||||
seriesInstanceUid: DICOMWeb.getString(series['0020000E']),
|
||||
seriesNumber: DICOMWeb.getNumber(series['00200011'], 0) || 0,
|
||||
});
|
||||
series[INFO] = info;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
@@ -54,7 +54,11 @@ function ViewerLayout({
|
||||
};
|
||||
};
|
||||
|
||||
const defaultTool = { icon: 'tool-more-menu', label: 'More', isActive: false };
|
||||
const defaultTool = {
|
||||
icon: 'tool-more-menu',
|
||||
label: 'More',
|
||||
isActive: false,
|
||||
};
|
||||
const [toolbars, setToolbars] = useState({ primary: [], secondary: [] });
|
||||
const [activeTool, setActiveTool] = useState(defaultTool);
|
||||
|
||||
@@ -63,7 +67,12 @@ function ViewerLayout({
|
||||
};
|
||||
|
||||
const onPrimaryClickHandler = (evt, btn) => {
|
||||
if (btn.props && btn.props.commands && evt.value && btn.props.commands[evt.value]) {
|
||||
if (
|
||||
btn.props &&
|
||||
btn.props.commands &&
|
||||
evt.value &&
|
||||
btn.props.commands[evt.value]
|
||||
) {
|
||||
const { commandName, commandOptions } = btn.props.commands[evt.value];
|
||||
commandsManager.runCommand(commandName, commandOptions);
|
||||
}
|
||||
@@ -75,8 +84,13 @@ function ViewerLayout({
|
||||
() => {
|
||||
console.warn('~~~ TOOL BAR MODIFIED EVENT CAUGHT');
|
||||
const updatedToolbars = {
|
||||
primary: ToolBarService.getButtonSection('primary', { onClick: onPrimaryClickHandler, setActiveTool: setActiveToolHandler }),
|
||||
secondary: ToolBarService.getButtonSection('secondary', { setActiveTool: setActiveToolHandler }),
|
||||
primary: ToolBarService.getButtonSection('primary', {
|
||||
onClick: onPrimaryClickHandler,
|
||||
setActiveTool: setActiveToolHandler,
|
||||
}),
|
||||
secondary: ToolBarService.getButtonSection('secondary', {
|
||||
setActiveTool: setActiveToolHandler,
|
||||
}),
|
||||
};
|
||||
setToolbars(updatedToolbars);
|
||||
}
|
||||
@@ -94,18 +108,25 @@ function ViewerLayout({
|
||||
<Header>
|
||||
<ErrorBoundary context="Primary Toolbar">
|
||||
<div className="relative flex justify-center">
|
||||
{toolbars.primary.map(toolDef => {
|
||||
{toolbars.primary.map((toolDef, index) => {
|
||||
const isNested = Array.isArray(toolDef);
|
||||
if (!isNested) {
|
||||
const { id, Component, componentProps } = toolDef;
|
||||
return <Component key={id} id={id} {...componentProps} />;
|
||||
} else {
|
||||
return (
|
||||
<NestedMenu isActive={activeTool.isActive} icon={activeTool.icon} label={activeTool.label}>
|
||||
<NestedMenu
|
||||
key={index}
|
||||
isActive={activeTool.isActive}
|
||||
icon={activeTool.icon}
|
||||
label={activeTool.label}
|
||||
>
|
||||
<div className="flex">
|
||||
{toolDef.map(x => {
|
||||
const { id, Component, componentProps } = x;
|
||||
return <Component key={id} id={id} {...componentProps} />;
|
||||
return (
|
||||
<Component key={id} id={id} {...componentProps} />
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</NestedMenu>
|
||||
@@ -174,7 +195,7 @@ ViewerLayout.propTypes = {
|
||||
leftPanels: PropTypes.array,
|
||||
rightPanels: PropTypes.array,
|
||||
/** Responsible for rendering our grid of viewports; provided by consuming application */
|
||||
children: PropTypes.oneOfType(PropTypes.node, PropTypes.func).isRequired,
|
||||
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
|
||||
};
|
||||
|
||||
ViewerLayout.defaultProps = {
|
||||
|
||||
+2
-2
@@ -5,8 +5,8 @@ import { Button, ButtonGroup, Icon, IconButton } from '@ohif/ui';
|
||||
function ActionButtons({ onExportClick, onCreateReportClick }) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<ButtonGroup color="black" onClick={onExportClick} size="inherit">
|
||||
<Button className="text-base px-2 py-2">Export</Button>
|
||||
<ButtonGroup color="black" size="inherit">
|
||||
<Button className="text-base px-2 py-2" onClick={onExportClick}>Export</Button>
|
||||
<IconButton
|
||||
className="px-2"
|
||||
color="black"
|
||||
|
||||
+12
@@ -447,6 +447,18 @@ function _createStudyBrowserTabs(
|
||||
const displaySetsForStudy = displaySets.filter(
|
||||
ds => ds.StudyInstanceUID === study.studyInstanceUid
|
||||
);
|
||||
|
||||
displaySetsForStudy.sort((a,b) => {
|
||||
if (a.seriesNumber !== b.seriesNumber) {
|
||||
return a.seriesNumber - b.seriesNumber;
|
||||
}
|
||||
|
||||
const seriesDateA = Date.parse(a.seriesDate);
|
||||
const seriesDateB = Date.parse(b.seriesDate);
|
||||
|
||||
return seriesDateA - seriesDateB;
|
||||
});
|
||||
|
||||
const tabStudy = Object.assign({}, study, {
|
||||
displaySets: displaySetsForStudy,
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user