From ac2df0b3d092d1953e93a5c84ab476838227f0f1 Mon Sep 17 00:00:00 2001 From: Bruno Alves de Faria Date: Wed, 21 Jun 2017 16:47:52 -0300 Subject: [PATCH] Allowing new target handling on max targets criteria --- .../trialOptionsModal/trialOptionsModal.js | 1 + .../measurementTableView.js | 7 +-- .../conformance/criteria/BaseCriterion.js | 27 +++++++++ .../client/conformance/criteria/MaxTargets.js | 57 +++++++++++-------- .../criteria/MaxTargetsPerOrgan.js | 26 ++++++--- 5 files changed, 81 insertions(+), 37 deletions(-) diff --git a/Packages/ohif-lesiontracker/client/components/trialOptionsModal/trialOptionsModal.js b/Packages/ohif-lesiontracker/client/components/trialOptionsModal/trialOptionsModal.js index ee91c7b4b..c39e736fd 100644 --- a/Packages/ohif-lesiontracker/client/components/trialOptionsModal/trialOptionsModal.js +++ b/Packages/ohif-lesiontracker/client/components/trialOptionsModal/trialOptionsModal.js @@ -67,6 +67,7 @@ Template.trialOptionsModal.helpers({ Template.trialOptionsModal.events({ 'change .js-trial'(event, instance) { const form = instance.$('form').first().data('component'); + if (!form) return; instance.selectedTrial.set(form.value().trialCriteria); } }); diff --git a/Packages/ohif-measurements/client/components/measurementTable/measurementTableView/measurementTableView.js b/Packages/ohif-measurements/client/components/measurementTable/measurementTableView/measurementTableView.js index 501322209..5c8ff01ef 100644 --- a/Packages/ohif-measurements/client/components/measurementTable/measurementTableView/measurementTableView.js +++ b/Packages/ohif-measurements/client/components/measurementTable/measurementTableView/measurementTableView.js @@ -41,12 +41,7 @@ Template.measurementTableView.helpers({ const configuration = OHIF.measurements.MeasurementApi.getConfiguration(); const trialCriteriaType = OHIF.lesiontracker.TrialCriteriaTypes.findOne({ selected: true }); const trialCriteriaTypeId = trialCriteriaType.id.toLowerCase(); - const trialToolGroupMap = { - recist: 'nonTargets', - irrc: 'targets' - }; - - const toolGroupId = trialToolGroupMap[trialCriteriaTypeId]; + const toolGroupId = trialCriteriaTypeId === 'recist' ? 'nonTargets' : 'targets'; const toolGroup = _.findWhere(configuration.measurementTools, { id: toolGroupId }); return { diff --git a/Packages/ohif-measurements/client/conformance/criteria/BaseCriterion.js b/Packages/ohif-measurements/client/conformance/criteria/BaseCriterion.js index 2d4684ab9..f88d92170 100644 --- a/Packages/ohif-measurements/client/conformance/criteria/BaseCriterion.js +++ b/Packages/ohif-measurements/client/conformance/criteria/BaseCriterion.js @@ -1,3 +1,5 @@ +import { _ } from 'meteor/underscore'; + export class BaseCriterion { 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; + } + } diff --git a/Packages/ohif-measurements/client/conformance/criteria/MaxTargets.js b/Packages/ohif-measurements/client/conformance/criteria/MaxTargets.js index 57738d400..325380cbb 100644 --- a/Packages/ohif-measurements/client/conformance/criteria/MaxTargets.js +++ b/Packages/ohif-measurements/client/conformance/criteria/MaxTargets.js @@ -1,5 +1,5 @@ -import { BaseCriterion } from './BaseCriterion'; import { _ } from 'meteor/underscore'; +import { BaseCriterion } from './BaseCriterion'; export const MaxTargetsSchema = { type: 'object', @@ -8,26 +8,30 @@ export const MaxTargetsSchema = { label: 'Max targets allowed in study', type: 'integer', 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'] }; @@ -35,6 +39,7 @@ export const MaxTargetsSchema = { * Check if the number of target measurements exceeded the limit allowed * Options: * 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 * locationNotIn: Filter to evaluate only measurements without the specified locations * message: Message to be displayed in case of nonconformity @@ -47,17 +52,21 @@ export class MaxTargetsCriterion extends BaseCriterion { evaluate(data) { const { options } = this; + + const newTargetNumbers = this.getNewTargetNumbers(data); const measurementNumbers = []; _.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.locationNotIn && options.locationNotIn.indexOf(location) > -1) return; - measurementNumbers.push(target.measurement.measurementNumber); + measurementNumbers.push(measurementNumber); }); - let message = options.message; - if (!message && measurementNumbers.length > this.options.limit) { - message = `The study should not have more than ${this.options.limit} targets.`; + let message; + if (measurementNumbers.length > this.options.limit) { + const increment = options.newTarget ? 'new ' : ''; + message = options.message || `The study should not have more than ${this.options.limit} ${increment}targets.`; } return this.generateResponse(message); diff --git a/Packages/ohif-measurements/client/conformance/criteria/MaxTargetsPerOrgan.js b/Packages/ohif-measurements/client/conformance/criteria/MaxTargetsPerOrgan.js index 73646d265..c361822a6 100644 --- a/Packages/ohif-measurements/client/conformance/criteria/MaxTargetsPerOrgan.js +++ b/Packages/ohif-measurements/client/conformance/criteria/MaxTargetsPerOrgan.js @@ -1,3 +1,4 @@ +import { _ } from 'meteor/underscore'; import { BaseCriterion } from './BaseCriterion'; export const MaxTargetsPerOrganSchema = { @@ -7,6 +8,10 @@ export const MaxTargetsPerOrganSchema = { label: 'Max targets allowed per organ', type: 'integer', minimum: 1 + }, + newTarget: { + label: 'Flag to evaluate only new targets', + type: 'boolean' } }, required: ['limit'] @@ -17,6 +22,7 @@ export const MaxTargetsPerOrganSchema = { * Check if the number of target measurements per organ exceeded the limit allowed * Options: * limit: Max targets allowed in study + * newTarget: Flag to evaluate only new targets (must be evaluated on both) */ export class MaxTargetsPerOrganCriterion extends BaseCriterion { @@ -25,25 +31,31 @@ export class MaxTargetsPerOrganCriterion extends BaseCriterion { } evaluate(data) { + const { options } = this; const targetsPerOrgan = {}; - let message; let measurements = []; - for (let i = 0; i < data.targets.length; i++) { - const measurement = data.targets[i].measurement; + const newTargetNumbers = this.getNewTargetNumbers(data); + _.each(data.targets, target => { + const { measurement } = target; const { location, measurementNumber } = measurement; if (!targetsPerOrgan[location]) { targetsPerOrgan[location] = new Set(); } - targetsPerOrgan[location].add(measurementNumber); - if (targetsPerOrgan[location].size > this.options.limit) { + if (!options.newTarget || newTargetNumbers.has(measurementNumber)) { + targetsPerOrgan[location].add(measurementNumber); + } + + if (targetsPerOrgan[location].size > options.limit) { measurements.push(measurement); } - } + }); + let message; 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);