LT-350: Fixing save button display issue on Viewer

This commit is contained in:
Bruno Alves de Faria 2017-01-11 11:52:45 -02:00
parent 76ebe11c8e
commit 9a11dc1808
8 changed files with 159 additions and 29 deletions

View File

@ -1 +1,3 @@
import './utils';
import './schema.js'; import './schema.js';

View File

@ -0,0 +1 @@
import './objectPath';

View File

@ -0,0 +1,116 @@
import { OHIF } from 'meteor/ohif:core';
class ObjectPath {
/**
* Set an object property based on "path" (namespace) supplied creating
* ... intermediary objects if they do not exist.
* @param object {Object} An object where the properties specified on path should be set.
* @param path {String} A string representing the property to be set, e.g. "user.study.series.timepoint".
* @param value {Any} The value of the property that will be set.
* @return {Boolean} Returns "true" on success, "false" if any intermediate component of the supplied path
* ... is not a valid Object, in which case the property cannot be set. No excpetions are thrown.
*/
static set(object, path, value) {
let components = ObjectPath.getPathComponents(path),
length = components !== null ? components.length : 0,
result = false;
if (length > 0 && ObjectPath.isValidObject(object)) {
let i = 0,
last = length - 1,
currentObject = object;
while (i < last) {
let field = components[i];
if (field in currentObject) {
if (!ObjectPath.isValidObject(currentObject[field])) {
break;
}
} else {
currentObject[field] = {};
}
currentObject = currentObject[field];
i++;
}
if (i === last) {
currentObject[components[last]] = value;
result = true;
}
}
return result;
}
/**
* Get an object property based on "path" (namespace) supplied traversing the object
* ... tree as necessary.
* @param object {Object} An object where the properties specified might exist.
* @param path {String} A string representing the property to be searched for, e.g. "user.study.series.timepoint".
* @return {Any} The value of the property if found. By default, returns the special type "undefined".
*/
static get(object, path) {
let found, // undefined by default
components = ObjectPath.getPathComponents(path),
length = components !== null ? components.length : 0;
if (length > 0 && ObjectPath.isValidObject(object)) {
let i = 0,
last = length - 1,
currentObject = object;
while (i < last) {
let field = components[i];
const isValid = ObjectPath.isValidObject(currentObject[field]);
if (field in currentObject && isValid) {
currentObject = currentObject[field];
i++;
} else {
break;
}
}
if (i === last && components[last] in currentObject) {
found = currentObject[components[last]];
}
}
return found;
}
/**
* Check if the supplied argument is a real JavaScript Object instance.
* @param object {Any} The subject to be tested.
* @return {Boolean} Returns "true" if the object is a real Object instance and "false" otherwise.
*/
static isValidObject(object) {
return (
typeof object === 'object' &&
object !== null &&
object instanceof Object
);
}
static getPathComponents(path) {
return (typeof path === 'string' ? path.split('.') : null);
}
}
OHIF.utils.ObjectPath = ObjectPath;

View File

@ -1,7 +1,5 @@
import { OHIF } from 'meteor/ohif:core'; import { OHIF } from 'meteor/ohif:core';
OHIF.utils = {};
// Return the array sorting function for its object's properties // Return the array sorting function for its object's properties
OHIF.utils.sortBy = function() { OHIF.utils.sortBy = function() {
var fields = [].slice.call(arguments), var fields = [].slice.call(arguments),

View File

@ -7,6 +7,7 @@ import { Meteor } from 'meteor/meteor';
const OHIF = { const OHIF = {
log: {}, log: {},
ui: {}, ui: {},
utils: {},
viewer: {} viewer: {}
}; };

View File

@ -21,6 +21,7 @@ class MeasurementApi {
this.toolGroups = {}; this.toolGroups = {};
this.tools = {}; this.tools = {};
this.toolsGroupsMap = {}; this.toolsGroupsMap = {};
this.changeObserver = new Tracker.Dependency();
configuration.measurementTools.forEach(toolGroup => { configuration.measurementTools.forEach(toolGroup => {
const groupCollection = new Mongo.Collection(null); const groupCollection = new Mongo.Collection(null);
@ -77,6 +78,9 @@ class MeasurementApi {
location location
} }
}); });
// Enable reactivity
this.changeObserver.changed();
}; };
const removedHandler = measurement => { const removedHandler = measurement => {
@ -107,6 +111,9 @@ class MeasurementApi {
collection.update(filter, operator, options); collection.update(filter, operator, options);
}); });
} }
// Enable reactivity
this.changeObserver.changed();
}; };
collection.find().observe({ collection.find().observe({
@ -264,15 +271,15 @@ class MeasurementApi {
}); });
} }
fetch(measurementTypeId, selector, options) { fetch(toolGroupId, selector, options) {
if (!this.toolGroups[measurementTypeId]) { if (!this.toolGroups[toolGroupId]) {
throw 'MeasurementApi: No Collection with the id: ' + measurementTypeId; throw 'MeasurementApi: No Collection with the id: ' + toolGroupId;
} }
selector = selector || {}; selector = selector || {};
options = options || {}; options = options || {};
const result = []; const result = [];
const items = this.toolGroups[measurementTypeId].find(selector, options).fetch(); const items = this.toolGroups[toolGroupId].find(selector, options).fetch();
items.forEach(item => { items.forEach(item => {
result.push(this.tools[item.toolId].findOne(item.toolItemId)); result.push(this.tools[item.toolId].findOne(item.toolItemId));
}); });

View File

@ -2,7 +2,7 @@
<div class="caseProgress"> <div class="caseProgress">
{{#unless progressComplete}} {{#unless progressComplete}}
{{>radialProgressBar isLocked=isLocked progressPercent=progressPercent progressText=progressText}} {{>radialProgressBar isLocked=isLocked progressPercent=progressPercent progressText=progressText}}
{{ /unless }} {{/unless}}
{{#if isLocked}} {{#if isLocked}}
<div class="caseProgressStatus"> <div class="caseProgressStatus">
<h5>Locked</h5> <h5>Locked</h5>

View File

@ -58,39 +58,44 @@ Template.caseProgress.onRendered(() => {
// follow-up. Note that this is done outside of the reactive function // follow-up. Note that this is done outside of the reactive function
// below so that new lesions don't change the initial target count. // below so that new lesions don't change the initial target count.
const config = OHIF.measurements.MeasurementApi.getConfiguration();
const tools = config.measurementTools;
const toolsToInclude = tools.filter(tool => tool.options && tool.options.caseProgress && tool.options.caseProgress.include);
const toolIds = toolsToInclude.map(tool => tool.id);
const api = instance.data.measurementApi; const api = instance.data.measurementApi;
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 => { const getNumMeasurementsAtTimepoint = timepointId => {
OHIF.log.info('getNumMeasurementsAtTimepoint'); OHIF.log.info('getNumMeasurementsAtTimepoint');
const filter = { const filter = getTimepointFilter(timepointId);
timepointId: timepointId
};
let count = 0; let count = 0;
toolIds.forEach(measurementTypeId => { toolGroups.forEach(toolGroup => {
count += api.fetch(measurementTypeId, filter).length; count += api.fetch(toolGroup.id, filter).length;
}); });
return count; return count;
}; };
const getNumRemainingBetweenTimepoints = (currentTimepointId, priorTimepointId) => { const getNumRemainingBetweenTimepoints = (currentTimepointId, priorTimepointId) => {
const currentFilter = { const currentFilter = getTimepointFilter(currentTimepointId);
timepointId: currentTimepointId const priorFilter = getTimepointFilter(priorTimepointId);
};
const priorFilter = {
timepointId: priorTimepointId
};
let totalRemaining = 0; let totalRemaining = 0;
toolIds.forEach(measurementTypeId => { toolGroups.forEach(toolGroup => {
const numCurrent = api.fetch(measurementTypeId, currentFilter).length; const toolGroupId = toolGroup.id;
const numPrior = api.fetch(measurementTypeId, priorFilter).length; const numCurrent = api.fetch(toolGroupId, currentFilter).length;
const numPrior = api.fetch(toolGroupId, priorFilter).length;
const remaining = Math.max(numPrior - numCurrent, 0); const remaining = Math.max(numPrior - numCurrent, 0);
totalRemaining += remaining; totalRemaining += remaining;
}); });
@ -98,8 +103,6 @@ Template.caseProgress.onRendered(() => {
return totalRemaining; return totalRemaining;
}; };
const totalMeasurements = getNumMeasurementsAtTimepoint(prior.timepointId);
// If we're currently reviewing a Baseline timepoint, don't do any // If we're currently reviewing a Baseline timepoint, don't do any
// progress measurement. // progress measurement.
if (current.timepointType === 'baseline') { if (current.timepointType === 'baseline') {
@ -108,8 +111,10 @@ Template.caseProgress.onRendered(() => {
// Setup a reactive function to update the progress whenever // Setup a reactive function to update the progress whenever
// a measurement is made // a measurement is made
instance.autorun(() => { instance.autorun(() => {
api.changeObserver.depend();
// Obtain the number of Measurements for which the current Timepoint has // Obtain the number of Measurements for which the current Timepoint has
// no Measurement data // no Measurement data
const totalMeasurements = getNumMeasurementsAtTimepoint(prior.timepointId);
const numRemainingMeasurements = getNumRemainingBetweenTimepoints(current.timepointId, prior.timepointId); const numRemainingMeasurements = getNumRemainingBetweenTimepoints(current.timepointId, prior.timepointId);
const numMeasurementsMade = totalMeasurements - numRemainingMeasurements; const numMeasurementsMade = totalMeasurements - numRemainingMeasurements;