From 1fecd8c576688c2e5deb90962f670c70e67b87d4 Mon Sep 17 00:00:00 2001 From: Howard Tong Date: Tue, 4 Jun 2019 22:37:38 -0700 Subject: [PATCH 1/5] #1824: Adds confirm modal for no criteria summary --- .../variant_central/interpretation/summary.js | 546 +++++++++--------- .../components/variant_central/title.js | 36 +- 2 files changed, 304 insertions(+), 278 deletions(-) diff --git a/src/clincoded/static/components/variant_central/interpretation/summary.js b/src/clincoded/static/components/variant_central/interpretation/summary.js index 8a3c99f95..cc68865ca 100644 --- a/src/clincoded/static/components/variant_central/interpretation/summary.js +++ b/src/clincoded/static/components/variant_central/interpretation/summary.js @@ -126,7 +126,9 @@ var EvaluationSummary = module.exports.EvaluationSummary = createReactClass({ } } if (!this.state.evidenceSummary) { - this.refs['evaluation-evidence-summary'].resetValue(); + if (this.refs['.evaluation-evidence-summary']) { + this.refs['evaluation-evidence-summary'].resetValue(); + } } else { this.refs['evaluation-evidence-summary'].setValue(this.state.evidenceSummary); } @@ -582,7 +584,7 @@ var EvaluationSummary = module.exports.EvaluationSummary = createReactClass({ render() { let interpretation = this.state.interpretation; let evaluations = interpretation ? interpretation.evaluations : null; - let sortedEvaluations = evaluations ? sortByStrength(evaluations) : null; + let sortedEvaluations = sortByStrength(evaluations); let calculatedAssertion = this.state.autoClassification ? this.state.autoClassification : this.state.calculatedAssertion; let provisionalVariant = null; let alteredClassification = null; @@ -627,318 +629,312 @@ var EvaluationSummary = module.exports.EvaluationSummary = createReactClass({ return (

Evaluation Summary

- - {(evaluations && evaluations.length) ? -
- -
-
-
-
-
-
-
Calculated Pathogenicity:
-
{calculatedAssertion ? calculatedAssertion : 'None'}
-
-
-
Modified Pathogenicity:
-
{modifiedPathogenicity ? modifiedPathogenicity : 'None'}
-
-
-
-
-
Disease:
-
{interpretation.disease && interpretation.disease.term ? interpretation.disease.term : 'None'}
-
-
-
Mode of Inheritance:
-
{renderSelectedModeInheritance(interpretation)}
-
-
+
+
+
+ +
+
+
+
Calculated Pathogenicity:
+
{calculatedAssertion ? calculatedAssertion : 'None'}
+
+
+
Modified Pathogenicity:
+
{modifiedPathogenicity ? modifiedPathogenicity : 'None'}
+
- {!this.state.isClassificationViewOnly ? -
-
-
-
- Modify Pathogenicity:(optional)} - defaultValue={provisionalPathogenicity} handleChange={this.handleChange} - labelClassName="col-sm-6 control-label" wrapperClassName="col-sm-6" groupClassName="form-group"> - - - - - - - - - Explain reason(s) for change:(required for modified pathogenicity)} - value={provisionalReason} handleChange={this.handleChange} rows="5" - placeholder="Note: If you selected a pathogenicity different from the Calculated Pathogenicity, you must provide a reason for the change here." - labelClassName="col-sm-6 control-label" wrapperClassName="col-sm-6" groupClassName="form-group" /> -
-
-
-
- -
+
+
+
Disease:
+
{interpretation.disease && interpretation.disease.term ? interpretation.disease.term : 'None'}
+
+
+
Mode of Inheritance:
+
{renderSelectedModeInheritance(interpretation)}
+
+
+
+ {!this.state.isClassificationViewOnly ? +
+
+
+
+ Modify Pathogenicity:(optional)} + defaultValue={provisionalPathogenicity} handleChange={this.handleChange} + labelClassName="col-sm-6 control-label" wrapperClassName="col-sm-6" groupClassName="form-group"> + + + + + + + + + Explain reason(s) for change:(required for modified pathogenicity)} + value={provisionalReason} handleChange={this.handleChange} rows="5" + placeholder="Note: If you selected a pathogenicity different from the Calculated Pathogenicity, you must provide a reason for the change here." + labelClassName="col-sm-6 control-label" wrapperClassName="col-sm-6" groupClassName="form-group" />
-
-
- An Interpretation will remain In Progress until Saved as Provisional. +
+
+
-
- : -
-
-
-
-
-
-
Modify Pathogenicity:
-
{provisionalPathogenicity}
-
-
-
-
-
Explain reason(s) for change:
-
{provisionalReason && provisionalReason.length ? provisionalReason : 'None'}
-
-
+
+
+ An Interpretation will remain In Progress until Saved as Provisional. +
+ +
+
+ : +
+
+
+
+
+
+
Modify Pathogenicity:
+
{provisionalPathogenicity}
+
-
-
-
-
-
Evidence Summary:
-
{evidenceSummary && evidenceSummary.length ? evidenceSummary : 'None'}
+
+
+
Explain reason(s) for change:
+
{provisionalReason && provisionalReason.length ? provisionalReason : 'None'}
- {classificationStatus === 'In progress' ? -
- +
+
+
+
Evidence Summary:
+
{evidenceSummary && evidenceSummary.length ? evidenceSummary : 'None'}
+
- : null} -
- } - -
-
- {provisionalVariant && showProvisional ? -
- {shouldProvisionClassification ? -
-
-

- Save this Interpretation as Provisional if you have finished all your evaluations and wish to mark it as complete. Once - you have saved it as Provisional, you will not be able to undo it, but you will be able to make a new current Provisional Interpretation, archiving the current - one, with access to its Evaluation Summary. -

-
-
-
-

Save Interpretation as Provisional

-
-
-
-
- : -
-

- The option to save an Interpretation as Provisional will not appear when the saved calculated or modified value - is "Likely Pathogenic" or "Pathogenic" and there is no associated disease. -

+ {classificationStatus === 'In progress' ? +
+ +
+ : null}
} -
- : null} - {provisionalVariant && showApproval ? -
-
-

- When ready, you may save this Provisional Interpretation as Approved. Once you have saved it as Approved it will become - uneditable, but you will be able to save a new current Approved Interpretation, thus archiving this current one and retaining access to its Evaluation Summary. -

-
-
-
-

Approve Interpretation

-
-
- -
-
-
- : null} - {provisionalVariant && (showPublish || showUnpublish) ? -
-
- {isPublishActive === 'auto' ? -

- Publish the current () - Approved Interpretation to the Evidence Repository. -

- : + +
+
+ {provisionalVariant && showProvisional ? +
+ {shouldProvisionClassification ? +
+

- {showUnpublish ? 'Unpublish' : 'Publish'} the selected - Approved Interpretation {showUnpublish ? 'from' : 'to'} the Evidence Repository. + Save this Interpretation as Provisional if you have finished all your evaluations and wish to mark it as complete. Once + you have saved it as Provisional, you will not be able to undo it, but you will be able to make a new current Provisional Interpretation, archiving the current + one, with access to its Evaluation Summary.

- } -
-
-
-

{showUnpublish ? 'Unpublish Interpretation from' : 'Publish Interpretation to'} the Evidence Repository

-
- +
+
+

Save Interpretation as Provisional

+
+
+ +
-
- : null} - {!showProvisional && !showApproval && !allowPublishButton ? -
+ : +
+

+ The option to save an Interpretation as Provisional will not appear when the saved calculated or modified value + is "Likely Pathogenic" or "Pathogenic" and there is no associated disease. +

+
+ } +
+ : null} + {provisionalVariant && showApproval ? +
+

- The option to publish an approved interpretation to the Evidence Repository is - currently only available for VCEPs that have guidelines approved by the Sequence Variant Interpretation Working Group. + When ready, you may save this Provisional Interpretation as Approved. Once you have saved it as Approved it will become + uneditable, but you will be able to save a new current Approved Interpretation, thus archiving this current one and retaining access to its Evaluation Summary.

- : null} - {sortedSnapshotList.length ? -
+
-

Saved Provisional and Approved Interpretation(s)

+

Approve Interpretation

- + provisional={provisionalVariant} + affiliation={affiliation} + updateSnapshotList={this.props.updateSnapshotList} + updateProvisionalObj={this.props.updateProvisionalObj} + snapshots={sortedSnapshotList} + />
- : null} - -
-
-

Criteria meeting an evaluation strength

-
- - - {tableHeader()} - - {sortedEvaluations.met ? - - {sortedEvaluations.met.map(function(item, i) { - return (renderMetCriteriaRow(item, i)); - })} - + + : null} + {provisionalVariant && (showPublish || showUnpublish) ? +
+
+ {isPublishActive === 'auto' ? +

+ Publish the current () + Approved Interpretation to the Evidence Repository. +

: -
- No criteria meeting an evaluation strength. -
+

+ {showUnpublish ? 'Unpublish' : 'Publish'} the selected + Approved Interpretation {showUnpublish ? 'from' : 'to'} the Evidence Repository. +

} -
+
+
+
+

{showUnpublish ? 'Unpublish Interpretation from' : 'Publish Interpretation to'} the Evidence Repository

+
+
+ +
+
- -
+ : null} + {!showProvisional && !showApproval && !allowPublishButton ? +
+

+ The option to publish an approved interpretation to the Evidence Repository is + currently only available for VCEPs that have guidelines approved by the Sequence Variant Interpretation Working Group. +

+
+ : null} + {sortedSnapshotList.length ? +
-

Criteria evaluated as "Not met"

+

Saved Provisional and Approved Interpretation(s)

+
+
+
- - - {tableHeader()} - - {sortedEvaluations.not_met ? - - {sortedEvaluations.not_met.map(function(item, i) { - return (renderNotMetCriteriaRow(item, i)); - })} - - : -
- No criteria evaluated as "Not met". -
- } -
+ : null} -
-
-

Criteria "Not yet evaluated"

-
- - - {tableHeader()} - - {sortedEvaluations.not_evaluated ? - - {sortedEvaluations.not_evaluated.map(function(item, i) { - return (renderNotEvalCriteriaRow(item, i)); - })} - - : -
- No criteria yet to be evaluated. -
- } -
+
+
+

Criteria meeting an evaluation strength

+ + + {tableHeader()} + + {sortedEvaluations.met ? + + {sortedEvaluations.met.map(function(item, i) { + return (renderMetCriteriaRow(item, i)); + })} + + : +
+ No criteria meeting an evaluation strength. +
+ } +
+
+
+
+

Criteria evaluated as "Not met"

+
+ + + {tableHeader()} + + {sortedEvaluations.not_met ? + + {sortedEvaluations.not_met.map(function(item, i) { + return (renderNotMetCriteriaRow(item, i)); + })} + + : +
+ No criteria evaluated as "Not met". +
+ } +
- : -

No evaluations found in this interpretation.

- } + +
+
+

Criteria "Not yet evaluated"

+
+ + + {tableHeader()} + + {sortedEvaluations.not_evaluated ? + + {sortedEvaluations.not_evaluated.map(function(item, i) { + return (renderNotEvalCriteriaRow(item, i)); + })} + + : +
+ No criteria yet to be evaluated. +
+ } +
+
+ +
); } @@ -1179,7 +1175,7 @@ function getModifiedLevel(entry) { // untouched obj has only one key:value element (criteria: code) // } -function sortByStrength(evaluations) { +function sortByStrength(evaluations = []) { // Get all criteria codes let criteriaCodes = Object.keys(evidenceCodes); diff --git a/src/clincoded/static/components/variant_central/title.js b/src/clincoded/static/components/variant_central/title.js index 2f31182e9..30e5943c9 100644 --- a/src/clincoded/static/components/variant_central/title.js +++ b/src/clincoded/static/components/variant_central/title.js @@ -3,6 +3,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; import _ from 'underscore'; +import ModalComponent from '../../libs/bootstrap/modal'; import { FormMixin, Form, Input } from '../../libs/bootstrap/form'; import { queryKeyValue, editQueryValue, addQueryKey } from '../globals'; import { renderVariantTitle } from '../../libs/render_variant_title'; @@ -69,6 +70,21 @@ var Title = module.exports.Title = createReactClass({ return title; }, + /** + * Method to handle user's response (Agree/Disagree) to PHI Disclaimer modal (presented when user attempts to start a new interpretation) + * @param {object} e - The submitted event object + * @param {string} buttonSelected - String value of the button/response selected by the user + */ + handleViewSummaryResponse: function(e, buttonSelected) { + this.child.closeModal(); + + if (buttonSelected === 'Continue') { + this.handleSummaryButtonEvent(e); + } else { + e.preventDefault(); e.stopPropagation(); + } + }, + // handler for 'View Summary' & 'Return to Interpretation' button click events handleSummaryButtonEvent: function(e) { e.preventDefault(); e.stopPropagation(); @@ -95,9 +111,9 @@ var Title = module.exports.Title = createReactClass({ render() { const variant = this.props.data; const interpretation = this.state.interpretation; + const evaluations = interpretation ? interpretation.evaluations : null; let calculatePatho_button = this.props.interpretationUuid ? true : false; let summaryButtonTitle = this.state.summaryVisible ? 'Return to Interpretation' : 'View Summary'; - return (
@@ -109,8 +125,22 @@ var Title = module.exports.Title = createReactClass({
- + {this.state.summaryVisible || (evaluations && evaluations.length) ? + + : + {summaryButtonTitle}} + onRef={ref => (this.child = ref)}> +
+ You have not applied any criteria, are you sure you want to finish this interpretation? +
+
+ this.handleViewSummaryResponse(e, 'Cancel')} title="Cancel" /> + this.handleViewSummaryResponse(e, 'Continue')} title="Continue" /> +
+
+ }
From e8cbe39f554b24be6ab5b56c79289845609e3a34 Mon Sep 17 00:00:00 2001 From: Howard Tong Date: Wed, 5 Jun 2019 08:57:52 -0700 Subject: [PATCH 2/5] Removes incorrect comment --- src/clincoded/static/components/variant_central/title.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/clincoded/static/components/variant_central/title.js b/src/clincoded/static/components/variant_central/title.js index 30e5943c9..b06cad008 100644 --- a/src/clincoded/static/components/variant_central/title.js +++ b/src/clincoded/static/components/variant_central/title.js @@ -70,11 +70,6 @@ var Title = module.exports.Title = createReactClass({ return title; }, - /** - * Method to handle user's response (Agree/Disagree) to PHI Disclaimer modal (presented when user attempts to start a new interpretation) - * @param {object} e - The submitted event object - * @param {string} buttonSelected - String value of the button/response selected by the user - */ handleViewSummaryResponse: function(e, buttonSelected) { this.child.closeModal(); From ba96abbdf515341db77bc1470e600fd7bb3538d2 Mon Sep 17 00:00:00 2001 From: Howard Tong Date: Thu, 6 Jun 2019 10:38:35 -0700 Subject: [PATCH 3/5] Fixes save with no evals --- .../components/variant_central/interpretation/summary.js | 6 +++--- src/clincoded/static/components/variant_central/title.js | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/clincoded/static/components/variant_central/interpretation/summary.js b/src/clincoded/static/components/variant_central/interpretation/summary.js index cc68865ca..60b5c0522 100644 --- a/src/clincoded/static/components/variant_central/interpretation/summary.js +++ b/src/clincoded/static/components/variant_central/interpretation/summary.js @@ -44,7 +44,7 @@ var EvaluationSummary = module.exports.EvaluationSummary = createReactClass({ getInitialState() { return { interpretation: this.props.interpretation, - calculatedAssertion: this.props.calculatedAssertion, + calculatedAssertion: this.props.calculatedAssertion || 'Uncertain significance', autoClassification: null, modifiedPathogenicity: null, provisionalPathogenicity: this.props.provisionalPathogenicity, @@ -583,7 +583,7 @@ var EvaluationSummary = module.exports.EvaluationSummary = createReactClass({ render() { let interpretation = this.state.interpretation; - let evaluations = interpretation ? interpretation.evaluations : null; + let evaluations = interpretation ? interpretation.evaluations : undefined; let sortedEvaluations = sortByStrength(evaluations); let calculatedAssertion = this.state.autoClassification ? this.state.autoClassification : this.state.calculatedAssertion; let provisionalVariant = null; @@ -647,7 +647,7 @@ var EvaluationSummary = module.exports.EvaluationSummary = createReactClass({
Disease:
-
{interpretation.disease && interpretation.disease.term ? interpretation.disease.term : 'None'}
+
{interpretation && interpretation.disease && interpretation.disease.term ? interpretation.disease.term : 'None'}
Mode of Inheritance:
diff --git a/src/clincoded/static/components/variant_central/title.js b/src/clincoded/static/components/variant_central/title.js index b06cad008..a1e6d5856 100644 --- a/src/clincoded/static/components/variant_central/title.js +++ b/src/clincoded/static/components/variant_central/title.js @@ -106,6 +106,7 @@ var Title = module.exports.Title = createReactClass({ render() { const variant = this.props.data; const interpretation = this.state.interpretation; + const provisionalCount = interpretation ? interpretation.provisional_count : 0; const evaluations = interpretation ? interpretation.evaluations : null; let calculatePatho_button = this.props.interpretationUuid ? true : false; let summaryButtonTitle = this.state.summaryVisible ? 'Return to Interpretation' : 'View Summary'; @@ -120,7 +121,7 @@ var Title = module.exports.Title = createReactClass({
- {this.state.summaryVisible || (evaluations && evaluations.length) ? + {this.state.summaryVisible || (evaluations && evaluations.length) || provisionalCount > 0 ? : From 985c630cc157aabf25165f16b0723b0ff02413d6 Mon Sep 17 00:00:00 2001 From: Howard Tong Date: Thu, 6 Jun 2019 11:59:30 -0700 Subject: [PATCH 4/5] Fixes code style --- src/clincoded/static/components/variant_central/title.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clincoded/static/components/variant_central/title.js b/src/clincoded/static/components/variant_central/title.js index a1e6d5856..955b870f1 100644 --- a/src/clincoded/static/components/variant_central/title.js +++ b/src/clincoded/static/components/variant_central/title.js @@ -124,7 +124,7 @@ var Title = module.exports.Title = createReactClass({ {this.state.summaryVisible || (evaluations && evaluations.length) || provisionalCount > 0 ? - : + : {summaryButtonTitle}} onRef={ref => (this.child = ref)}> From fc88226cd5f8985b8f64d5ec5b275ad623e16984 Mon Sep 17 00:00:00 2001 From: Howard Tong Date: Tue, 20 Aug 2019 10:29:48 -0700 Subject: [PATCH 5/5] Fixes logic for eval summary tables, refactor --- .../variant_central/interpretation/summary.js | 230 ++---------------- .../evaluations.js | 208 ++-------------- .../static/libs/sort_eval_criteria.js | 181 ++++++++++++++ 3 files changed, 223 insertions(+), 396 deletions(-) create mode 100644 src/clincoded/static/libs/sort_eval_criteria.js diff --git a/src/clincoded/static/components/variant_central/interpretation/summary.js b/src/clincoded/static/components/variant_central/interpretation/summary.js index 60b5c0522..cf7068f39 100644 --- a/src/clincoded/static/components/variant_central/interpretation/summary.js +++ b/src/clincoded/static/components/variant_central/interpretation/summary.js @@ -16,6 +16,7 @@ import CurationSnapshots from '../../provisional_classification/snapshots'; import { renderSelectedModeInheritance } from '../../../libs/render_mode_inheritance'; import { sortListByDate } from '../../../libs/helpers/sort'; import { allowPublishGlobal } from '../../../libs/allow_publish'; +import { sortByStrength } from '../../../libs/sort_eval_criteria'; var EvaluationSummary = module.exports.EvaluationSummary = createReactClass({ mixins: [FormMixin, RestMixin], @@ -44,7 +45,7 @@ var EvaluationSummary = module.exports.EvaluationSummary = createReactClass({ getInitialState() { return { interpretation: this.props.interpretation, - calculatedAssertion: this.props.calculatedAssertion || 'Uncertain significance', + calculatedAssertion: this.props.calculatedAssertion || 'Uncertain significance - insufficient evidence', autoClassification: null, modifiedPathogenicity: null, provisionalPathogenicity: this.props.provisionalPathogenicity, @@ -126,9 +127,7 @@ var EvaluationSummary = module.exports.EvaluationSummary = createReactClass({ } } if (!this.state.evidenceSummary) { - if (this.refs['.evaluation-evidence-summary']) { - this.refs['evaluation-evidence-summary'].resetValue(); - } + this.refs['evaluation-evidence-summary'].resetValue(); } else { this.refs['evaluation-evidence-summary'].setValue(this.state.evidenceSummary); } @@ -872,44 +871,44 @@ var EvaluationSummary = module.exports.EvaluationSummary = createReactClass({

Criteria meeting an evaluation strength

- - - {tableHeader()} - - {sortedEvaluations.met ? + {sortedEvaluations && sortedEvaluations.met && sortedEvaluations.met.length ? +
+ + {tableHeader()} + {sortedEvaluations.met.map(function(item, i) { return (renderMetCriteriaRow(item, i)); })} - : -
- No criteria meeting an evaluation strength. -
- } -
+ + : +
+ No criteria meeting an evaluation strength. +
+ }

Criteria evaluated as "Not met"

- - - {tableHeader()} - - {sortedEvaluations.not_met ? + {sortedEvaluations && sortedEvaluations.not_met && sortedEvaluations.not_met.length ? +
+ + {tableHeader()} + {sortedEvaluations.not_met.map(function(item, i) { return (renderNotMetCriteriaRow(item, i)); })} - : -
- No criteria evaluated as "Not met". -
- } -
+ + : +
+ No criteria evaluated as "Not met". +
+ }
@@ -920,7 +919,7 @@ var EvaluationSummary = module.exports.EvaluationSummary = createReactClass({ {tableHeader()} - {sortedEvaluations.not_evaluated ? + {sortedEvaluations && sortedEvaluations.not_evaluated && sortedEvaluations.not_evaluated.length ? {sortedEvaluations.not_evaluated.map(function(item, i) { return (renderNotEvalCriteriaRow(item, i)); @@ -1163,180 +1162,3 @@ function getModifiedLevel(entry) { } return modifiedLevel; } - -// Function to sort evaluations by criteria strength level -// Sort Order: very strong or stand alone >> strong >> moderate >> supporting -// Input: array, interpretation.evaluations -// output: object as -// { -// met: array of sorted met evaluations, -// not_met: array of sorted not-met evaluations, -// not_evaluated: array of sorted not-evaluated and untouched objects; -// untouched obj has only one key:value element (criteria: code) -// } - -function sortByStrength(evaluations = []) { - // Get all criteria codes - let criteriaCodes = Object.keys(evidenceCodes); - - let evaluationMet = []; - let evaluationNotMet = []; - let evaluationNotEvaluated = []; - - for (let evaluation of evaluations) { - if (evaluation.criteriaStatus === 'met') { - evaluationMet.push(evaluation); - criteriaCodes.splice(criteriaCodes.indexOf(evaluation.criteria), 1); - } else if (evaluation.criteriaStatus === 'not-met') { - evaluationNotMet.push(evaluation); - criteriaCodes.splice(criteriaCodes.indexOf(evaluation.criteria), 1); - } else { - evaluationNotEvaluated.push(evaluation); - criteriaCodes.splice(criteriaCodes.indexOf(evaluation.criteria), 1); - } - } - - // Generate object for earch untouched criteria - let untouchedCriteriaObjList = []; - if (criteriaCodes.length) { - for (let criterion of criteriaCodes) { - untouchedCriteriaObjList.push({ - criteria: criterion - }); - } - } - // merge not-evaluated and untouched together - evaluationNotEvaluated = evaluationNotEvaluated.concat(untouchedCriteriaObjList); - - let sortedMetList = []; - let sortedNotMetList = []; - let sortedNotEvaluatedList = []; - - // sort Met - if (evaluationMet.length) { - // setup count strength values - const MODIFIER_VS = 'very-strong'; - const MODIFIER_SA = 'stand-alone'; - const MODIFIER_S = 'strong'; - const MODIFIER_M = 'moderate'; - const MODIFIER_P = 'supporting'; - - // temp storage - let vs_sa_level = []; - let strong_level = []; - let moderate_level = []; - let supporting_level = []; - - for (let evaluation of evaluationMet) { - let modified = evaluation.criteriaModifier ? evaluation.criteriaModifier : null; - if (modified) { - if (modified === MODIFIER_VS || modified === MODIFIER_SA) { - vs_sa_level.push(evaluation); - } else if (modified === MODIFIER_S) { - strong_level.push(evaluation); - } else if (modified === MODIFIER_M) { - moderate_level.push(evaluation); - } else if (modified === MODIFIER_P) { - supporting_level.push(evaluation); - } - } else { - if (evaluation.criteria === 'PVS1' || evaluation.criteria === 'BA1') { - vs_sa_level.push(evaluation); - } else if (evaluation.criteria[1] === 'S') { - strong_level.push(evaluation); - } else if (evaluation.criteria[1] === 'M') { - moderate_level.push(evaluation); - } else if (evaluation.criteria[1] === 'P') { - supporting_level.push(evaluation); - } - } - } - - if (vs_sa_level.length) { - sortedMetList = sortedMetList .concat(vs_sa_level); - } - if (strong_level.length) { - sortedMetList = sortedMetList.concat(strong_level); - } - if (moderate_level.length) { - sortedMetList = sortedMetList.concat(moderate_level); - } - if (supporting_level.length) { - sortedMetList = sortedMetList.concat(supporting_level); - } - } - - // sort Not-Met - if (evaluationNotMet.length) { - // temp storage - let vs_sa_level = []; - let strong_level = []; - let moderate_level = []; - let supporting_level = []; - - for (let evaluation of evaluationNotMet) { - if (evaluation.criteria === 'PVS1' || evaluation.criteria === 'BA1') { - vs_sa_level.push(evaluation); - } else if (evaluation.criteria[1] === 'S') { - strong_level.push(evaluation); - } else if (evaluation.criteria[1] === 'M') { - moderate_level.push(evaluation); - } else if (evaluation.criteria[1] === 'P') { - supporting_level.push(evaluation); - } - } - - if (vs_sa_level.length) { - sortedNotMetList = sortedNotMetList .concat(vs_sa_level); - } - if (strong_level.length) { - sortedNotMetList = sortedNotMetList.concat(strong_level); - } - if (moderate_level.length) { - sortedNotMetList = sortedNotMetList.concat(moderate_level); - } - if (supporting_level.length) { - sortedNotMetList = sortedNotMetList.concat(supporting_level); - } - } - - //sort Not-Evaluated and untouched - if (evaluationNotEvaluated.length) { - // temp storage - let vs_sa_level = []; - let strong_level = []; - let moderate_level = []; - let supporting_level = []; - - for (let evaluation of evaluationNotEvaluated) { - if (evaluation.criteria === 'PVS1' || evaluation.criteria === 'BA1') { - vs_sa_level.push(evaluation); - } else if (evaluation.criteria[1] === 'S') { - strong_level.push(evaluation); - } else if (evaluation.criteria[1] === 'M') { - moderate_level.push(evaluation); - } else if (evaluation.criteria[1] === 'P') { - supporting_level.push(evaluation); - } - } - - if (vs_sa_level.length) { - sortedNotEvaluatedList = sortedNotEvaluatedList .concat(vs_sa_level); - } - if (strong_level.length) { - sortedNotEvaluatedList = sortedNotEvaluatedList.concat(strong_level); - } - if (moderate_level.length) { - sortedNotEvaluatedList = sortedNotEvaluatedList.concat(moderate_level); - } - if (supporting_level.length) { - sortedNotEvaluatedList = sortedNotEvaluatedList.concat(supporting_level); - } - } - - return ({ - met: sortedMetList, - not_met: sortedNotMetList, - not_evaluated: sortedNotEvaluatedList - }); -} diff --git a/src/clincoded/static/components/variant_interpretation_summary/evaluations.js b/src/clincoded/static/components/variant_interpretation_summary/evaluations.js index df33d93fd..c8bcf9136 100644 --- a/src/clincoded/static/components/variant_interpretation_summary/evaluations.js +++ b/src/clincoded/static/components/variant_interpretation_summary/evaluations.js @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import * as evidenceCodes from '../variant_central/interpretation/mapping/evidence_code.json'; +import { sortByStrength } from '../../libs/sort_eval_criteria'; class VariantInterpretationSummaryEvaluation extends Component { constructor(props) { @@ -10,8 +11,8 @@ class VariantInterpretationSummaryEvaluation extends Component { render() { const { interpretation, classification } = this.props; - let evaluations = interpretation ? interpretation.evaluations : null; - let sortedEvaluations = evaluations ? sortByStrength(evaluations) : null; + let evaluations = interpretation ? interpretation.evaluations : undefined; + let sortedEvaluations = sortByStrength(evaluations); return (
@@ -19,7 +20,7 @@ class VariantInterpretationSummaryEvaluation extends Component {

Criteria meeting an evaluation strength

- {sortedEvaluations && sortedEvaluations.met ? + {sortedEvaluations && sortedEvaluations.met && sortedEvaluations.met.length ? {tableHeader()} @@ -41,7 +42,7 @@ class VariantInterpretationSummaryEvaluation extends Component {

Criteria evaluated as "Not met"

- {sortedEvaluations && sortedEvaluations.not_met ? + {sortedEvaluations && sortedEvaluations.not_met && sortedEvaluations.not_met.length ?
{tableHeader()} @@ -63,22 +64,22 @@ class VariantInterpretationSummaryEvaluation extends Component {

Criteria "Not yet evaluated"

- {sortedEvaluations && sortedEvaluations.not_evaluated ? -
- - {tableHeader()} - +
+ + {tableHeader()} + + {sortedEvaluations && sortedEvaluations.not_evaluated && sortedEvaluations.not_evaluated.length ? {sortedEvaluations.not_evaluated.map(function(item, i) { return (renderNotEvalCriteriaRow(item, i)); })} -
- : -
- No criteria yet to be evaluated. -
- } + : +
+ No criteria yet to be evaluated. +
+ } +
); @@ -315,180 +316,3 @@ function getModifiedLevel(entry) { } return modifiedLevel; } - -// Function to sort evaluations by criteria strength level -// Sort Order: very strong or stand alone >> strong >> moderate >> supporting -// Input: array, interpretation.evaluations -// output: object as -// { -// met: array of sorted met evaluations, -// not_met: array of sorted not-met evaluations, -// not_evaluated: array of sorted not-evaluated and untouched objects; -// untouched obj has only one key:value element (criteria: code) -// } - -function sortByStrength(evaluations) { - // Get all criteria codes - let criteriaCodes = Object.keys(evidenceCodes); - - let evaluationMet = []; - let evaluationNotMet = []; - let evaluationNotEvaluated = []; - - for (let evaluation of evaluations) { - if (evaluation.criteriaStatus === 'met') { - evaluationMet.push(evaluation); - criteriaCodes.splice(criteriaCodes.indexOf(evaluation.criteria), 1); - } else if (evaluation.criteriaStatus === 'not-met') { - evaluationNotMet.push(evaluation); - criteriaCodes.splice(criteriaCodes.indexOf(evaluation.criteria), 1); - } else { - evaluationNotEvaluated.push(evaluation); - criteriaCodes.splice(criteriaCodes.indexOf(evaluation.criteria), 1); - } - } - - // Generate object for earch untouched criteria - let untouchedCriteriaObjList = []; - if (criteriaCodes.length) { - for (let criterion of criteriaCodes) { - untouchedCriteriaObjList.push({ - criteria: criterion - }); - } - } - // merge not-evaluated and untouched together - evaluationNotEvaluated = evaluationNotEvaluated.concat(untouchedCriteriaObjList); - - let sortedMetList = []; - let sortedNotMetList = []; - let sortedNotEvaluatedList = []; - - // sort Met - if (evaluationMet.length) { - // setup count strength values - const MODIFIER_VS = 'very-strong'; - const MODIFIER_SA = 'stand-alone'; - const MODIFIER_S = 'strong'; - const MODIFIER_M = 'moderate'; - const MODIFIER_P = 'supporting'; - - // temp storage - let vs_sa_level = []; - let strong_level = []; - let moderate_level = []; - let supporting_level = []; - - for (let evaluation of evaluationMet) { - let modified = evaluation.criteriaModifier ? evaluation.criteriaModifier : null; - if (modified) { - if (modified === MODIFIER_VS || modified === MODIFIER_SA) { - vs_sa_level.push(evaluation); - } else if (modified === MODIFIER_S) { - strong_level.push(evaluation); - } else if (modified === MODIFIER_M) { - moderate_level.push(evaluation); - } else if (modified === MODIFIER_P) { - supporting_level.push(evaluation); - } - } else { - if (evaluation.criteria === 'PVS1' || evaluation.criteria === 'BA1') { - vs_sa_level.push(evaluation); - } else if (evaluation.criteria[1] === 'S') { - strong_level.push(evaluation); - } else if (evaluation.criteria[1] === 'M') { - moderate_level.push(evaluation); - } else if (evaluation.criteria[1] === 'P') { - supporting_level.push(evaluation); - } - } - } - - if (vs_sa_level.length) { - sortedMetList = sortedMetList .concat(vs_sa_level); - } - if (strong_level.length) { - sortedMetList = sortedMetList.concat(strong_level); - } - if (moderate_level.length) { - sortedMetList = sortedMetList.concat(moderate_level); - } - if (supporting_level.length) { - sortedMetList = sortedMetList.concat(supporting_level); - } - } - - // sort Not-Met - if (evaluationNotMet.length) { - // temp storage - let vs_sa_level = []; - let strong_level = []; - let moderate_level = []; - let supporting_level = []; - - for (let evaluation of evaluationNotMet) { - if (evaluation.criteria === 'PVS1' || evaluation.criteria === 'BA1') { - vs_sa_level.push(evaluation); - } else if (evaluation.criteria[1] === 'S') { - strong_level.push(evaluation); - } else if (evaluation.criteria[1] === 'M') { - moderate_level.push(evaluation); - } else if (evaluation.criteria[1] === 'P') { - supporting_level.push(evaluation); - } - } - - if (vs_sa_level.length) { - sortedNotMetList = sortedNotMetList .concat(vs_sa_level); - } - if (strong_level.length) { - sortedNotMetList = sortedNotMetList.concat(strong_level); - } - if (moderate_level.length) { - sortedNotMetList = sortedNotMetList.concat(moderate_level); - } - if (supporting_level.length) { - sortedNotMetList = sortedNotMetList.concat(supporting_level); - } - } - - //sort Not-Evaluated and untouched - if (evaluationNotEvaluated.length) { - // temp storage - let vs_sa_level = []; - let strong_level = []; - let moderate_level = []; - let supporting_level = []; - - for (let evaluation of evaluationNotEvaluated) { - if (evaluation.criteria === 'PVS1' || evaluation.criteria === 'BA1') { - vs_sa_level.push(evaluation); - } else if (evaluation.criteria[1] === 'S') { - strong_level.push(evaluation); - } else if (evaluation.criteria[1] === 'M') { - moderate_level.push(evaluation); - } else if (evaluation.criteria[1] === 'P') { - supporting_level.push(evaluation); - } - } - - if (vs_sa_level.length) { - sortedNotEvaluatedList = sortedNotEvaluatedList .concat(vs_sa_level); - } - if (strong_level.length) { - sortedNotEvaluatedList = sortedNotEvaluatedList.concat(strong_level); - } - if (moderate_level.length) { - sortedNotEvaluatedList = sortedNotEvaluatedList.concat(moderate_level); - } - if (supporting_level.length) { - sortedNotEvaluatedList = sortedNotEvaluatedList.concat(supporting_level); - } - } - - return ({ - met: sortedMetList, - not_met: sortedNotMetList, - not_evaluated: sortedNotEvaluatedList - }); -} \ No newline at end of file diff --git a/src/clincoded/static/libs/sort_eval_criteria.js b/src/clincoded/static/libs/sort_eval_criteria.js new file mode 100644 index 000000000..24031f519 --- /dev/null +++ b/src/clincoded/static/libs/sort_eval_criteria.js @@ -0,0 +1,181 @@ +import * as evidenceCodes from '../components/variant_central/interpretation/mapping/evidence_code.json'; + +/** + * Function to sort evaluations by criteria strength level + * Sort Order: very strong or stand alone >> strong >> moderate >> supporting + * + * Ooutput: object as + * { + * met: array of sorted met evaluations, + * not_met: array of sorted not-met evaluations, + * not_evaluated: array of sorted not-evaluated and untouched objects; + * untouched obj has only one key:value element (criteria: code) + * } + * + * @param {array} evaluations interpretation.evaluations + */ +export function sortByStrength(evaluations = []) { + // Get all criteria codes + let criteriaCodes = Object.keys(evidenceCodes); + + let evaluationMet = []; + let evaluationNotMet = []; + let evaluationNotEvaluated = []; + + for (let evaluation of evaluations) { + if (evaluation.criteriaStatus === 'met') { + evaluationMet.push(evaluation); + criteriaCodes.splice(criteriaCodes.indexOf(evaluation.criteria), 1); + } else if (evaluation.criteriaStatus === 'not-met') { + evaluationNotMet.push(evaluation); + criteriaCodes.splice(criteriaCodes.indexOf(evaluation.criteria), 1); + } else { + evaluationNotEvaluated.push(evaluation); + criteriaCodes.splice(criteriaCodes.indexOf(evaluation.criteria), 1); + } + } + + // Generate object for earch untouched criteria + let untouchedCriteriaObjList = []; + if (criteriaCodes.length) { + for (let criterion of criteriaCodes) { + untouchedCriteriaObjList.push({ + criteria: criterion + }); + } + } + // merge not-evaluated and untouched together + evaluationNotEvaluated = evaluationNotEvaluated.concat(untouchedCriteriaObjList); + + let sortedMetList = []; + let sortedNotMetList = []; + let sortedNotEvaluatedList = []; + + // sort Met + if (evaluationMet.length) { + // setup count strength values + const MODIFIER_VS = 'very-strong'; + const MODIFIER_SA = 'stand-alone'; + const MODIFIER_S = 'strong'; + const MODIFIER_M = 'moderate'; + const MODIFIER_P = 'supporting'; + + // temp storage + let vs_sa_level = []; + let strong_level = []; + let moderate_level = []; + let supporting_level = []; + + for (let evaluation of evaluationMet) { + let modified = evaluation.criteriaModifier ? evaluation.criteriaModifier : null; + if (modified) { + if (modified === MODIFIER_VS || modified === MODIFIER_SA) { + vs_sa_level.push(evaluation); + } else if (modified === MODIFIER_S) { + strong_level.push(evaluation); + } else if (modified === MODIFIER_M) { + moderate_level.push(evaluation); + } else if (modified === MODIFIER_P) { + supporting_level.push(evaluation); + } + } else { + if (evaluation.criteria === 'PVS1' || evaluation.criteria === 'BA1') { + vs_sa_level.push(evaluation); + } else if (evaluation.criteria[1] === 'S') { + strong_level.push(evaluation); + } else if (evaluation.criteria[1] === 'M') { + moderate_level.push(evaluation); + } else if (evaluation.criteria[1] === 'P') { + supporting_level.push(evaluation); + } + } + } + + if (vs_sa_level.length) { + sortedMetList = sortedMetList .concat(vs_sa_level); + } + if (strong_level.length) { + sortedMetList = sortedMetList.concat(strong_level); + } + if (moderate_level.length) { + sortedMetList = sortedMetList.concat(moderate_level); + } + if (supporting_level.length) { + sortedMetList = sortedMetList.concat(supporting_level); + } + } + + // sort Not-Met + if (evaluationNotMet.length) { + // temp storage + let vs_sa_level = []; + let strong_level = []; + let moderate_level = []; + let supporting_level = []; + + for (let evaluation of evaluationNotMet) { + if (evaluation.criteria === 'PVS1' || evaluation.criteria === 'BA1') { + vs_sa_level.push(evaluation); + } else if (evaluation.criteria[1] === 'S') { + strong_level.push(evaluation); + } else if (evaluation.criteria[1] === 'M') { + moderate_level.push(evaluation); + } else if (evaluation.criteria[1] === 'P') { + supporting_level.push(evaluation); + } + } + + if (vs_sa_level.length) { + sortedNotMetList = sortedNotMetList .concat(vs_sa_level); + } + if (strong_level.length) { + sortedNotMetList = sortedNotMetList.concat(strong_level); + } + if (moderate_level.length) { + sortedNotMetList = sortedNotMetList.concat(moderate_level); + } + if (supporting_level.length) { + sortedNotMetList = sortedNotMetList.concat(supporting_level); + } + } + + //sort Not-Evaluated and untouched + if (evaluationNotEvaluated.length) { + // temp storage + let vs_sa_level = []; + let strong_level = []; + let moderate_level = []; + let supporting_level = []; + + for (let evaluation of evaluationNotEvaluated) { + if (evaluation.criteria === 'PVS1' || evaluation.criteria === 'BA1') { + vs_sa_level.push(evaluation); + } else if (evaluation.criteria[1] === 'S') { + strong_level.push(evaluation); + } else if (evaluation.criteria[1] === 'M') { + moderate_level.push(evaluation); + } else if (evaluation.criteria[1] === 'P') { + supporting_level.push(evaluation); + } + } + + if (vs_sa_level.length) { + sortedNotEvaluatedList = sortedNotEvaluatedList .concat(vs_sa_level); + } + if (strong_level.length) { + sortedNotEvaluatedList = sortedNotEvaluatedList.concat(strong_level); + } + if (moderate_level.length) { + sortedNotEvaluatedList = sortedNotEvaluatedList.concat(moderate_level); + } + if (supporting_level.length) { + sortedNotEvaluatedList = sortedNotEvaluatedList.concat(supporting_level); + } + } + + return ({ + met: sortedMetList, + not_met: sortedNotMetList, + not_evaluated: sortedNotEvaluatedList + }); +}