Allowing new target handling on max targets criteria

This commit is contained in:
Bruno Alves de Faria 2017-06-21 16:47:52 -03:00
parent 6e2dfacd3a
commit ac2df0b3d0
5 changed files with 81 additions and 37 deletions

View File

@ -67,6 +67,7 @@ Template.trialOptionsModal.helpers({
Template.trialOptionsModal.events({ Template.trialOptionsModal.events({
'change .js-trial'(event, instance) { 'change .js-trial'(event, instance) {
const form = instance.$('form').first().data('component'); const form = instance.$('form').first().data('component');
if (!form) return;
instance.selectedTrial.set(form.value().trialCriteria); instance.selectedTrial.set(form.value().trialCriteria);
} }
}); });

View File

@ -41,12 +41,7 @@ Template.measurementTableView.helpers({
const configuration = OHIF.measurements.MeasurementApi.getConfiguration(); const configuration = OHIF.measurements.MeasurementApi.getConfiguration();
const trialCriteriaType = OHIF.lesiontracker.TrialCriteriaTypes.findOne({ selected: true }); const trialCriteriaType = OHIF.lesiontracker.TrialCriteriaTypes.findOne({ selected: true });
const trialCriteriaTypeId = trialCriteriaType.id.toLowerCase(); const trialCriteriaTypeId = trialCriteriaType.id.toLowerCase();
const trialToolGroupMap = { const toolGroupId = trialCriteriaTypeId === 'recist' ? 'nonTargets' : 'targets';
recist: 'nonTargets',
irrc: 'targets'
};
const toolGroupId = trialToolGroupMap[trialCriteriaTypeId];
const toolGroup = _.findWhere(configuration.measurementTools, { id: toolGroupId }); const toolGroup = _.findWhere(configuration.measurementTools, { id: toolGroupId });
return { return {

View File

@ -1,3 +1,5 @@
import { _ } from 'meteor/underscore';
export class BaseCriterion { export class BaseCriterion {
constructor(options) { constructor(options) {
@ -16,4 +18,29 @@ export class BaseCriterion {
}; };
} }
getNewTargetNumbers(data) {
const { options } = this;
const baselineMeasurementNumbers = [];
const newTargetNumbers = new Set();
if (options.newTarget) {
_.each(data.targets, target => {
const { measurementNumber } = target.measurement;
if (target.timepoint.timepointType === 'baseline') {
baselineMeasurementNumbers.push(measurementNumber);
}
});
_.each(data.targets, target => {
const { measurementNumber } = target.measurement;
if (target.timepoint.timepointType === 'followup') {
if (!_.contains(baselineMeasurementNumbers, measurementNumber)) {
newTargetNumbers.add(measurementNumber);
}
}
});
}
return newTargetNumbers;
}
} }

View File

@ -1,5 +1,5 @@
import { BaseCriterion } from './BaseCriterion';
import { _ } from 'meteor/underscore'; import { _ } from 'meteor/underscore';
import { BaseCriterion } from './BaseCriterion';
export const MaxTargetsSchema = { export const MaxTargetsSchema = {
type: 'object', type: 'object',
@ -8,26 +8,30 @@ export const MaxTargetsSchema = {
label: 'Max targets allowed in study', label: 'Max targets allowed in study',
type: 'integer', type: 'integer',
minimum: 1 minimum: 1
},
newTarget: {
label: 'Flag to evaluate only new targets',
type: 'boolean'
},
locationIn: {
label: 'Filter to evaluate only measurements with the specified locations',
type: 'array',
items: {
type: 'string'
},
minItems: 1,
uniqueItems: true
},
locationNotIn: {
label: 'Filter to evaluate only measurements without the specified locations',
type: 'array',
items: {
type: 'string'
},
minItems: 1,
uniqueItems: true
} }
}, },
locationIn: {
label: 'Filter to evaluate only measurements with the specified locations',
type: 'array',
items: {
type: 'string'
},
minItems: 1,
uniqueItems: true
},
locationNotIn: {
label: 'Filter to evaluate only measurements without the specified locations',
type: 'array',
items: {
type: 'string'
},
minItems: 1,
uniqueItems: true
},
required: ['limit'] required: ['limit']
}; };
@ -35,6 +39,7 @@ export const MaxTargetsSchema = {
* Check if the number of target measurements exceeded the limit allowed * Check if the number of target measurements exceeded the limit allowed
* Options: * Options:
* limit: Max targets allowed in study * limit: Max targets allowed in study
* newTarget: Flag to evaluate only new targets (must be evaluated on both)
* locationIn: Filter to evaluate only measurements with the specified locations * locationIn: Filter to evaluate only measurements with the specified locations
* locationNotIn: Filter to evaluate only measurements without the specified locations * locationNotIn: Filter to evaluate only measurements without the specified locations
* message: Message to be displayed in case of nonconformity * message: Message to be displayed in case of nonconformity
@ -47,17 +52,21 @@ export class MaxTargetsCriterion extends BaseCriterion {
evaluate(data) { evaluate(data) {
const { options } = this; const { options } = this;
const newTargetNumbers = this.getNewTargetNumbers(data);
const measurementNumbers = []; const measurementNumbers = [];
_.each(data.targets, target => { _.each(data.targets, target => {
const { location } = target.measurement; const { location, measurementNumber } = target.measurement;
if (options.newTarget && !newTargetNumbers.has(measurementNumber)) return;
if (options.locationIn && options.locationIn.indexOf(location) === -1) return; if (options.locationIn && options.locationIn.indexOf(location) === -1) return;
if (options.locationNotIn && options.locationNotIn.indexOf(location) > -1) return; if (options.locationNotIn && options.locationNotIn.indexOf(location) > -1) return;
measurementNumbers.push(target.measurement.measurementNumber); measurementNumbers.push(measurementNumber);
}); });
let message = options.message; let message;
if (!message && measurementNumbers.length > this.options.limit) { if (measurementNumbers.length > this.options.limit) {
message = `The study should not have more than ${this.options.limit} targets.`; const increment = options.newTarget ? 'new ' : '';
message = options.message || `The study should not have more than ${this.options.limit} ${increment}targets.`;
} }
return this.generateResponse(message); return this.generateResponse(message);

View File

@ -1,3 +1,4 @@
import { _ } from 'meteor/underscore';
import { BaseCriterion } from './BaseCriterion'; import { BaseCriterion } from './BaseCriterion';
export const MaxTargetsPerOrganSchema = { export const MaxTargetsPerOrganSchema = {
@ -7,6 +8,10 @@ export const MaxTargetsPerOrganSchema = {
label: 'Max targets allowed per organ', label: 'Max targets allowed per organ',
type: 'integer', type: 'integer',
minimum: 1 minimum: 1
},
newTarget: {
label: 'Flag to evaluate only new targets',
type: 'boolean'
} }
}, },
required: ['limit'] required: ['limit']
@ -17,6 +22,7 @@ export const MaxTargetsPerOrganSchema = {
* Check if the number of target measurements per organ exceeded the limit allowed * Check if the number of target measurements per organ exceeded the limit allowed
* Options: * Options:
* limit: Max targets allowed in study * limit: Max targets allowed in study
* newTarget: Flag to evaluate only new targets (must be evaluated on both)
*/ */
export class MaxTargetsPerOrganCriterion extends BaseCriterion { export class MaxTargetsPerOrganCriterion extends BaseCriterion {
@ -25,25 +31,31 @@ export class MaxTargetsPerOrganCriterion extends BaseCriterion {
} }
evaluate(data) { evaluate(data) {
const { options } = this;
const targetsPerOrgan = {}; const targetsPerOrgan = {};
let message;
let measurements = []; let measurements = [];
for (let i = 0; i < data.targets.length; i++) { const newTargetNumbers = this.getNewTargetNumbers(data);
const measurement = data.targets[i].measurement; _.each(data.targets, target => {
const { measurement } = target;
const { location, measurementNumber } = measurement; const { location, measurementNumber } = measurement;
if (!targetsPerOrgan[location]) { if (!targetsPerOrgan[location]) {
targetsPerOrgan[location] = new Set(); targetsPerOrgan[location] = new Set();
} }
targetsPerOrgan[location].add(measurementNumber); if (!options.newTarget || newTargetNumbers.has(measurementNumber)) {
if (targetsPerOrgan[location].size > this.options.limit) { targetsPerOrgan[location].add(measurementNumber);
}
if (targetsPerOrgan[location].size > options.limit) {
measurements.push(measurement); measurements.push(measurement);
} }
} });
let message;
if (measurements.length) { if (measurements.length) {
message = `Each organ should not have more than ${this.options.limit} targets.`; const increment = options.newTarget ? 'new ' : '';
message = options.message || `Each organ should not have more than ${options.limit} ${increment}targets.`;
} }
return this.generateResponse(message, measurements); return this.generateResponse(message, measurements);