From d9ecc001637fdafe7f460fcba5184dcba3f5ef57 Mon Sep 17 00:00:00 2001 From: Ally Wu Date: Fri, 22 Mar 2024 08:13:08 -0400 Subject: [PATCH 1/7] [GLT-4068] added case TAT report --- changes/add_GLT-4068.md | 1 + .../rest/DownloadRestController.java | 3 + .../oicr/gsi/dimsum/service/CaseService.java | 16 +- .../gsi/dimsum/util/reporting/Column.java | 13 + .../util/reporting/reports/CaseReport.java | 259 ++++++++++++++++++ ts/data/case.ts | 25 +- 6 files changed, 315 insertions(+), 2 deletions(-) create mode 100644 changes/add_GLT-4068.md create mode 100644 src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseReport.java diff --git a/changes/add_GLT-4068.md b/changes/add_GLT-4068.md new file mode 100644 index 00000000..c847fe9c --- /dev/null +++ b/changes/add_GLT-4068.md @@ -0,0 +1 @@ +Case TAT report generated from the Cases list and uses the same filters that are applied to the list \ No newline at end of file diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/controller/rest/DownloadRestController.java b/src/main/java/ca/on/oicr/gsi/dimsum/controller/rest/DownloadRestController.java index 9a3656ef..a476d7b7 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/controller/rest/DownloadRestController.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/controller/rest/DownloadRestController.java @@ -19,6 +19,7 @@ import ca.on.oicr.gsi.dimsum.controller.BadRequestException; import ca.on.oicr.gsi.dimsum.service.CaseService; import ca.on.oicr.gsi.dimsum.util.reporting.Report; +import ca.on.oicr.gsi.dimsum.util.reporting.reports.CaseReport; import ca.on.oicr.gsi.dimsum.util.reporting.reports.TglTrackingReport; @RestController @@ -51,6 +52,8 @@ private static Report getReport(String reportName) { switch (reportName) { case "tgl-tracking-sheet": return TglTrackingReport.INSTANCE; + case "case-report": + return CaseReport.INSTANCE; default: throw new BadRequestException("Invalid report name"); } diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/service/CaseService.java b/src/main/java/ca/on/oicr/gsi/dimsum/service/CaseService.java index 18d10009..359af112 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/service/CaseService.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/service/CaseService.java @@ -63,7 +63,6 @@ @Service public class CaseService { - // overlap to maintain signoffs that may have been completed during data refresh private static final int CACHE_OVERLAP_MINUTES = 10; @@ -136,6 +135,21 @@ public Stream getCaseStream(Collection filters) { return filterCases(cacheUpdatedCases, filters); } + public Stream getFilteredCases(Map parameters) { + List filters = convertParametersToFilters(parameters); + return getCaseStream(filters); + } + + private List convertParametersToFilters(Map parameters) { + List filters = new ArrayList<>(); + parameters.forEach((key, value) -> { + CaseFilterKey filterKey = CaseFilterKey.valueOf(key.toUpperCase()); + CaseFilter filter = new CaseFilter(filterKey, value); + filters.add(filter); + }); + return filters; + } + public Map getAssaysById() { return caseData.getAssaysById(); } diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Column.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Column.java index f4b7eedd..5351d282 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Column.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Column.java @@ -32,6 +32,19 @@ public void writeExcelCell(Cell cell, T object) { }; } + public static Column forInteger(String title, Function getter) { + return new Column(title) { + + @Override + public void writeExcelCell(Cell cell, T object) { + Integer value = getter.apply(object); + if (value != null) { + cell.setCellValue(value.doubleValue()); + } + } + }; + } + private final String title; public Column(String title) { diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseReport.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseReport.java new file mode 100644 index 00000000..57c0dee6 --- /dev/null +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseReport.java @@ -0,0 +1,259 @@ +package ca.on.oicr.gsi.dimsum.util.reporting.reports; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import ca.on.oicr.gsi.cardea.data.Assay; +import ca.on.oicr.gsi.cardea.data.Case; +import ca.on.oicr.gsi.cardea.data.Project; +import ca.on.oicr.gsi.cardea.data.Requisition; +import ca.on.oicr.gsi.cardea.data.Sample; +import ca.on.oicr.gsi.cardea.data.Test; +import ca.on.oicr.gsi.dimsum.service.CaseService; +import ca.on.oicr.gsi.dimsum.util.reporting.Column; +import ca.on.oicr.gsi.dimsum.util.reporting.Report; +import ca.on.oicr.gsi.dimsum.util.reporting.ReportSection; +import ca.on.oicr.gsi.dimsum.util.reporting.ReportSection.TableReportSection; + +public class CaseReport extends Report { + + private static class RowData { + private final Case kase; + private final Test test; + private final Assay assay; + private final Requisition requisition; + private final LocalDate completionDate; + + public RowData(Case kase, Test test, Assay assay, Requisition requisition, + LocalDate completionDate) { + this.kase = kase; + this.test = test; + this.assay = assay; + this.requisition = requisition; + this.completionDate = completionDate; + } + + public Case getCase() { + return kase; + } + + public Test getTest() { + return test; + } + + public Assay getAssay() { + return assay; + } + + public Requisition getRequisition() { + return requisition; + } + } + + private static final ReportSection caseSection = + new TableReportSection("Case Report", + Arrays.asList( + Column.forString("Case ID", + x -> x.getCase().getId()), + Column.forString("Projects", + x -> x.getCase().getProjects() + .stream() + .map(Project::getName) + .collect(Collectors + .joining(", "))), + Column.forString("Requisition", + x -> x.getRequisition() + .getName()), + Column.forString("Assay", + x -> x.getAssay() + .getName()), + Column.forString("Assay Test", + x -> x.getTest().getName()), + Column.forString("Start Date", + x -> x.getCase().getStartDate() + .format(DateTimeFormatter.ISO_LOCAL_DATE)), + Column.forString("Receipt Completed", + x -> Optional.ofNullable( + findReceiptCompletedDate( + x.getCase())) + .map(date -> date + .format(DateTimeFormatter.ISO_LOCAL_DATE)) + .orElse("")), + Column.forInteger("Receipt Days", + x -> x.getCase().getReceiptDaysSpent()), + Column.forString("Supplemental Only", + x -> isSupplementalOnly( + x.getTest(), + x.getRequisition()) + ? "Yes" + : "No"), + Column.forString("Extraction Completed", + x -> formatLocalDate( + findExtractionCompletedDate( + x.getCase(), + x.getTest()))), + Column.forInteger("Extraction Days", + x -> x.getTest().getExtractionDaysSpent()), + Column.forString("Library Prep. Completed", + x -> formatLocalDate( + findLibraryPrepCompletedDate( + x.getCase(), + x.getTest()))), + Column.forInteger("Library Prep. Days", + x -> x.getTest().getLibraryPreparationDaysSpent()), + Column.forString("Library Qual. Completed", + x -> formatLocalDate( + findLibraryQualCompletedDate( + x.getCase(), + x.getTest()))), + Column.forInteger("Library Qual. Days", + x -> x.getTest().getLibraryQualificationDaysSpent()), + Column.forString("Full-Depth Completed", + x -> formatLocalDate( + findFullDepthCompletedDate( + x.getCase(), + x.getTest()))), + Column.forInteger("Full-Depth Days", + x -> x.getTest().getFullDepthSequencingDaysSpent()), + Column.forString( + "Analysis Review Completed", + x -> formatLocalDate( + findAnalysisReviewCompletedDate( + x.completionDate))), + Column.forInteger("Analysis Review Days", + x -> x.getCase().getAnalysisReviewDaysSpent()), + Column.forString( + "Release Approval Completed", + x -> formatLocalDate( + findReleaseApprovalCompletedDate( + x.completionDate))), + Column.forInteger("Release Approval Days", + x -> x.getCase().getReleaseApprovalDaysSpent()), + Column.forString("Release Completed", + x -> formatLocalDate( + findReleaseCompletedDate( + x.completionDate))), + Column.forInteger("Release Days", + x -> x.getCase().getReleaseDaysSpent()), + Column.forString("Completion Date", + x -> formatLocalDate( + x.completionDate)), + Column.forInteger("Total Days", + x -> calculateDaysBetween(x + .getCase() + .getStartDate(), + x.completionDate)))) { + + @Override + public List getData(CaseService caseService, + Map parameters) { + Map assaysById = caseService.getAssaysById(); + + return caseService.getFilteredCases(parameters) + .flatMap(kase -> kase.getTests().stream() + .map(test -> { + LocalDate completionDate = + calculateCompletionDate( + test); + return new RowData( + kase, + test, + assaysById.get(kase + .getAssayId()), + kase.getRequisition(), + completionDate); + })) + .collect(Collectors.toList()); + } + + }; + + public static final CaseReport INSTANCE = new CaseReport(); + + private CaseReport() { + super("Case Report", caseSection); + } + + private static String formatLocalDate(LocalDate date) { + return Optional.ofNullable(date) + .map(d -> d.format(DateTimeFormatter.ISO_LOCAL_DATE)) + .orElse(""); + } + + private static boolean isSupplementalOnly(Test test, Requisition requisition) { + if (test == null || test.getExtractions().isEmpty()) { + return false; + } + return test.getExtractions().stream() + .allMatch(sample -> !sample.getRequisitionId() + .equals(requisition.getId())); + } + + private static LocalDate findReceiptCompletedDate(Case kase) { + return findLatestCompletionDate(new ArrayList<>(kase.getReceipts())); + } + + private static LocalDate findExtractionCompletedDate(Case kase, Test test) { + return findLatestCompletionDate(new ArrayList<>(test.getExtractions())); + } + + private static LocalDate findLibraryPrepCompletedDate(Case kase, Test test) { + return findLatestCompletionDate(new ArrayList<>(test.getLibraryPreparations())); + } + + private static LocalDate findLibraryQualCompletedDate(Case kase, Test test) { + return findLatestCompletionDate(new ArrayList<>(test.getLibraryQualifications())); + } + + private static LocalDate findFullDepthCompletedDate(Case kase, Test test) { + return findLatestCompletionDate(new ArrayList<>(test.getFullDepthSequencings())); + } + + private static LocalDate findAnalysisReviewCompletedDate(LocalDate completionDate) { + return completionDate; + + } + + private static LocalDate findReleaseApprovalCompletedDate(LocalDate completionDate) { + return completionDate; + } + + private static LocalDate findReleaseCompletedDate(LocalDate completionDate) { + return completionDate; + } + + private static LocalDate calculateCompletionDate(Test test) { + if (test == null) { + return null; + } + return test.getFullDepthSequencings().stream() + .map(Sample::getQcDate) + .filter(Objects::nonNull) + .max(LocalDate::compareTo) + .orElse(null); + } + + private static LocalDate findLatestCompletionDate(List samples) { + return samples.stream() + .map(Sample::getQcDate) + .filter(Objects::nonNull) + .max(LocalDate::compareTo) + .orElse(null); + } + + private static Integer calculateDaysBetween(LocalDate start, LocalDate end) { + if (start != null && end != null) { + return (int) ChronoUnit.DAYS.between(start, end); + } + return null; + } + +} + diff --git a/ts/data/case.ts b/ts/data/case.ts index 9f8e4cd6..e4020d4e 100644 --- a/ts/data/case.ts +++ b/ts/data/case.ts @@ -21,6 +21,7 @@ import { Requisition } from "./requisition"; import { Tooltip } from "../component/tooltip"; import { caseFilters, latestActivitySort } from "../component/table-components"; import { AssayTargets, Metric, MetricSubcategory } from "./assay"; +import { postDownload } from "../util/requests"; import { anyFail, getMetricNames, @@ -187,7 +188,25 @@ export const caseDefinition: TableDefinition = { } return null; }, - staticActions: [legendAction], + staticActions: [ + legendAction, + { + title: "TAT Report", + handler: () => { + const currentFilters: { [key: string]: any } = {}; + for (const filter of caseFilters) { + const value = getFilterValue(filter.key); + if (value !== undefined && value !== null) { + currentFilters[filter.key] = value; + } + } + postDownload( + urls.rest.downloads.reports("case-report"), + currentFilters + ); + }, + }, + ], bulkActions: [ { title: "Sign Off", @@ -1706,3 +1725,7 @@ function hasDeliverable(kase: Case, deliverable: string) { .flatMap((deliverableType) => deliverableType.releases) .some((release) => release.deliverable === deliverable); } +function getFilterValue(key: string) { + const urlParams = new URLSearchParams(window.location.search); + return urlParams.get(key); +} From 9c63cf58b1e361ce59d1cf9b49ebfcff603369b6 Mon Sep 17 00:00:00 2001 From: Ally Wu Date: Mon, 1 Apr 2024 16:04:11 -0400 Subject: [PATCH 2/7] comments implemented --- .../rest/DownloadRestController.java | 3 + .../gsi/dimsum/util/reporting/Column.java | 19 ++ .../util/reporting/reports/CaseTatReport.java | 206 ++++++++++++++++++ ts/component/table-builder.ts | 6 +- ts/data/case.ts | 19 +- 5 files changed, 250 insertions(+), 3 deletions(-) create mode 100644 src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/controller/rest/DownloadRestController.java b/src/main/java/ca/on/oicr/gsi/dimsum/controller/rest/DownloadRestController.java index 3784146d..a72a2ded 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/controller/rest/DownloadRestController.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/controller/rest/DownloadRestController.java @@ -17,6 +17,7 @@ import ca.on.oicr.gsi.dimsum.service.CaseService; import ca.on.oicr.gsi.dimsum.util.reporting.Report; import ca.on.oicr.gsi.dimsum.util.reporting.ReportFormat; +import ca.on.oicr.gsi.dimsum.util.reporting.reports.CaseTatReport; import ca.on.oicr.gsi.dimsum.util.reporting.reports.DareInputSheet; import ca.on.oicr.gsi.dimsum.util.reporting.reports.FullDepthSummary; import ca.on.oicr.gsi.dimsum.util.reporting.reports.TglTrackingReport; @@ -55,6 +56,8 @@ private static Report getReport(String reportName) { return FullDepthSummary.INSTANCE; case "dare-input-sheet": return DareInputSheet.INSTANCE; + case "case-tat-report": + return CaseTatReport.INSTANCE; default: throw new BadRequestException("Invalid report name"); } diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Column.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Column.java index 639e3f1b..191b4b48 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Column.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Column.java @@ -51,6 +51,25 @@ public String getDelimitedColumnString(String delimiter, T object) { }; } + public static Column forInteger(String title, Function getter) { + return new Column(title) { + + @Override + public void writeExcelCell(Cell cell, T object) { + Integer value = getter.apply(object); + if (value != null) { + cell.setCellValue(value.doubleValue()); + } + } + + @Override + public String getDelimitedColumnString(String delimiter, T object) { + Integer value = getter.apply(object); + return value != null ? value.toString() : ""; + } + }; + } + private final String title; public Column(String title) { diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java new file mode 100644 index 00000000..fce39f28 --- /dev/null +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java @@ -0,0 +1,206 @@ +package ca.on.oicr.gsi.dimsum.util.reporting.reports; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import ca.on.oicr.gsi.cardea.data.Case; +import ca.on.oicr.gsi.cardea.data.CaseDeliverable; +import ca.on.oicr.gsi.cardea.data.CaseRelease; +import ca.on.oicr.gsi.cardea.data.Requisition; +import ca.on.oicr.gsi.cardea.data.Sample; +import ca.on.oicr.gsi.cardea.data.Test; +import ca.on.oicr.gsi.dimsum.service.CaseService; +import ca.on.oicr.gsi.dimsum.service.filtering.CaseFilter; +import ca.on.oicr.gsi.dimsum.service.filtering.CaseFilterKey; +import ca.on.oicr.gsi.dimsum.util.SampleUtils; +import ca.on.oicr.gsi.dimsum.util.reporting.Column; +import ca.on.oicr.gsi.dimsum.util.reporting.Report; +import ca.on.oicr.gsi.dimsum.util.reporting.ReportSection; +import ca.on.oicr.gsi.dimsum.util.reporting.ReportSection.TableReportSection; + +public class CaseTatReport extends Report { + + private static class RowData { + private final Case kase; + private final Test test; + + public RowData(Case kase, Test test) { + this.kase = kase; + this.test = test; + } + + public Case getCase() { + return kase; + } + + public Test getTest() { + return test; + } + } + + private static final ReportSection caseSection = new TableReportSection<>( + "Case Report", + Arrays.asList( + Column.forString("Case ID", x -> x.getCase().getId()), + Column.forString("Projects", + x -> getSortedProjectNameAndPipeline(x.getCase()).stream() + .map(str -> str.split(" - ")[0]) + .collect(Collectors.joining(", "))), + Column.forString("Pipeline", + x -> getSortedProjectNameAndPipeline(x.getCase()).stream() + .map(str -> str.split(" - ")[1]) + .collect(Collectors.joining(", "))), + Column.forString("Requisition", x -> x.getCase().getRequisition().getName()), + Column.forString("Assay", x -> x.getCase().getAssayName()), + Column.forString("Start Date", + x -> x.getCase().getStartDate() + .format(DateTimeFormatter.ISO_LOCAL_DATE)), + Column.forString("Receipt Completed Date", x -> Optional + .ofNullable(findLatestCompletionDate(x.getCase().getReceipts())) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)) + .orElse("")), + Column.forInteger("Receipt Days", x -> x.getCase().getReceiptDaysSpent()), + Column.forString("Test", x -> x.getTest().getName()), + Column.forString("Supplemental Only", + x -> isSupplementalOnly(x.getTest(), x.getCase().getRequisition()) + ? "Yes" + : "No"), + Column.forString("Extraction Completed Date", x -> Optional + .ofNullable(findLatestCompletionDate(x.getTest().getExtractions())) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)) + .orElse("")), + Column.forInteger("Extraction Days", x -> x.getTest().getExtractionDaysSpent()), + Column.forString("Library Prep Completed Date", x -> Optional.ofNullable( + findLatestCompletionDate(x.getTest().getLibraryPreparations())) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)) + .orElse("")), + Column.forInteger("Library Prep. Days", + x -> x.getTest().getLibraryPreparationDaysSpent()), + Column.forString("Library Qual Completed Date", x -> Optional.ofNullable( + findLatestCompletionDate(x.getTest().getLibraryQualifications())) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)) + .orElse("")), + Column.forInteger("Library Qual. Days", + x -> x.getTest().getLibraryQualificationDaysSpent()), + Column.forString("Full Depth Completed Date", x -> Optional + .ofNullable( + findLatestCompletionDate(x.getTest().getFullDepthSequencings())) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)) + .orElse("")), + Column.forInteger("Full-Depth Days", + x -> x.getTest().getFullDepthSequencingDaysSpent()), + Column.forString("Analysis Review Completed", + x -> x.getCase().getDeliverables().stream() + .map(CaseDeliverable::getAnalysisReviewQcDate) + .filter(Objects::nonNull) + .max(LocalDate::compareTo) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)) + .orElse("")), + Column.forInteger("Analysis Review Days", + x -> x.getCase().getAnalysisReviewDaysSpent()), + Column.forString("Release Approval Completed", + x -> x.getCase().getDeliverables().stream() + .map(CaseDeliverable::getReleaseApprovalQcDate) + .filter(Objects::nonNull) + .max(LocalDate::compareTo) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)) + .orElse("")), + Column.forInteger("Release Approval Days", + x -> x.getCase().getReleaseApprovalDaysSpent()), + Column.forString("Completion Date", x -> getCompletionDate(x.getCase())), + Column.forInteger("Total Days", x -> x.getCase().getCaseDaysSpent()))) { + @Override + public List getData(CaseService caseService, Map parameters) { + List filters = convertParametersToFilters(parameters); + return caseService.getCaseStream(filters) + .flatMap(kase -> kase.getTests().stream() + .map(test -> new RowData(kase, test))) + .collect(Collectors.toList()); + } + }; + + public static final CaseTatReport INSTANCE = new CaseTatReport(); + + private CaseTatReport() { + super("Case TAT Report", caseSection); + } + + private static Collection getSortedProjectNameAndPipeline(Case case1) { + return case1.getProjects() + .stream() + .map(project -> project.getName() + " - " + project.getPipeline()) + .sorted(Comparator + .comparing(str -> !str.contains("Accredited with Clinical Report"))) + .collect(Collectors.toList()); + } + + private static List convertParametersToFilters(Map parameters) { + List filters = new ArrayList<>(); + parameters.forEach((key, value) -> { + CaseFilterKey filterKey = CaseFilterKey.valueOf(key.toUpperCase()); + CaseFilter filter = new CaseFilter(filterKey, value); + filters.add(filter); + }); + return filters; + } + + private static boolean isSupplementalOnly(Test test, Requisition requisition) { + if (test == null || test.getExtractions().isEmpty()) { + return false; + } + return test.getExtractions().stream() + .allMatch(sample -> !sample.getRequisitionId().equals(requisition.getId())); + } + + private static LocalDate findLatestCompletionDate(List samples) { + return samples.stream() + .filter(SampleUtils::isPassed) + .map(sample -> { + if (sample.getRun() != null) { + LocalDate sampleReviewDate = sample.getDataReviewDate(); + LocalDate runReviewDate = sample.getRun().getDataReviewDate(); + return Stream.of(sampleReviewDate, runReviewDate) + .filter(Objects::nonNull) + .max(LocalDate::compareTo) + .orElse(null); + } else { + return sample.getQcDate(); + } + }) + .filter(Objects::nonNull) + .max(LocalDate::compareTo) + .orElse(null); + } + + private static String getCompletionDate(Case x) { + if (x.isStopped()) { + return "STOPPED"; + } + List deliverables = x.getDeliverables(); + if (deliverables.isEmpty()) { + return null; + } + List releases = deliverables.get(0).getReleases(); + if (releases.isEmpty()) { + return null; + } + if (releases.stream() + .anyMatch(release -> release.getQcPassed() == null || !release.getQcPassed())) { + return null; + } + LocalDate latestQcDate = releases.stream() + .map(CaseRelease::getQcDate) + .max(LocalDate::compareTo) + .orElse(null); + return latestQcDate != null ? latestQcDate.toString() : null; + } +} diff --git a/ts/component/table-builder.ts b/ts/component/table-builder.ts index 81bf2216..988c349d 100644 --- a/ts/component/table-builder.ts +++ b/ts/component/table-builder.ts @@ -53,7 +53,7 @@ export interface FilterDefinition { export interface StaticAction { title: string; - handler: () => void; + handler: (filters: { key: string; value: string }[]) => void; } export interface BulkAction { @@ -316,7 +316,9 @@ export class TableBuilder { } if (this.definition.staticActions) { this.definition.staticActions.forEach((action) => { - addActionButton(container, action.title, action.handler); + addActionButton(container, action.title, () => + action.handler(this.acceptedFilters) + ); }); } } diff --git a/ts/data/case.ts b/ts/data/case.ts index 8e338565..1c475b55 100644 --- a/ts/data/case.ts +++ b/ts/data/case.ts @@ -187,7 +187,24 @@ export const caseDefinition: TableDefinition = { } return null; }, - staticActions: [legendAction], + staticActions: [ + legendAction, + { + title: "TAT Report", + handler: (filters: { key: string; value: string }[]) => { + const currentFilters: { [key: string]: any } = {}; + for (const filter of filters) { + if (filter.value !== undefined && filter.value !== null) { + currentFilters[filter.key] = filter.value; + } + } + postDownload( + urls.rest.downloads.reports("case-tat-report"), + currentFilters + ); + }, + }, + ], bulkActions: [ { title: "Download", From 765d730b3bbc6257e000698273076156a29593a1 Mon Sep 17 00:00:00 2001 From: Ally Wu Date: Thu, 4 Apr 2024 20:13:59 -0400 Subject: [PATCH 3/7] fixups --- .../oicr/gsi/dimsum/service/CaseService.java | 16 +- .../util/reporting/reports/CaseTatReport.java | 316 +++++++++--------- ts/component/table-builder.ts | 15 +- ts/data/case.ts | 13 +- 4 files changed, 180 insertions(+), 180 deletions(-) diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/service/CaseService.java b/src/main/java/ca/on/oicr/gsi/dimsum/service/CaseService.java index f1bdcf25..3162904a 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/service/CaseService.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/service/CaseService.java @@ -64,6 +64,7 @@ @Service public class CaseService { + // overlap to maintain signoffs that may have been completed during data refresh private static final int CACHE_OVERLAP_MINUTES = 10; @@ -136,21 +137,6 @@ public Stream getCaseStream(Collection filters) { return filterCases(cacheUpdatedCases, filters); } - public Stream getFilteredCases(Map parameters) { - List filters = convertParametersToFilters(parameters); - return getCaseStream(filters); - } - - private List convertParametersToFilters(Map parameters) { - List filters = new ArrayList<>(); - parameters.forEach((key, value) -> { - CaseFilterKey filterKey = CaseFilterKey.valueOf(key.toUpperCase()); - CaseFilter filter = new CaseFilter(filterKey, value); - filters.add(filter); - }); - return filters; - } - public Map getAssaysById() { return caseData.getAssaysById(); } diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java index fce39f28..a3a50d97 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java @@ -4,17 +4,16 @@ import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; import ca.on.oicr.gsi.cardea.data.Case; import ca.on.oicr.gsi.cardea.data.CaseDeliverable; import ca.on.oicr.gsi.cardea.data.CaseRelease; +import ca.on.oicr.gsi.cardea.data.Project; import ca.on.oicr.gsi.cardea.data.Requisition; import ca.on.oicr.gsi.cardea.data.Sample; import ca.on.oicr.gsi.cardea.data.Test; @@ -29,178 +28,179 @@ public class CaseTatReport extends Report { - private static class RowData { - private final Case kase; - private final Test test; + private static class RowData { - public RowData(Case kase, Test test) { - this.kase = kase; - this.test = test; - } + private final Case kase; + private final Test test; - public Case getCase() { - return kase; - } + public RowData(Case kase, Test test) { + this.kase = kase; + this.test = test; + } - public Test getTest() { - return test; - } + public Case getCase() { + return kase; + } + + public Test getTest() { + return test; } + } + + private static final ReportSection caseSection = + new TableReportSection<>("Case Report", + Arrays.asList( + Column.forString("Case ID", x -> x.getCase().getId()), + Column.forString("Projects", + x -> getSortedProjectNameOrPipeline(x.getCase(), Project::getName)), + Column.forString("Pipeline", + x -> getSortedProjectNameOrPipeline(x.getCase(), Project::getPipeline)), + Column.forString("Requisition", x -> x.getCase().getRequisition().getName()), + Column.forString("Assay", x -> x.getCase().getAssayName()), + Column.forString("Start Date", + x -> x.getCase().getStartDate().format(DateTimeFormatter.ISO_LOCAL_DATE)), + Column.forString("Receipt Completed Date", + x -> Optional + .ofNullable(findLatestCompletionDate(x.getCase().getReceipts())) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse("")), + Column.forInteger("Receipt Days", x -> x.getCase().getReceiptDaysSpent()), + Column.forString("Test", x -> x.getTest().getName()), + Column.forString("Supplemental Only", + x -> isSupplementalOnly(x.getTest(), x.getCase().getRequisition()) ? "Yes" + : "No"), + Column.forString("Extraction Completed Date", + x -> Optional + .ofNullable(findLatestCompletionDate(x.getTest().getExtractions())) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse("")), + Column.forInteger("Extraction Days", x -> x.getTest().getExtractionDaysSpent()), + Column.forString("Library Prep Completed Date", + x -> Optional + .ofNullable(findLatestCompletionDate(x.getTest().getLibraryPreparations())) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse("")), + Column.forInteger("Library Prep. Days", + x -> x.getTest().getLibraryPreparationDaysSpent()), + Column.forString("Library Qual Completed Date", + x -> Optional + .ofNullable(findLatestCompletionDate(x.getTest().getLibraryQualifications())) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse("")), + Column.forInteger("Library Qual. Days", + x -> x.getTest().getLibraryQualificationDaysSpent()), + Column.forString("Full Depth Completed Date", + x -> Optional + .ofNullable(findLatestCompletionDate(x.getTest().getFullDepthSequencings())) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse("")), + Column.forInteger("Full-Depth Days", + x -> x.getTest().getFullDepthSequencingDaysSpent()), + Column.forString("Analysis Review Completed", x -> { + List dates = x.getCase().getDeliverables().stream() + .map(CaseDeliverable::getAnalysisReviewQcDate).collect(Collectors.toList()); + if (dates.contains(null)) { + return null; + } + return dates.stream().max(LocalDate::compareTo) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse(null); + }), + Column.forInteger("Analysis Review Days", + x -> x.getCase().getAnalysisReviewDaysSpent()), + Column.forString("Release Approval Completed", x -> { + List dates = x.getCase().getDeliverables().stream() + .map(CaseDeliverable::getReleaseApprovalQcDate).collect(Collectors.toList()); + if (dates.contains(null)) { + return null; + } + return dates.stream().max(LocalDate::compareTo) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse(null); + }), + Column.forInteger("Release Approval Days", + x -> x.getCase().getReleaseApprovalDaysSpent()), + Column.forString("Completion Date", x -> getCompletionDate(x.getCase())), + Column.forInteger("Total Days", x -> x.getCase().getCaseDaysSpent()))) { - private static final ReportSection caseSection = new TableReportSection<>( - "Case Report", - Arrays.asList( - Column.forString("Case ID", x -> x.getCase().getId()), - Column.forString("Projects", - x -> getSortedProjectNameAndPipeline(x.getCase()).stream() - .map(str -> str.split(" - ")[0]) - .collect(Collectors.joining(", "))), - Column.forString("Pipeline", - x -> getSortedProjectNameAndPipeline(x.getCase()).stream() - .map(str -> str.split(" - ")[1]) - .collect(Collectors.joining(", "))), - Column.forString("Requisition", x -> x.getCase().getRequisition().getName()), - Column.forString("Assay", x -> x.getCase().getAssayName()), - Column.forString("Start Date", - x -> x.getCase().getStartDate() - .format(DateTimeFormatter.ISO_LOCAL_DATE)), - Column.forString("Receipt Completed Date", x -> Optional - .ofNullable(findLatestCompletionDate(x.getCase().getReceipts())) - .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)) - .orElse("")), - Column.forInteger("Receipt Days", x -> x.getCase().getReceiptDaysSpent()), - Column.forString("Test", x -> x.getTest().getName()), - Column.forString("Supplemental Only", - x -> isSupplementalOnly(x.getTest(), x.getCase().getRequisition()) - ? "Yes" - : "No"), - Column.forString("Extraction Completed Date", x -> Optional - .ofNullable(findLatestCompletionDate(x.getTest().getExtractions())) - .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)) - .orElse("")), - Column.forInteger("Extraction Days", x -> x.getTest().getExtractionDaysSpent()), - Column.forString("Library Prep Completed Date", x -> Optional.ofNullable( - findLatestCompletionDate(x.getTest().getLibraryPreparations())) - .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)) - .orElse("")), - Column.forInteger("Library Prep. Days", - x -> x.getTest().getLibraryPreparationDaysSpent()), - Column.forString("Library Qual Completed Date", x -> Optional.ofNullable( - findLatestCompletionDate(x.getTest().getLibraryQualifications())) - .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)) - .orElse("")), - Column.forInteger("Library Qual. Days", - x -> x.getTest().getLibraryQualificationDaysSpent()), - Column.forString("Full Depth Completed Date", x -> Optional - .ofNullable( - findLatestCompletionDate(x.getTest().getFullDepthSequencings())) - .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)) - .orElse("")), - Column.forInteger("Full-Depth Days", - x -> x.getTest().getFullDepthSequencingDaysSpent()), - Column.forString("Analysis Review Completed", - x -> x.getCase().getDeliverables().stream() - .map(CaseDeliverable::getAnalysisReviewQcDate) - .filter(Objects::nonNull) - .max(LocalDate::compareTo) - .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)) - .orElse("")), - Column.forInteger("Analysis Review Days", - x -> x.getCase().getAnalysisReviewDaysSpent()), - Column.forString("Release Approval Completed", - x -> x.getCase().getDeliverables().stream() - .map(CaseDeliverable::getReleaseApprovalQcDate) - .filter(Objects::nonNull) - .max(LocalDate::compareTo) - .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)) - .orElse("")), - Column.forInteger("Release Approval Days", - x -> x.getCase().getReleaseApprovalDaysSpent()), - Column.forString("Completion Date", x -> getCompletionDate(x.getCase())), - Column.forInteger("Total Days", x -> x.getCase().getCaseDaysSpent()))) { @Override public List getData(CaseService caseService, Map parameters) { - List filters = convertParametersToFilters(parameters); - return caseService.getCaseStream(filters) - .flatMap(kase -> kase.getTests().stream() - .map(test -> new RowData(kase, test))) - .collect(Collectors.toList()); + List filters = convertParametersToFilters(parameters); + return caseService.getCaseStream(filters) + .flatMap(kase -> kase.getTests().stream().map(test -> new RowData(kase, test))) + .collect(Collectors.toList()); } - }; + }; - public static final CaseTatReport INSTANCE = new CaseTatReport(); + public static final CaseTatReport INSTANCE = new CaseTatReport(); - private CaseTatReport() { - super("Case TAT Report", caseSection); - } + private CaseTatReport() { + super("Case TAT Report", caseSection); + } - private static Collection getSortedProjectNameAndPipeline(Case case1) { - return case1.getProjects() - .stream() - .map(project -> project.getName() + " - " + project.getPipeline()) - .sorted(Comparator - .comparing(str -> !str.contains("Accredited with Clinical Report"))) - .collect(Collectors.toList()); - } + private static String getSortedProjectNameOrPipeline(Case kase, + Function function) { + return kase.getProjects().stream() + .map(function) + .sorted() + .collect(Collectors.joining(", ")); + } - private static List convertParametersToFilters(Map parameters) { - List filters = new ArrayList<>(); - parameters.forEach((key, value) -> { - CaseFilterKey filterKey = CaseFilterKey.valueOf(key.toUpperCase()); - CaseFilter filter = new CaseFilter(filterKey, value); - filters.add(filter); - }); - return filters; - } + private static List convertParametersToFilters(Map parameters) { + List filters = new ArrayList<>(); + parameters.forEach((key, value) -> { + CaseFilterKey filterKey = CaseFilterKey.valueOf(key.toUpperCase()); + CaseFilter filter = new CaseFilter(filterKey, value); + filters.add(filter); + }); + return filters; + } - private static boolean isSupplementalOnly(Test test, Requisition requisition) { - if (test == null || test.getExtractions().isEmpty()) { - return false; - } - return test.getExtractions().stream() - .allMatch(sample -> !sample.getRequisitionId().equals(requisition.getId())); + private static boolean isSupplementalOnly(Test test, Requisition requisition) { + if (test == null || test.getExtractions().isEmpty()) { + return false; } + return test.getExtractions().stream() + .allMatch(sample -> !sample.getRequisitionId() + .equals(requisition.getId())); + } - private static LocalDate findLatestCompletionDate(List samples) { - return samples.stream() - .filter(SampleUtils::isPassed) - .map(sample -> { - if (sample.getRun() != null) { - LocalDate sampleReviewDate = sample.getDataReviewDate(); - LocalDate runReviewDate = sample.getRun().getDataReviewDate(); - return Stream.of(sampleReviewDate, runReviewDate) - .filter(Objects::nonNull) - .max(LocalDate::compareTo) - .orElse(null); - } else { - return sample.getQcDate(); - } - }) - .filter(Objects::nonNull) + private static LocalDate findLatestCompletionDate(List samples) { + return samples.stream() + .filter(SampleUtils::isPassed) + .map(sample -> { + if (sample.getRun() != null) { + LocalDate sampleReviewDate = sample.getDataReviewDate(); + LocalDate runReviewDate = sample.getRun().getDataReviewDate(); + if (sampleReviewDate == null || runReviewDate == null) { + return null; + } + return Stream.of(sampleReviewDate, runReviewDate) .max(LocalDate::compareTo) .orElse(null); - } + } else { + return sample.getQcDate(); + } + }) + .max(LocalDate::compareTo) + .orElse(null); + } - private static String getCompletionDate(Case x) { - if (x.isStopped()) { - return "STOPPED"; - } - List deliverables = x.getDeliverables(); - if (deliverables.isEmpty()) { - return null; - } - List releases = deliverables.get(0).getReleases(); - if (releases.isEmpty()) { - return null; - } - if (releases.stream() - .anyMatch(release -> release.getQcPassed() == null || !release.getQcPassed())) { - return null; - } - LocalDate latestQcDate = releases.stream() - .map(CaseRelease::getQcDate) - .max(LocalDate::compareTo) - .orElse(null); - return latestQcDate != null ? latestQcDate.toString() : null; + private static String getCompletionDate(Case x) { + if (x.isStopped()) { + return "STOPPED"; + } + List deliverables = x.getDeliverables(); + if (deliverables.isEmpty()) { + return null; + } + List releases = deliverables.stream() + .flatMap(deliverable -> deliverable.getReleases().stream()) + .collect(Collectors.toList()); + if (releases.isEmpty()) { + return null; + } + if (releases.stream() + .anyMatch(release -> release.getQcPassed() == null || !release.getQcPassed())) { + return null; } + LocalDate latestQcDate = releases.stream() + .map(CaseRelease::getQcDate) + .max(LocalDate::compareTo) + .orElse(null); + return latestQcDate != null ? latestQcDate.toString() : null; + } } diff --git a/ts/component/table-builder.ts b/ts/component/table-builder.ts index 988c349d..7ad932ab 100644 --- a/ts/component/table-builder.ts +++ b/ts/component/table-builder.ts @@ -53,7 +53,10 @@ export interface FilterDefinition { export interface StaticAction { title: string; - handler: (filters: { key: string; value: string }[]) => void; + handler: ( + filters: { key: string; value: string }[], + baseFilter?: { key: string; value: string } + ) => void; } export interface BulkAction { @@ -316,9 +319,13 @@ export class TableBuilder { } if (this.definition.staticActions) { this.definition.staticActions.forEach((action) => { - addActionButton(container, action.title, () => - action.handler(this.acceptedFilters) - ); + addActionButton(container, action.title, () => { + const baseFilter = + this.baseFilterKey && this.baseFilterValue + ? { key: this.baseFilterKey, value: this.baseFilterValue } + : undefined; + action.handler(this.acceptedFilters, baseFilter); + }); }); } } diff --git a/ts/data/case.ts b/ts/data/case.ts index 1c475b55..06c27f66 100644 --- a/ts/data/case.ts +++ b/ts/data/case.ts @@ -192,15 +192,22 @@ export const caseDefinition: TableDefinition = { { title: "TAT Report", handler: (filters: { key: string; value: string }[]) => { - const currentFilters: { [key: string]: any } = {}; + const currentFilters: { [key: string]: string[] } = {}; for (const filter of filters) { if (filter.value !== undefined && filter.value !== null) { - currentFilters[filter.key] = filter.value; + if (!currentFilters[filter.key]) { + currentFilters[filter.key] = []; + } + currentFilters[filter.key].push(filter.value); } } + const joinedFilters: { [key: string]: string } = {}; + for (const key in currentFilters) { + joinedFilters[key] = currentFilters[key].join(","); + } postDownload( urls.rest.downloads.reports("case-tat-report"), - currentFilters + Object.keys(joinedFilters).length > 0 ? joinedFilters : {} ); }, }, From 25ee3a6a6547f28893f8deeedd9b634489e035ce Mon Sep 17 00:00:00 2001 From: Ally Wu Date: Mon, 8 Apr 2024 13:27:14 -0400 Subject: [PATCH 4/7] more fixups + change to JsonNode --- .../rest/DownloadRestController.java | 4 +- .../gsi/dimsum/util/reporting/Report.java | 16 +- .../dimsum/util/reporting/ReportSection.java | 13 +- .../util/reporting/reports/CaseTatReport.java | 146 ++++++++++-------- .../reporting/reports/DareInputSheet.java | 4 +- .../reporting/reports/FullDepthSummary.java | 4 +- .../reporting/reports/TglTrackingReport.java | 3 +- ts/data/case.ts | 12 +- 8 files changed, 116 insertions(+), 86 deletions(-) diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/controller/rest/DownloadRestController.java b/src/main/java/ca/on/oicr/gsi/dimsum/controller/rest/DownloadRestController.java index a72a2ded..75dd0ab3 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/controller/rest/DownloadRestController.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/controller/rest/DownloadRestController.java @@ -3,7 +3,6 @@ import java.io.IOException; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.Map; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; @@ -13,6 +12,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import com.fasterxml.jackson.databind.JsonNode; import ca.on.oicr.gsi.dimsum.controller.BadRequestException; import ca.on.oicr.gsi.dimsum.service.CaseService; import ca.on.oicr.gsi.dimsum.util.reporting.Report; @@ -31,7 +31,7 @@ public class DownloadRestController { @PostMapping("/reports/{reportName}") public HttpEntity generateReport(@PathVariable String reportName, - @RequestBody Map parameters, HttpServletResponse response) + @RequestBody JsonNode parameters, HttpServletResponse response) throws IOException { ReportFormat format = Report.getFormat(parameters); diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Report.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Report.java index 478dbab2..7cec35f7 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Report.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Report.java @@ -5,9 +5,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Map; -import java.util.Objects; import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import com.fasterxml.jackson.databind.JsonNode; import ca.on.oicr.gsi.dimsum.controller.BadRequestException; import ca.on.oicr.gsi.dimsum.service.CaseService; @@ -28,8 +27,8 @@ public String getTitle() { return title; } - public static ReportFormat getFormat(Map parameters) { - String format = parameters.get(PARAM_FORMAT); + public static ReportFormat getFormat(JsonNode parameters) { + String format = parameters.has(PARAM_FORMAT) ? parameters.get(PARAM_FORMAT).asText() : null; if (format == null) { return ReportFormat.EXCEL; } @@ -45,7 +44,7 @@ public static ReportFormat getFormat(Map parameters) { } } - public byte[] writeFile(CaseService caseService, Map parameters) + public byte[] writeFile(CaseService caseService, JsonNode parameters) throws IOException { ReportFormat format = getFormat(parameters); @@ -61,7 +60,7 @@ public byte[] writeFile(CaseService caseService, Map parameters) } } - private byte[] writeExcelFile(CaseService caseService, Map parameters) + private byte[] writeExcelFile(CaseService caseService, JsonNode parameters) throws IOException { XSSFWorkbook workbook = new XSSFWorkbook(); for (ReportSection section : sections) { @@ -74,9 +73,10 @@ private byte[] writeExcelFile(CaseService caseService, Map param } private byte[] writeDelimitedFile(CaseService caseService, String delimiter, - Map parameters) { + JsonNode parameters) { StringBuilder sb = new StringBuilder(); - boolean includeHeadings = Objects.equals("true", parameters.get(PARAM_HEADINGS)); + boolean includeHeadings = + parameters.has(PARAM_HEADINGS) && "true".equals(parameters.get(PARAM_HEADINGS).asText()); // This does not support multiple sections sections.get(0).createDelimitedText(sb, caseService, delimiter, includeHeadings, parameters); return sb.toString().getBytes(); diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/ReportSection.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/ReportSection.java index 00bea44d..ab210997 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/ReportSection.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/ReportSection.java @@ -2,7 +2,6 @@ import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -10,6 +9,7 @@ import org.apache.poi.ss.usermodel.Row; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import com.fasterxml.jackson.databind.JsonNode; import ca.on.oicr.gsi.dimsum.controller.BadRequestException; import ca.on.oicr.gsi.dimsum.service.CaseService; @@ -84,7 +84,7 @@ public List> getColumns() { } public void createExcelSheet(XSSFWorkbook workbook, CaseService caseService, - Map parameters) { + JsonNode parameters) { List objects = getData(caseService, parameters); XSSFSheet worksheet = workbook.createSheet(getTitle()); writeExcelSheet(worksheet, objects); @@ -93,7 +93,7 @@ public void createExcelSheet(XSSFWorkbook workbook, CaseService caseService, protected abstract void writeExcelSheet(XSSFSheet worksheet, List objects); public void createDelimitedText(StringBuilder sb, CaseService caseService, - String delimiter, boolean includeHeadings, Map parameters) { + String delimiter, boolean includeHeadings, JsonNode parameters) { List objects = getData(caseService, parameters); writeDelimitedText(sb, objects, delimiter, includeHeadings); } @@ -110,10 +110,11 @@ protected abstract void writeDelimitedText(StringBuilder sb, List objects, St * * @throws BadRequestException if there are invalid parameters */ - public abstract List getData(CaseService caseService, Map parameters); + public abstract List getData(CaseService caseService, JsonNode parameters); - protected static Set getParameterStringSet(Map parameters, String name) { - String value = parameters.get(name); + protected static Set getParameterStringSet(JsonNode parameters, String name) { + JsonNode valueNode = parameters.get(name); + String value = (valueNode != null) ? valueNode.asText() : null; if (value == null || value.isEmpty()) { return null; } diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java index a3a50d97..b4c9528e 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java @@ -5,11 +5,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; -import java.util.stream.Stream; +import com.fasterxml.jackson.databind.JsonNode; import ca.on.oicr.gsi.cardea.data.Case; import ca.on.oicr.gsi.cardea.data.CaseDeliverable; import ca.on.oicr.gsi.cardea.data.CaseRelease; @@ -17,6 +15,7 @@ import ca.on.oicr.gsi.cardea.data.Requisition; import ca.on.oicr.gsi.cardea.data.Sample; import ca.on.oicr.gsi.cardea.data.Test; +import ca.on.oicr.gsi.dimsum.controller.BadRequestException; import ca.on.oicr.gsi.dimsum.service.CaseService; import ca.on.oicr.gsi.dimsum.service.filtering.CaseFilter; import ca.on.oicr.gsi.dimsum.service.filtering.CaseFilterKey; @@ -59,65 +58,56 @@ public Test getTest() { Column.forString("Assay", x -> x.getCase().getAssayName()), Column.forString("Start Date", x -> x.getCase().getStartDate().format(DateTimeFormatter.ISO_LOCAL_DATE)), - Column.forString("Receipt Completed Date", - x -> Optional - .ofNullable(findLatestCompletionDate(x.getCase().getReceipts())) - .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse("")), + Column.forString("Receipt Completed", + x -> findLatestCompletionDate(x.getCase().getReceipts())), Column.forInteger("Receipt Days", x -> x.getCase().getReceiptDaysSpent()), Column.forString("Test", x -> x.getTest().getName()), Column.forString("Supplemental Only", x -> isSupplementalOnly(x.getTest(), x.getCase().getRequisition()) ? "Yes" : "No"), - Column.forString("Extraction Completed Date", - x -> Optional - .ofNullable(findLatestCompletionDate(x.getTest().getExtractions())) - .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse("")), + Column.forString("Extraction Completed", + x -> findLatestCompletionDate(x.getTest().getExtractions())), Column.forInteger("Extraction Days", x -> x.getTest().getExtractionDaysSpent()), - Column.forString("Library Prep Completed Date", - x -> Optional - .ofNullable(findLatestCompletionDate(x.getTest().getLibraryPreparations())) - .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse("")), + Column.forString("Library Prep Completed", + x -> findLatestCompletionDate(x.getTest().getLibraryPreparations())), Column.forInteger("Library Prep. Days", x -> x.getTest().getLibraryPreparationDaysSpent()), - Column.forString("Library Qual Completed Date", - x -> Optional - .ofNullable(findLatestCompletionDate(x.getTest().getLibraryQualifications())) - .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse("")), + Column.forString("Library Qual Completed", + x -> findLatestCompletionDate(x.getTest().getLibraryQualifications())), Column.forInteger("Library Qual. Days", x -> x.getTest().getLibraryQualificationDaysSpent()), - Column.forString("Full Depth Completed Date", - x -> Optional - .ofNullable(findLatestCompletionDate(x.getTest().getFullDepthSequencings())) - .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse("")), + Column.forString("Full-Depth Completed", + x -> findLatestCompletionDate(x.getTest().getFullDepthSequencings())), Column.forInteger("Full-Depth Days", x -> x.getTest().getFullDepthSequencingDaysSpent()), - Column.forString("Analysis Review Completed", x -> { - List dates = x.getCase().getDeliverables().stream() - .map(CaseDeliverable::getAnalysisReviewQcDate).collect(Collectors.toList()); - if (dates.contains(null)) { - return null; - } - return dates.stream().max(LocalDate::compareTo) - .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse(null); - }), + Column.forString("Analysis Review Completed", + x -> getMaxDateFromDeliverables(x.getCase(), + CaseDeliverable::getAnalysisReviewQcDate)), Column.forInteger("Analysis Review Days", x -> x.getCase().getAnalysisReviewDaysSpent()), - Column.forString("Release Approval Completed", x -> { + Column.forString("Release Approval Completed", + x -> getMaxDateFromDeliverables(x.getCase(), + CaseDeliverable::getReleaseApprovalQcDate)), + Column.forString("Release Completed", x -> { + if (!x.getCase().isStopped()) { + return getCompletionDate(x.getCase()); + } List dates = x.getCase().getDeliverables().stream() - .map(CaseDeliverable::getReleaseApprovalQcDate).collect(Collectors.toList()); + .flatMap(deliverable -> deliverable.getReleases().stream()) + .map(CaseRelease::getQcDate) + .collect(Collectors.toList()); if (dates.contains(null)) { return null; } return dates.stream().max(LocalDate::compareTo) .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse(null); }), - Column.forInteger("Release Approval Days", - x -> x.getCase().getReleaseApprovalDaysSpent()), + Column.forInteger("Release Days", x -> x.getCase().getReleaseDaysSpent()), Column.forString("Completion Date", x -> getCompletionDate(x.getCase())), Column.forInteger("Total Days", x -> x.getCase().getCaseDaysSpent()))) { @Override - public List getData(CaseService caseService, Map parameters) { + public List getData(CaseService caseService, JsonNode parameters) { List filters = convertParametersToFilters(parameters); return caseService.getCaseStream(filters) .flatMap(kase -> kase.getTests().stream().map(test -> new RowData(kase, test))) @@ -139,44 +129,74 @@ private static String getSortedProjectNameOrPipeline(Case kase, .collect(Collectors.joining(", ")); } - private static List convertParametersToFilters(Map parameters) { + private static List convertParametersToFilters(JsonNode parameters) { List filters = new ArrayList<>(); - parameters.forEach((key, value) -> { - CaseFilterKey filterKey = CaseFilterKey.valueOf(key.toUpperCase()); - CaseFilter filter = new CaseFilter(filterKey, value); - filters.add(filter); + parameters.fields().forEachRemaining(entry -> { + try { + CaseFilterKey filterKey = CaseFilterKey.valueOf(entry.getKey().toUpperCase()); + String[] values = entry.getValue().asText().split(","); + for (String value : values) { + CaseFilter filter = new CaseFilter(filterKey, value.trim()); + filters.add(filter); + } + } catch (IllegalArgumentException e) { + throw new BadRequestException( + "Invalid filter key: " + entry.getKey() + ". " + e.getMessage()); + } }); return filters; } private static boolean isSupplementalOnly(Test test, Requisition requisition) { - if (test == null || test.getExtractions().isEmpty()) { + if (test.getExtractions().isEmpty() + || test.getLibraryPreparations().isEmpty() + || test.getLibraryQualifications().isEmpty() + || test.getFullDepthSequencings().isEmpty()) { return false; } return test.getExtractions().stream() - .allMatch(sample -> !sample.getRequisitionId() - .equals(requisition.getId())); + .allMatch(sample -> !sample.getRequisitionId().equals(requisition.getId())) + && test.getLibraryPreparations().stream() + .allMatch(sample -> !sample.getRequisitionId().equals(requisition.getId())) + && test.getLibraryQualifications().stream() + .allMatch(sample -> !sample.getRequisitionId().equals(requisition.getId())) + && test.getFullDepthSequencings().stream() + .allMatch(sample -> !sample.getRequisitionId().equals(requisition.getId())); } - private static LocalDate findLatestCompletionDate(List samples) { - return samples.stream() - .filter(SampleUtils::isPassed) - .map(sample -> { - if (sample.getRun() != null) { - LocalDate sampleReviewDate = sample.getDataReviewDate(); - LocalDate runReviewDate = sample.getRun().getDataReviewDate(); - if (sampleReviewDate == null || runReviewDate == null) { - return null; - } - return Stream.of(sampleReviewDate, runReviewDate) - .max(LocalDate::compareTo) - .orElse(null); - } else { - return sample.getQcDate(); + private static String findLatestCompletionDate(List samples) { + LocalDate latestDate = null; + for (Sample sample : samples) { + if (SampleUtils.isPassed(sample)) { + LocalDate dateToCompare = null; + if (sample.getRun() != null) { + LocalDate sampleReviewDate = sample.getDataReviewDate(); + LocalDate runReviewDate = sample.getRun().getDataReviewDate(); + if (sampleReviewDate != null && runReviewDate != null) { + dateToCompare = + runReviewDate.isAfter(sampleReviewDate) ? runReviewDate : sampleReviewDate; } - }) - .max(LocalDate::compareTo) - .orElse(null); + } else { + dateToCompare = sample.getQcDate(); + } + if (dateToCompare != null && (latestDate == null || dateToCompare.isAfter(latestDate))) { + latestDate = dateToCompare; + } + } + } + return latestDate != null ? latestDate.format(DateTimeFormatter.ISO_LOCAL_DATE) : null; + } + + private static String getMaxDateFromDeliverables(Case x, + Function dateExtractor) { + List dates = x.getDeliverables().stream() + .map(dateExtractor) + .collect(Collectors.toList()); + if (dates.contains(null)) { + return null; + } + return dates.stream().max(LocalDate::compareTo) + .map(date -> date.format(DateTimeFormatter.ISO_LOCAL_DATE)).orElse(null); } private static String getCompletionDate(Case x) { diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/DareInputSheet.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/DareInputSheet.java index dac228f1..8e8effc1 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/DareInputSheet.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/DareInputSheet.java @@ -2,8 +2,8 @@ import java.util.Arrays; import java.util.List; -import java.util.Map; import java.util.Set; +import com.fasterxml.jackson.databind.JsonNode; import ca.on.oicr.gsi.dimsum.controller.BadRequestException; import ca.on.oicr.gsi.dimsum.service.CaseService; import ca.on.oicr.gsi.dimsum.util.reporting.Column; @@ -21,7 +21,7 @@ public class DareInputSheet extends Report { @Override public List getData(CaseService caseService, - Map parameters) { + JsonNode parameters) { Set caseIds = getParameterStringSet(parameters, "caseIds"); if (caseIds == null) { throw new BadRequestException("caseIds parameter missing"); diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/FullDepthSummary.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/FullDepthSummary.java index f26a1bb1..c0fba44a 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/FullDepthSummary.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/FullDepthSummary.java @@ -2,8 +2,8 @@ import java.util.Arrays; import java.util.List; -import java.util.Map; import java.util.Set; +import com.fasterxml.jackson.databind.JsonNode; import ca.on.oicr.gsi.dimsum.controller.BadRequestException; import ca.on.oicr.gsi.dimsum.service.CaseService; import ca.on.oicr.gsi.dimsum.util.reporting.Column; @@ -29,7 +29,7 @@ public class FullDepthSummary extends Report { @Override public List getData(CaseService caseService, - Map parameters) { + JsonNode parameters) { Set caseIds = getParameterStringSet(parameters, "caseIds"); if (caseIds == null) { throw new BadRequestException("caseIds parameter missing"); diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/TglTrackingReport.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/TglTrackingReport.java index 35ff2acf..9b795b06 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/TglTrackingReport.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/TglTrackingReport.java @@ -9,6 +9,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; +import com.fasterxml.jackson.databind.JsonNode; import ca.on.oicr.gsi.cardea.data.Assay; import ca.on.oicr.gsi.cardea.data.Case; import ca.on.oicr.gsi.cardea.data.Metric; @@ -97,7 +98,7 @@ public Assay getAssay() { @Override public List getData(CaseService caseService, - Map parameters) { + JsonNode parameters) { Set projectNames = getParameterStringSet(parameters, "projects"); List filters = null; if (projectNames != null) { diff --git a/ts/data/case.ts b/ts/data/case.ts index 06c27f66..8bba1872 100644 --- a/ts/data/case.ts +++ b/ts/data/case.ts @@ -191,14 +191,22 @@ export const caseDefinition: TableDefinition = { legendAction, { title: "TAT Report", - handler: (filters: { key: string; value: string }[]) => { + handler: ( + filters: { key: string; value: string }[], + baseFilter: { key: string; value: string } | undefined + ) => { const currentFilters: { [key: string]: string[] } = {}; + + if (baseFilter !== undefined) { + currentFilters[baseFilter.key] = baseFilter.value.split(","); + } + for (const filter of filters) { if (filter.value !== undefined && filter.value !== null) { if (!currentFilters[filter.key]) { currentFilters[filter.key] = []; } - currentFilters[filter.key].push(filter.value); + currentFilters[filter.key].push(...filter.value.split(",")); } } const joinedFilters: { [key: string]: string } = {}; From 1828b048d7cb2c6d17618d0bab0d46a1022ee849 Mon Sep 17 00:00:00 2001 From: Ally Wu Date: Wed, 10 Apr 2024 14:17:32 -0400 Subject: [PATCH 5/7] more fixups --- .../gsi/dimsum/util/reporting/Report.java | 2 +- .../util/reporting/reports/CaseTatReport.java | 41 +++++++++---------- ts/data/case.ts | 23 +++-------- 3 files changed, 26 insertions(+), 40 deletions(-) diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Report.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Report.java index 7cec35f7..1568cd19 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Report.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/Report.java @@ -76,7 +76,7 @@ private byte[] writeDelimitedFile(CaseService caseService, String delimiter, JsonNode parameters) { StringBuilder sb = new StringBuilder(); boolean includeHeadings = - parameters.has(PARAM_HEADINGS) && "true".equals(parameters.get(PARAM_HEADINGS).asText()); + parameters.has(PARAM_HEADINGS) && parameters.get(PARAM_HEADINGS).asBoolean(); // This does not support multiple sections sections.get(0).createDelimitedText(sb, caseService, delimiter, includeHeadings, parameters); return sb.toString().getBytes(); diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java index b4c9528e..f2b30b67 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; import com.fasterxml.jackson.databind.JsonNode; @@ -15,10 +16,11 @@ import ca.on.oicr.gsi.cardea.data.Requisition; import ca.on.oicr.gsi.cardea.data.Sample; import ca.on.oicr.gsi.cardea.data.Test; -import ca.on.oicr.gsi.dimsum.controller.BadRequestException; +import ca.on.oicr.gsi.dimsum.controller.mvc.MvcUtils; +import ca.on.oicr.gsi.dimsum.controller.rest.request.DataQuery; +import ca.on.oicr.gsi.dimsum.controller.rest.request.KeyValuePair; import ca.on.oicr.gsi.dimsum.service.CaseService; import ca.on.oicr.gsi.dimsum.service.filtering.CaseFilter; -import ca.on.oicr.gsi.dimsum.service.filtering.CaseFilterKey; import ca.on.oicr.gsi.dimsum.util.SampleUtils; import ca.on.oicr.gsi.dimsum.util.reporting.Column; import ca.on.oicr.gsi.dimsum.util.reporting.Report; @@ -130,38 +132,33 @@ private static String getSortedProjectNameOrPipeline(Case kase, } private static List convertParametersToFilters(JsonNode parameters) { - List filters = new ArrayList<>(); + DataQuery dataQuery = new DataQuery(); + List kvpFilters = new ArrayList<>(); parameters.fields().forEachRemaining(entry -> { - try { - CaseFilterKey filterKey = CaseFilterKey.valueOf(entry.getKey().toUpperCase()); - String[] values = entry.getValue().asText().split(","); - for (String value : values) { - CaseFilter filter = new CaseFilter(filterKey, value.trim()); - filters.add(filter); - } - } catch (IllegalArgumentException e) { - throw new BadRequestException( - "Invalid filter key: " + entry.getKey() + ". " + e.getMessage()); - } + String key = entry.getKey(); + String value = entry.getValue().asText(); + kvpFilters.add(new KeyValuePair(key, value)); }); - return filters; + dataQuery.setFilters(kvpFilters); + List caseFilters = MvcUtils.parseCaseFilters(dataQuery); + return caseFilters; } private static boolean isSupplementalOnly(Test test, Requisition requisition) { if (test.getExtractions().isEmpty() - || test.getLibraryPreparations().isEmpty() - || test.getLibraryQualifications().isEmpty() - || test.getFullDepthSequencings().isEmpty()) { + && test.getLibraryPreparations().isEmpty() + && test.getLibraryQualifications().isEmpty() + && test.getFullDepthSequencings().isEmpty()) { return false; } return test.getExtractions().stream() - .allMatch(sample -> !sample.getRequisitionId().equals(requisition.getId())) + .allMatch(sample -> !Objects.equals(sample.getRequisitionId(), requisition.getId())) && test.getLibraryPreparations().stream() - .allMatch(sample -> !sample.getRequisitionId().equals(requisition.getId())) + .allMatch(sample -> !Objects.equals(sample.getRequisitionId(), requisition.getId())) && test.getLibraryQualifications().stream() - .allMatch(sample -> !sample.getRequisitionId().equals(requisition.getId())) + .allMatch(sample -> !Objects.equals(sample.getRequisitionId(), requisition.getId())) && test.getFullDepthSequencings().stream() - .allMatch(sample -> !sample.getRequisitionId().equals(requisition.getId())); + .allMatch(sample -> !Objects.equals(sample.getRequisitionId(), requisition.getId())); } private static String findLatestCompletionDate(List samples) { diff --git a/ts/data/case.ts b/ts/data/case.ts index 8bba1872..69c6f320 100644 --- a/ts/data/case.ts +++ b/ts/data/case.ts @@ -195,27 +195,16 @@ export const caseDefinition: TableDefinition = { filters: { key: string; value: string }[], baseFilter: { key: string; value: string } | undefined ) => { - const currentFilters: { [key: string]: string[] } = {}; - + const joinedFiltersObj: { [key: string]: any } = {}; if (baseFilter !== undefined) { - currentFilters[baseFilter.key] = baseFilter.value.split(","); - } - - for (const filter of filters) { - if (filter.value !== undefined && filter.value !== null) { - if (!currentFilters[filter.key]) { - currentFilters[filter.key] = []; - } - currentFilters[filter.key].push(...filter.value.split(",")); - } - } - const joinedFilters: { [key: string]: string } = {}; - for (const key in currentFilters) { - joinedFilters[key] = currentFilters[key].join(","); + joinedFiltersObj[baseFilter.key] = baseFilter.value; } + filters.forEach((filter) => { + joinedFiltersObj[filter.key] = filter.value; + }); postDownload( urls.rest.downloads.reports("case-tat-report"), - Object.keys(joinedFilters).length > 0 ? joinedFilters : {} + joinedFiltersObj ); }, }, From bcd15702e5819a577b351e3718d5dd5781290845 Mon Sep 17 00:00:00 2001 From: Ally Wu Date: Wed, 10 Apr 2024 15:11:52 -0400 Subject: [PATCH 6/7] filter fix --- .../util/reporting/reports/CaseTatReport.java | 14 +++++++++----- ts/data/case.ts | 9 +++------ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java index f2b30b67..dff79ff4 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java @@ -134,11 +134,15 @@ private static String getSortedProjectNameOrPipeline(Case kase, private static List convertParametersToFilters(JsonNode parameters) { DataQuery dataQuery = new DataQuery(); List kvpFilters = new ArrayList<>(); - parameters.fields().forEachRemaining(entry -> { - String key = entry.getKey(); - String value = entry.getValue().asText(); - kvpFilters.add(new KeyValuePair(key, value)); - }); + + if (parameters.isArray()) { + for (JsonNode parameter : parameters) { + String key = parameter.get("key").asText(); + String value = parameter.get("value").asText(); + kvpFilters.add(new KeyValuePair(key, value)); + } + } + dataQuery.setFilters(kvpFilters); List caseFilters = MvcUtils.parseCaseFilters(dataQuery); return caseFilters; diff --git a/ts/data/case.ts b/ts/data/case.ts index 69c6f320..0bf9e770 100644 --- a/ts/data/case.ts +++ b/ts/data/case.ts @@ -195,16 +195,13 @@ export const caseDefinition: TableDefinition = { filters: { key: string; value: string }[], baseFilter: { key: string; value: string } | undefined ) => { - const joinedFiltersObj: { [key: string]: any } = {}; + const joinedFilters = [...filters]; if (baseFilter !== undefined) { - joinedFiltersObj[baseFilter.key] = baseFilter.value; + joinedFilters.push(baseFilter); } - filters.forEach((filter) => { - joinedFiltersObj[filter.key] = filter.value; - }); postDownload( urls.rest.downloads.reports("case-tat-report"), - joinedFiltersObj + joinedFilters ); }, }, From c1e2babf60528f8121d545680bddc77f983dcb9f Mon Sep 17 00:00:00 2001 From: Ally Wu Date: Wed, 10 Apr 2024 15:58:27 -0400 Subject: [PATCH 7/7] add release approval days --- .../oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java index dff79ff4..37734396 100644 --- a/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java +++ b/src/main/java/ca/on/oicr/gsi/dimsum/util/reporting/reports/CaseTatReport.java @@ -90,6 +90,8 @@ public Test getTest() { Column.forString("Release Approval Completed", x -> getMaxDateFromDeliverables(x.getCase(), CaseDeliverable::getReleaseApprovalQcDate)), + Column.forInteger("Release Approval Days", + x -> x.getCase().getReleaseApprovalDaysSpent()), Column.forString("Release Completed", x -> { if (!x.getCase().isStopped()) { return getCompletionDate(x.getCase());