From f00896e66d95e72312d6d4f9cbf8b6ff17941942 Mon Sep 17 00:00:00 2001 From: Dillan Cooke Date: Mon, 12 Aug 2024 14:12:18 -0400 Subject: [PATCH] [GLT-4252] Case QC Report improvements for stopped cases --- changes/change_case_qc_stopped.md | 2 + ts/case-report.ts | 81 +++++++++++++++++++++++++------ 2 files changed, 68 insertions(+), 15 deletions(-) create mode 100644 changes/change_case_qc_stopped.md diff --git a/changes/change_case_qc_stopped.md b/changes/change_case_qc_stopped.md new file mode 100644 index 00000000..33ba2a38 --- /dev/null +++ b/changes/change_case_qc_stopped.md @@ -0,0 +1,2 @@ +The Case QC Report now displays "CASE STOPPED" along with the stop reason if the case is stopped, +and correctly shows incomplete sign-offs as "N/A (case stopped)" diff --git a/ts/case-report.ts b/ts/case-report.ts index 7b1cb23c..f4227e1a 100644 --- a/ts/case-report.ts +++ b/ts/case-report.ts @@ -16,7 +16,7 @@ import { deliverableTypeLabels, } from "./data/case"; import { qcStatuses } from "./data/qc-status"; -import { makeTextDiv } from "./util/html-utils"; +import { makeTextDiv, styleText } from "./util/html-utils"; import { addMetricValueContents, getFirstReviewStatus, @@ -27,10 +27,7 @@ import { subcategoryApplies as sampleSubcategoryApplies, } from "./data/sample"; import { addTextDiv, makeNameDiv } from "./util/html-utils"; -import { - getBooleanMetricValueIcon, - getMetricRequirementText, -} from "./util/metrics"; +import { getMetricRequirementText } from "./util/metrics"; import { get } from "./util/requests"; import { siteConfig } from "./util/site-config"; import { urls } from "./util/urls"; @@ -42,6 +39,7 @@ interface ReportSample { metricCategory: MetricCategory; metricSubcategory: MetricSubcategory; caseAssayId: number; + caseStopped: boolean; } interface ReportAnalysisReview { @@ -50,6 +48,7 @@ interface ReportAnalysisReview { deliverable: CaseDeliverable; metricCategory: MetricCategory; metricSubcategory: MetricSubcategory; + caseStopped: boolean; } const attributes: AttributeDefinition[] = [ @@ -59,6 +58,21 @@ const attributes: AttributeDefinition[] = [ fragment.appendChild( makeNameDiv(object.id, undefined, urls.dimsum.case(object.id)) ); + if (object.requisition.stopped) { + const stopDiv = document.createElement("div"); + const stopText = document.createElement("span"); + stopText.innerText = "CASE STOPPED"; + styleText(stopText, "error"); + stopDiv.appendChild(stopText); + + if (object.requisition.stopReason) { + const reasonText = document.createElement("span"); + reasonText.innerText = ` (${object.requisition.stopReason})`; + stopDiv.appendChild(reasonText); + } + + fragment.appendChild(stopDiv); + } }, }, { @@ -230,14 +244,20 @@ const sampleGateMetricsDefinition: TableDefinition = { { title: "QC Metric Sign-Off", addParentContents(object, fragment) { - displayQcSignOff(fragment, getRunOrSampleLevel(object)); + displayQcSignOff( + fragment, + getRunOrSampleLevel(object), + object.caseStopped + ); addAssayMismatchText(fragment, object); }, getCellHighlight(object) { const qcable = getRunOrSampleLevel(object); - const reviewStatus = getFirstReviewStatus(qcable).cellStatus; - if (reviewStatus) { - return reviewStatus; + const reviewStatus = getFirstReviewStatus(qcable); + if (reviewStatus === qcStatuses.qc && object.caseStopped) { + return "na"; + } else if (reviewStatus.cellStatus) { + return reviewStatus.cellStatus; } else if (!object.sample.assayIds?.includes(object.caseAssayId)) { return "warning"; } @@ -248,7 +268,11 @@ const sampleGateMetricsDefinition: TableDefinition = { title: "QC Stage Sign-Off", addParentContents(object, fragment) { if (object.sample.run) { - displayDataReviewSignOff(fragment, getRunOrSampleLevel(object)); + displayDataReviewSignOff( + fragment, + getRunOrSampleLevel(object), + object.caseStopped + ); addAssayMismatchText(fragment, object); } else { addText(fragment, "No second review required"); @@ -261,7 +285,11 @@ const sampleGateMetricsDefinition: TableDefinition = { if (object.sample.run) { const qcable = getRunOrSampleLevel(object); if (!qcable.dataReviewDate) { - return qcStatuses.dataReview.cellStatus; + if (object.caseStopped) { + return "na"; + } else { + return qcStatuses.dataReview.cellStatus; + } } else if (qcable.dataReviewPassed) { return assayStatus; } else { @@ -393,6 +421,7 @@ const analysisReviewMetricsDefinition: TableDefinition< const deliverable = object.deliverable; displaySignOff( fragment, + object.caseStopped, deliverable.analysisReviewQcPassed, undefined, deliverable.analysisReviewQcUser, @@ -401,8 +430,14 @@ const analysisReviewMetricsDefinition: TableDefinition< ); }, getCellHighlight(object) { - return getDeliverableQcStatus(object.deliverable.analysisReviewQcPassed) - .cellStatus; + const status = getDeliverableQcStatus( + object.deliverable.analysisReviewQcPassed + ); + if (status === qcStatuses.qc && object.caseStopped) { + return "na"; + } else { + return status.cellStatus; + } }, }, { @@ -417,9 +452,14 @@ const analysisReviewMetricsDefinition: TableDefinition< ], }; -function displayQcSignOff(fragment: DocumentFragment, qcable: Qcable) { +function displayQcSignOff( + fragment: DocumentFragment, + qcable: Qcable, + caseStopped: boolean +) { displaySignOff( fragment, + caseStopped, qcable.qcPassed, qcable.qcReason, qcable.qcUser, @@ -428,9 +468,14 @@ function displayQcSignOff(fragment: DocumentFragment, qcable: Qcable) { ); } -function displayDataReviewSignOff(fragment: DocumentFragment, qcable: Qcable) { +function displayDataReviewSignOff( + fragment: DocumentFragment, + qcable: Qcable, + caseStopped: boolean +) { displaySignOff( fragment, + caseStopped, qcable.dataReviewPassed, undefined, qcable.dataReviewUser, @@ -440,6 +485,7 @@ function displayDataReviewSignOff(fragment: DocumentFragment, qcable: Qcable) { function displaySignOff( fragment: DocumentFragment, + caseStopped: boolean, qcPassed?: boolean, qcReason?: string, qcUser?: string, @@ -461,6 +507,8 @@ function displaySignOff( noteDiv.classList.add("mt-1em"); fragment.appendChild(noteDiv); } + } else if (caseStopped) { + fragment.appendChild(document.createTextNode("N/A (case stopped)")); } else { addPendingText(fragment); } @@ -617,6 +665,7 @@ function getReportSamples( metrics: [], }, caseAssayId: kase.assayId, + caseStopped: kase.requisition.stopped, }, ]; } @@ -628,6 +677,7 @@ function getReportSamples( metricCategory: category, metricSubcategory: subcategory, caseAssayId: kase.assayId, + caseStopped: kase.requisition.stopped, }; }); }) @@ -689,6 +739,7 @@ function getReportAnalysisReviews(kase: Case) { deliverable: deliverable, metricCategory: "ANALYSIS_REVIEW", metricSubcategory: subcategory, + caseStopped: kase.requisition.stopped, }; }); });