189 lines
6.5 KiB
JavaScript
189 lines
6.5 KiB
JavaScript
import { Template } from 'meteor/templating';
|
|
import { ReactiveVar } from 'meteor/reactive-var';
|
|
import { Session } from 'meteor/session';
|
|
import { Tracker } from 'meteor/tracker';
|
|
import { OHIF } from 'meteor/ohif:core';
|
|
|
|
Template.caseProgress.onCreated(() => {
|
|
const instance = Template.instance();
|
|
|
|
instance.progressPercent = new ReactiveVar();
|
|
instance.progressText = new ReactiveVar();
|
|
instance.isLocked = new ReactiveVar(false);
|
|
instance.path = 'viewer.studyViewer.measurements';
|
|
instance.saveObserver = new Tracker.Dependency();
|
|
|
|
instance.api = {
|
|
save() {
|
|
// Clear signaled unsaved changes...
|
|
const successHandler = () => {
|
|
OHIF.ui.unsavedChanges.clear(`${instance.path}.*`);
|
|
instance.saveObserver.changed();
|
|
};
|
|
|
|
// Display the error messages
|
|
const errorHandler = data => OHIF.ui.showDialog('dialogInfo', data);
|
|
|
|
const promise = instance.data.measurementApi.storeMeasurements();
|
|
promise.then(successHandler).catch(errorHandler);
|
|
OHIF.ui.showDialog('dialogLoading', {
|
|
promise,
|
|
text: 'Saving measurement data'
|
|
});
|
|
|
|
return promise;
|
|
}
|
|
};
|
|
|
|
instance.unsavedChangesHandler = () => {
|
|
const isNotDisabled = !instance.$('.js-finish-case').hasClass('disabled');
|
|
if (isNotDisabled && instance.progressPercent.get() === 100) {
|
|
instance.api.save();
|
|
}
|
|
};
|
|
|
|
// Attach handler for unsaved changes dialog...
|
|
OHIF.ui.unsavedChanges.attachHandler(instance.path, 'save', instance.unsavedChangesHandler);
|
|
});
|
|
|
|
Template.caseProgress.onDestroyed(() => {
|
|
const instance = Template.instance();
|
|
// Remove unsaved changes handler after this view has been destroyed...
|
|
OHIF.ui.unsavedChanges.removeHandler(instance.path, 'save', instance.unsavedChangesHandler);
|
|
});
|
|
|
|
Template.caseProgress.onRendered(() => {
|
|
const instance = Template.instance();
|
|
const { timepointApi, measurementApi } = instance.data;
|
|
|
|
// Stop here if we have no current timepoint ID (and therefore no defined timepointAPI)
|
|
if (!timepointApi) {
|
|
instance.progressPercent.set(100);
|
|
return;
|
|
}
|
|
|
|
// Get the current and prior timepoints
|
|
const current = timepointApi.current();
|
|
const prior = timepointApi.prior();
|
|
|
|
// Stop here if timepoint is locked
|
|
if (current && current.isLocked) {
|
|
return instance.isLocked.set(true);
|
|
} else {
|
|
instance.isLocked.set(false);
|
|
}
|
|
|
|
// Stop here if no current or prior timepoint was found
|
|
if (!current || !prior || !current.timepointId) {
|
|
return instance.progressPercent.set(100);
|
|
}
|
|
|
|
// Retrieve the initial number of targets left to measure at this
|
|
// follow-up. Note that this is done outside of the reactive function
|
|
// below so that new lesions don't change the initial target count.
|
|
|
|
const config = OHIF.measurements.MeasurementApi.getConfiguration();
|
|
const toolGroups = config.measurementTools;
|
|
|
|
const toolIds = [];
|
|
toolGroups.forEach(toolGroup => toolGroup.childTools.forEach(tool => {
|
|
const option = 'options.caseProgress.include';
|
|
if (OHIF.utils.ObjectPath.get(tool, option)) {
|
|
toolIds.push(tool.id);
|
|
}
|
|
}));
|
|
|
|
const getTimepointFilter = timepointId => ({
|
|
timepointId,
|
|
toolId: { $in: toolIds }
|
|
});
|
|
|
|
const getNumMeasurementsAtTimepoint = timepointId => {
|
|
OHIF.log.info('getNumMeasurementsAtTimepoint');
|
|
const filter = getTimepointFilter(timepointId);
|
|
|
|
let count = 0;
|
|
toolGroups.forEach(toolGroup => {
|
|
count += measurementApi.fetch(toolGroup.id, filter).length;
|
|
});
|
|
|
|
return count;
|
|
};
|
|
|
|
const getNumRemainingBetweenTimepoints = (currentTimepointId, priorTimepointId) => {
|
|
const currentFilter = getTimepointFilter(currentTimepointId);
|
|
const priorFilter = getTimepointFilter(priorTimepointId);
|
|
|
|
let totalRemaining = 0;
|
|
toolGroups.forEach(toolGroup => {
|
|
const toolGroupId = toolGroup.id;
|
|
const numCurrent = measurementApi.fetch(toolGroupId, currentFilter).length;
|
|
const numPrior = measurementApi.fetch(toolGroupId, priorFilter).length;
|
|
const remaining = Math.max(numPrior - numCurrent, 0);
|
|
totalRemaining += remaining;
|
|
});
|
|
|
|
return totalRemaining;
|
|
};
|
|
|
|
// If we're currently reviewing a Baseline timepoint, don't do any
|
|
// progress measurement.
|
|
if (current.timepointType === 'baseline') {
|
|
instance.progressPercent.set(100);
|
|
} else {
|
|
// Setup a reactive function to update the progress whenever
|
|
// a measurement is made
|
|
instance.autorun(() => {
|
|
measurementApi.changeObserver.depend();
|
|
// Obtain the number of Measurements for which the current Timepoint has
|
|
// no Measurement data
|
|
const totalMeasurements = getNumMeasurementsAtTimepoint(prior.timepointId);
|
|
const numRemainingMeasurements = getNumRemainingBetweenTimepoints(current.timepointId, prior.timepointId);
|
|
const numMeasurementsMade = totalMeasurements - numRemainingMeasurements;
|
|
|
|
// Update the Case Progress text with the remaining measurement count
|
|
instance.progressText.set(numRemainingMeasurements);
|
|
|
|
// Calculate the Case Progress as a percentage in order to update the
|
|
// radial progress bar
|
|
const progressPercent = Math.min(100, Math.round(100 * numMeasurementsMade / totalMeasurements));
|
|
instance.progressPercent.set(progressPercent);
|
|
});
|
|
}
|
|
});
|
|
|
|
Template.caseProgress.helpers({
|
|
progressPercent() {
|
|
return Template.instance().progressPercent.get();
|
|
},
|
|
|
|
progressText() {
|
|
return Template.instance().progressText.get();
|
|
},
|
|
|
|
isLocked() {
|
|
return Template.instance().isLocked.get();
|
|
},
|
|
|
|
progressComplete() {
|
|
const instance = Template.instance();
|
|
if (!instance.data.timepointApi) {
|
|
return true;
|
|
}
|
|
|
|
const progressPercent = instance.progressPercent.get();
|
|
return progressPercent === 100;
|
|
},
|
|
|
|
isFinishDisabled() {
|
|
const instance = Template.instance();
|
|
|
|
// Run this computation on save or every time any measurement / timepoint suffer changes
|
|
OHIF.ui.unsavedChanges.depend();
|
|
instance.saveObserver.depend();
|
|
Session.get('LayoutManagerUpdated');
|
|
|
|
return OHIF.ui.unsavedChanges.probe('viewer.*') === 0;
|
|
}
|
|
});
|