diff --git a/src/components/DataSubmissions/GenericTable.tsx b/src/components/DataSubmissions/GenericTable.tsx index 1a62cd7d..17170e56 100644 --- a/src/components/DataSubmissions/GenericTable.tsx +++ b/src/components/DataSubmissions/GenericTable.tsx @@ -142,6 +142,7 @@ export type FetchListing = { export type TableMethods = { refresh: () => void; + setPage: (page: number, forceRefetch?: boolean) => void; }; type Props = { @@ -193,6 +194,12 @@ const GenericTable = ({ useImperativeHandle(ref, () => ({ refresh: () => { fetchData(true); + }, + setPage: (newPage: number, forceRefetch = false) => { + setPage(newPage); + if (forceRefetch) { + fetchData(true); + } } })); diff --git a/src/content/dataSubmissions/QualityControl.tsx b/src/content/dataSubmissions/QualityControl.tsx index 60455c49..dd4bf41d 100644 --- a/src/content/dataSubmissions/QualityControl.tsx +++ b/src/content/dataSubmissions/QualityControl.tsx @@ -1,14 +1,21 @@ -import { useMemo, useRef, useState } from "react"; -import { useLazyQuery } from "@apollo/client"; +import { FC, useEffect, useMemo, useRef, useState } from "react"; +import { useLazyQuery, useQuery } from "@apollo/client"; import { useParams } from "react-router-dom"; import { isEqual } from "lodash"; -import { Box, Button, styled } from "@mui/material"; -import { SUBMISSION_QC_RESULTS, submissionQCResultsResp } from "../../graphql"; +import { Box, Button, FormControl, MenuItem, Select, styled } from "@mui/material"; +import { Controller, useForm } from 'react-hook-form'; +import { LIST_BATCHES, LIST_NODE_TYPES, ListBatchesResp, ListNodeTypesResp, SUBMISSION_QC_RESULTS, submissionQCResultsResp } from "../../graphql"; import GenericTable, { Column, FetchListing, TableMethods } from "../../components/DataSubmissions/GenericTable"; import { FormatDate } from "../../utils"; import ErrorDialog from "./ErrorDialog"; import QCResultsContext from "./Contexts/QCResultsContext"; +type FilterForm = { + nodeType: string | "All"; + batchID: number | "All"; + severity: QCResult["severity"] | "All"; +}; + const StyledErrorDetailsButton = styled(Button)({ display: "inline", color: "#0D78C5", @@ -42,6 +49,58 @@ const StyledBreakAll = styled(Box)({ wordBreak: "break-all" }); +const StyledFilterContainer = styled(Box)({ + display: "flex", + alignItems: "center", + justifyContent: "flex-start", + marginBottom: "19px", + paddingLeft: "24px", +}); + +const StyledFormControl = styled(FormControl)({ + margin: "10px", + marginRight: "15px", + minWidth: "250px", +}); + +const StyledInlineLabel = styled('label')({ + padding: "0 10px", + fontWeight: "700" +}); + +const baseTextFieldStyles = { + borderRadius: "8px", + "& .MuiInputBase-input": { + fontWeight: 400, + fontSize: "16px", + fontFamily: "'Nunito', 'Rubik', sans-serif", + padding: "10px", + height: "20px", + }, + "& .MuiOutlinedInput-notchedOutline": { + borderColor: "#6B7294", + }, + "&.Mui-focused .MuiOutlinedInput-notchedOutline": { + border: "1px solid #209D7D", + boxShadow: "2px 2px 4px 0px rgba(38, 184, 147, 0.10), -1px -1px 6px 0px rgba(38, 184, 147, 0.20)", + }, + "& .Mui-disabled": { + cursor: "not-allowed", + }, + "& .MuiList-root": { + padding: "0 !important", + }, + "& .MuiMenuItem-root.Mui-selected": { + background: "#3E7E6D !important", + color: "#FFFFFF !important", + }, + "& .MuiMenuItem-root:hover": { + background: "#D5EDE5", + }, +}; + +const StyledSelect = styled(Select)(baseTextFieldStyles); + const columns: Column[] = [ { label: "Type", @@ -100,8 +159,9 @@ const columns: Column[] = [ }, ]; -const QualityControl = () => { +const QualityControl: FC = () => { const { submissionId } = useParams(); + const { watch, control } = useForm(); const [loading, setLoading] = useState(false); // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -116,7 +176,26 @@ const QualityControl = () => { const [submissionQCResults] = useLazyQuery(SUBMISSION_QC_RESULTS, { variables: { id: submissionId }, context: { clientName: 'backend' }, - fetchPolicy: 'no-cache' + fetchPolicy: 'cache-and-network', + }); + + const { data: batchData } = useQuery(LIST_BATCHES, { + variables: { + submissionID: submissionId, + first: -1, + offset: 0, + partial: true, + orderBy: "displayID", + sortDirection: "asc", + }, + context: { clientName: 'backend' }, + fetchPolicy: 'cache-and-network', + }); + + const { data: nodeTypes } = useQuery(LIST_NODE_TYPES, { + variables: { _id: submissionId, }, + context: { clientName: 'backend' }, + fetchPolicy: 'cache-and-network', }); const handleFetchQCResults = async (fetchListing: FetchListing, force: boolean) => { @@ -133,13 +212,19 @@ const QualityControl = () => { try { setLoading(true); + + const nodeType = watch("nodeType"); + const batchID = watch("batchID"); const { data: d, error } = await submissionQCResults({ variables: { submissionID: submissionId, first, offset, sortDirection, - orderBy + orderBy, + nodeTypes: !nodeType || nodeType === "All" ? undefined : [watch("nodeType")], + batchIDs: !batchID || batchID === "All" ? undefined : [watch("batchID")], + severities: watch("severity") || "All", }, context: { clientName: 'backend' }, fetchPolicy: 'no-cache' @@ -166,8 +251,79 @@ const QualityControl = () => { handleOpenErrorDialog }), [handleOpenErrorDialog]); + useEffect(() => { + tableRef.current?.setPage(0, true); + }, [watch("nodeType"), watch("batchID"), watch("severity")]); + return ( <> + + Node Type + + ( + + All + {nodeTypes?.listSubmissionNodeTypes?.map((nodeType) => ( + {nodeType} + ))} + + )} + /> + + Batch ID + + ( + + All + {batchData?.listBatches?.batches?.map((batch) => ( + + {batch.displayID} + {` (${FormatDate(batch.createdAt, "MM/DD/YYYY")})`} + + ))} + + )} + /> + + Severity + + ( + + All + Error + Warning + + )} + /> + +