[OHIF-339] - workflow changes (#1931)
* workflow changes * Cherry pick OHIF-310 into this PR. * fix label bug and dead code * remove comment * Wire up CreateReportButton * fix additionalFindingTypes + save interaction * Remove unused createReportAsync call * stub for report hydration prompt * Update PR * Remove debuggers * push updated code * Push updates * push * fix sidebar save * enable tracking of new study or series * fix for duplicate created report series in sidebard * fix for unexpected viewport dialog after visiting study list then a new study * Fix for hydration not marking multiple series as active * Reviewer changes. * Respond to final review comment, add series description setting for export. Co-authored-by: James A. Petts <jamesapetts@gmail.com>
This commit is contained in:
1 parent
5f487840a1
commit
2a51d75f77
26 files changed
+948
-391
No files matched your search
@@ -6,6 +6,7 @@ import {
|
||||
stowSRFromMeasurements,
|
||||
} from './handleStructuredReport';
|
||||
import findMostRecentStructuredReport from './utils/findMostRecentStructuredReport';
|
||||
import cornerstone from 'cornerstone-core';
|
||||
import cornerstoneTools from 'cornerstone-tools';
|
||||
import dcmjs from 'dcmjs';
|
||||
|
||||
@@ -47,11 +48,20 @@ const retrieveMeasurements = server => {
|
||||
*
|
||||
* @param {object[]} measurementData An array of measurements from the measurements service
|
||||
* @param {string[]} additionalFindingTypes toolTypes that should be stored with labels as Findings
|
||||
* @param {object} options Naturalized DICOM JSON headers to merge into the displaySet.
|
||||
* as opposed to Finding Sites.
|
||||
* that you wish to serialize.
|
||||
*/
|
||||
const downloadReport = (measurementData, additionalFindingTypes = []) => {
|
||||
const srDataset = generateReport(measurementData, additionalFindingTypes);
|
||||
const downloadReport = (
|
||||
measurementData,
|
||||
additionalFindingTypes,
|
||||
options = {}
|
||||
) => {
|
||||
const srDataset = generateReport(
|
||||
measurementData,
|
||||
additionalFindingTypes,
|
||||
options
|
||||
);
|
||||
const reportBlob = dcmjs.data.datasetToBlob(srDataset);
|
||||
|
||||
//Create a URL for the binary.
|
||||
@@ -64,19 +74,29 @@ const downloadReport = (measurementData, additionalFindingTypes = []) => {
|
||||
* @param {object[]} measurementData An array of measurements from the measurements service
|
||||
* that you wish to serialize.
|
||||
* @param {string[]} additionalFindingTypes toolTypes that should be stored with labels as Findings
|
||||
* @param {object} options Naturalized DICOM JSON headers to merge into the displaySet.
|
||||
*
|
||||
*/
|
||||
const generateReport = (measurementData, additionalFindingTypes) => {
|
||||
const generateReport = (
|
||||
measurementData,
|
||||
additionalFindingTypes,
|
||||
options = {}
|
||||
) => {
|
||||
const filteredToolState = _getFilteredCornerstoneToolState(
|
||||
measurementData,
|
||||
additionalFindingTypes
|
||||
);
|
||||
|
||||
const report = MeasurementReport.generateReport(
|
||||
filteredToolState,
|
||||
cornerstone.metaData
|
||||
);
|
||||
|
||||
return report.dataset;
|
||||
const { dataset } = report;
|
||||
|
||||
// Add in top level series options
|
||||
Object.assign(dataset, options);
|
||||
|
||||
return dataset;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -85,13 +105,14 @@ const generateReport = (measurementData, additionalFindingTypes) => {
|
||||
* that you wish to serialize.
|
||||
* @param {object} dataSource The dataSource that you wish to use to persist the data.
|
||||
* @param {string[]} additionalFindingTypes toolTypes that should be stored with labels as Findings
|
||||
* as opposed to Finding Sites.
|
||||
* @param {object} options Naturalized DICOM JSON headers to merge into the displaySet.
|
||||
* @return {object} The naturalized report
|
||||
*/
|
||||
const storeMeasurements = async (
|
||||
measurementData,
|
||||
dataSource,
|
||||
additionalFindingTypes = []
|
||||
additionalFindingTypes,
|
||||
options = {}
|
||||
) => {
|
||||
// TODO -> Eventually use the measurements directly and not the dcmjs adapter,
|
||||
// But it is good enough for now whilst we only have cornerstone as a datasource.
|
||||
@@ -105,7 +126,8 @@ const storeMeasurements = async (
|
||||
try {
|
||||
const naturalizedReport = generateReport(
|
||||
measurementData,
|
||||
additionalFindingTypes
|
||||
additionalFindingTypes,
|
||||
options
|
||||
);
|
||||
const { StudyInstanceUID } = naturalizedReport;
|
||||
|
||||
@@ -117,6 +139,7 @@ const storeMeasurements = async (
|
||||
|
||||
return naturalizedReport;
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
log.error(
|
||||
`[DICOMSR] Error while saving the measurements: ${error.message}`
|
||||
);
|
||||
@@ -124,6 +147,8 @@ const storeMeasurements = async (
|
||||
}
|
||||
};
|
||||
|
||||
// _getFilteredCornerstoneToolState
|
||||
// DIFFERENT IMPLEMENTATION HERE! What's up?
|
||||
function _getFilteredCornerstoneToolState(
|
||||
measurementData,
|
||||
additionalFindingTypes
|
||||
@@ -147,7 +172,6 @@ function _getFilteredCornerstoneToolState(
|
||||
}
|
||||
|
||||
const measurmentDataI = measurementData.find(md => md.id === toolDataI.id);
|
||||
|
||||
const toolData = imageIdSpecificToolState[toolType].data;
|
||||
|
||||
let finding;
|
||||
|
||||
@@ -16,7 +16,7 @@ export default class ExtensionManager {
|
||||
this.moduleTypeNames.forEach(moduleType => {
|
||||
this.modules[moduleType] = [];
|
||||
});
|
||||
this._extensionLifeCycleHooks = { onModeEnter: {} };
|
||||
this._extensionLifeCycleHooks = { onModeEnter: {}, onModeExit: {} };
|
||||
this.dataSourceMap = {};
|
||||
this.defaultDataSourceName = appConfig.defaultDataSourceName;
|
||||
this.activeDataSource = undefined;
|
||||
@@ -29,12 +29,21 @@ export default class ExtensionManager {
|
||||
onModeEnter() {
|
||||
const {
|
||||
registeredExtensionIds,
|
||||
getModuleEntry,
|
||||
_servicesManager,
|
||||
_commandsManager,
|
||||
_extensionLifeCycleHooks,
|
||||
} = this;
|
||||
|
||||
const {
|
||||
MeasurementService,
|
||||
ViewportGridService,
|
||||
HangingProtocolService,
|
||||
} = _servicesManager.services;
|
||||
|
||||
MeasurementService.clearMeasurements();
|
||||
ViewportGridService.reset();
|
||||
HangingProtocolService.reset();
|
||||
|
||||
registeredExtensionIds.forEach(extensionId => {
|
||||
const onModeEnter = _extensionLifeCycleHooks.onModeEnter[extensionId];
|
||||
|
||||
@@ -47,6 +56,36 @@ export default class ExtensionManager {
|
||||
});
|
||||
}
|
||||
|
||||
onModeExit() {
|
||||
const {
|
||||
registeredExtensionIds,
|
||||
_servicesManager,
|
||||
_commandsManager,
|
||||
_extensionLifeCycleHooks,
|
||||
} = this;
|
||||
|
||||
const {
|
||||
MeasurementService,
|
||||
ViewportGridService,
|
||||
HangingProtocolService,
|
||||
} = _servicesManager.services;
|
||||
|
||||
MeasurementService.clearMeasurements();
|
||||
ViewportGridService.reset();
|
||||
HangingProtocolService.reset();
|
||||
|
||||
registeredExtensionIds.forEach(extensionId => {
|
||||
const onModeExit = _extensionLifeCycleHooks.onModeExit[extensionId];
|
||||
|
||||
if (typeof onModeExit === 'function') {
|
||||
onModeExit({
|
||||
servicesManager: _servicesManager,
|
||||
commandsManager: _commandsManager,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of extensions, or an array of arrays that contains extension
|
||||
* configuration pairs.
|
||||
@@ -110,6 +149,11 @@ export default class ExtensionManager {
|
||||
extension.onModeEnter;
|
||||
}
|
||||
|
||||
if (extension.onModeExit) {
|
||||
this._extensionLifeCycleHooks.onModeExit[extensionId] =
|
||||
extension.onModeExit;
|
||||
}
|
||||
|
||||
// Register Modules
|
||||
this.moduleTypeNames.forEach(moduleType => {
|
||||
const extensionModule = this._getExtensionModule(
|
||||
|
||||
@@ -77,10 +77,10 @@ class ConformanceCriteria {
|
||||
this.nonconformities = nonconformities;
|
||||
this.groupedNonConformities = groupedNonConformities;
|
||||
|
||||
console.warn('nonconformities');
|
||||
console.warn(nonconformities);
|
||||
console.warn('groupedNonConformities');
|
||||
console.warn(groupedNonConformities);
|
||||
// console.warn('nonconformities');
|
||||
// console.warn(nonconformities);
|
||||
// console.warn('groupedNonConformities');
|
||||
// console.warn(groupedNonConformities);
|
||||
|
||||
return nonconformities;
|
||||
}
|
||||
|
||||
@@ -57,9 +57,7 @@ function _getInstance(StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID) {
|
||||
const BaseImplementation = {
|
||||
EVENTS,
|
||||
listeners: {},
|
||||
// TODO: The assumption is that this is called per Study per Series
|
||||
// We should do more to verify/clarify that
|
||||
addInstances(instances) {
|
||||
addInstances(instances, madeInClient = false) {
|
||||
const { StudyInstanceUID, SeriesInstanceUID } = instances[0];
|
||||
|
||||
let study = _model.studies.find(
|
||||
@@ -81,6 +79,7 @@ const BaseImplementation = {
|
||||
this._broadcastEvent(EVENTS.INSTANCES_ADDED, {
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
madeInClient,
|
||||
});
|
||||
},
|
||||
addSeriesMetadata(seriesSummaryMetadata) {
|
||||
|
||||
@@ -36,6 +36,10 @@ export default class DisplaySetService {
|
||||
return displaySetCache;
|
||||
}
|
||||
|
||||
getMostRecentDisplaySet() {
|
||||
return this.activeDisplaySets[this.activeDisplaySets.length - 1];
|
||||
}
|
||||
|
||||
getActiveDisplaySets() {
|
||||
return this.activeDisplaySets;
|
||||
}
|
||||
@@ -69,6 +73,12 @@ export default class DisplaySetService {
|
||||
displaySet => displaySet.displaySetInstanceUID === displaySetInstanceUid
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} input
|
||||
* @param {*} param1
|
||||
* @returns {string[]} - added displaySetInstanceUIDs
|
||||
*/
|
||||
makeDisplaySets = (input, { batch = false, madeInClient = false } = {}) => {
|
||||
if (!input || !input.length) {
|
||||
throw new Error('No instances were provided.');
|
||||
@@ -84,11 +94,12 @@ export default class DisplaySetService {
|
||||
let displaySetsAdded = [];
|
||||
|
||||
if (batch) {
|
||||
input.forEach(instances => {
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
const instances = input[i];
|
||||
const displaySets = this.makeDisplaySetForInstances(instances);
|
||||
|
||||
displaySetsAdded = [...displaySetsAdded, displaySets];
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const displaySets = this.makeDisplaySetForInstances(input);
|
||||
|
||||
@@ -109,6 +120,8 @@ export default class DisplaySetService {
|
||||
displaySetsAdded,
|
||||
options,
|
||||
});
|
||||
|
||||
return displaySetsAdded;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user