Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CRDCDH-661 QC Results Filters #254

Merged
merged 17 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/components/DataSubmissions/GenericTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ export type FetchListing<T> = {

export type TableMethods = {
refresh: () => void;
setPage: (page: number) => void;
};

type Props<T> = {
Expand Down Expand Up @@ -193,6 +194,9 @@ const GenericTable = <T,>({
useImperativeHandle(ref, () => ({
refresh: () => {
fetchData(true);
},
setPage: (newPage: number) => {
setPage(newPage);
}
}));

Expand Down
171 changes: 164 additions & 7 deletions src/content/dataSubmissions/QualityControl.tsx
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -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<QCResult>[] = [
{
label: "Type",
Expand Down Expand Up @@ -100,8 +159,9 @@ const columns: Column<QCResult>[] = [
},
];

const QualityControl = () => {
const QualityControl: FC = () => {
const { submissionId } = useParams();
const { watch, control } = useForm<FilterForm>();

const [loading, setLoading] = useState<boolean>(false);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
Expand All @@ -116,7 +176,26 @@ const QualityControl = () => {
const [submissionQCResults] = useLazyQuery<submissionQCResultsResp>(SUBMISSION_QC_RESULTS, {
variables: { id: submissionId },
context: { clientName: 'backend' },
fetchPolicy: 'no-cache'
fetchPolicy: 'cache-and-network',
});

const { data: batchData } = useQuery<ListBatchesResp>(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<ListNodeTypesResp>(LIST_NODE_TYPES, {
variables: { _id: submissionId, },
context: { clientName: 'backend' },
fetchPolicy: 'cache-and-network',
});

const handleFetchQCResults = async (fetchListing: FetchListing<QCResult>, force: boolean) => {
Expand All @@ -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'
Expand All @@ -166,8 +251,80 @@ const QualityControl = () => {
handleOpenErrorDialog
}), [handleOpenErrorDialog]);

useEffect(() => {
handleFetchQCResults(null, true);
tableRef.current?.setPage(0);
}, [watch("nodeType"), watch("batchID"), watch("severity")]);

return (
<>
<StyledFilterContainer>
<StyledInlineLabel htmlFor="nodeType-filter">Node Type</StyledInlineLabel>
<StyledFormControl>
<Controller
name="nodeType"
control={control}
render={({ field }) => (
<StyledSelect
{...field}
defaultValue="All"
value={field.value || "All"}
MenuProps={{ disablePortal: true }}
inputProps={{ id: "nodeType-filter" }}
>
<MenuItem value="All">All</MenuItem>
{nodeTypes?.listSubmissionNodeTypes?.map((nodeType) => (
<MenuItem key={nodeType} value={nodeType}>{nodeType}</MenuItem>
))}
</StyledSelect>
)}
/>
</StyledFormControl>
<StyledInlineLabel htmlFor="batchID-filter">Batch ID</StyledInlineLabel>
<StyledFormControl>
<Controller
name="batchID"
control={control}
render={({ field }) => (
<StyledSelect
{...field}
defaultValue="All"
value={field.value || "All"}
MenuProps={{ disablePortal: true }}
inputProps={{ id: "batchID-filter" }}
>
<MenuItem value="All">All</MenuItem>
{batchData?.listBatches?.batches?.map((batch) => (
<MenuItem key={batch._id} value={batch._id}>
{batch.displayID}
{` (${FormatDate(batch.createdAt, "MM/DD/YYYY")})`}
</MenuItem>
))}
</StyledSelect>
)}
/>
</StyledFormControl>
<StyledInlineLabel htmlFor="severity-filter">Severity</StyledInlineLabel>
<StyledFormControl>
<Controller
name="severity"
control={control}
render={({ field }) => (
<StyledSelect
{...field}
defaultValue="All"
value={field.value || "All"}
MenuProps={{ disablePortal: true }}
inputProps={{ id: "severity-filter" }}
>
<MenuItem value="All">All</MenuItem>
<MenuItem value="Error">Error</MenuItem>
<MenuItem value="Warning">Warning</MenuItem>
</StyledSelect>
)}
/>
</StyledFormControl>
</StyledFilterContainer>
<QCResultsContext.Provider value={providerValue}>
<GenericTable
ref={tableRef}
Expand Down
3 changes: 3 additions & 0 deletions src/graphql/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ export type { Response as submissionQCResultsResp } from "./submissionQCResults"
export { mutation as VALIDATE_SUBMISSION } from "./validateSubmission";
export type { Response as ValidateSubmissionResp } from "./validateSubmission";

export { query as LIST_NODE_TYPES } from "./listSubmissionNodeTypes";
export type { Response as ListNodeTypesResp } from "./listSubmissionNodeTypes";

// User Profile
export { query as GET_USER } from "./getUser";
export type { Response as GetUserResp } from "./getUser";
Expand Down
57 changes: 37 additions & 20 deletions src/graphql/listBatches.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,45 @@
import gql from 'graphql-tag';

// The base Batch model used for all listBatches queries
const BaseBatchFragment = gql`
fragment BaseBatchFragment on Batch {
_id
displayID
createdAt
updatedAt
}
`;

// The extended batch model which includes all fields
const FullBatchFragment = gql`
fragment BatchFragment on Batch {
submissionID
type
metadataIntention
fileCount
files {
nodeType
filePrefix
fileName
size
status
errors
createdAt
updatedAt
}
status
errors
}
`;

export const query = gql`
query listBatches(
$submissionID: ID!
$first: Int
$offset: Int
$orderBy: String
$sortDirection: String
$partial: Boolean = false
) {
listBatches(
submissionID: $submissionID
Expand All @@ -17,29 +50,13 @@ export const query = gql`
) {
total
batches {
_id
displayID
submissionID
type
metadataIntention
fileCount
files {
nodeType
filePrefix
fileName
size
status
errors
createdAt
updatedAt
}
status
errors
createdAt
updatedAt
...BaseBatchFragment
...BatchFragment @skip(if: $partial)
}
}
}
${FullBatchFragment}
${BaseBatchFragment}
`;

export type Response = {
Expand Down
11 changes: 11 additions & 0 deletions src/graphql/listSubmissionNodeTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import gql from "graphql-tag";

export const query = gql`
query listSubmissionNodeTypes($_id: ID!) {
listSubmissionNodeTypes(_id: $_id)
}
`;

export type Response = {
listSubmissionNodeTypes: string[];
};
6 changes: 6 additions & 0 deletions src/graphql/submissionQCResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ import gql from "graphql-tag";
export const query = gql`
query submissionQCResults(
$id: ID!
$nodeTypes: [String]
$batchIDs: [ID]
$severities: String
$first: Int
$offset: Int
$orderBy: String
$sortDirection: String
) {
submissionQCResults(
_id: $id
nodeTypes: $nodeTypes
batchIDs: $batchIDs
severities: $severities
first: $first
offset: $offset
orderBy: $orderBy
Expand Down