From e35a24c4f226653fa7e4f4b285d45e4363a4ad74 Mon Sep 17 00:00:00 2001 From: Graham McNeill Date: Tue, 3 Dec 2024 20:23:03 +0000 Subject: [PATCH] [Platform] Add QC warnings to study page (#588) * DetailPopover component * polish sumstats and warnings * cleanup popover * not available --- .../pages/CredibleSetPage/ProfileHeader.tsx | 149 +++++++----------- packages/ui/src/components/DetailPopover.tsx | 67 ++++++++ packages/ui/src/index.tsx | 1 + 3 files changed, 127 insertions(+), 90 deletions(-) create mode 100644 packages/ui/src/components/DetailPopover.tsx diff --git a/apps/platform/src/pages/CredibleSetPage/ProfileHeader.tsx b/apps/platform/src/pages/CredibleSetPage/ProfileHeader.tsx index 98fdd6d39..a0132e87b 100644 --- a/apps/platform/src/pages/CredibleSetPage/ProfileHeader.tsx +++ b/apps/platform/src/pages/CredibleSetPage/ProfileHeader.tsx @@ -1,4 +1,4 @@ -import { Fragment, useState } from "react"; +import { Fragment } from "react"; import { usePlatformApi, Field, @@ -9,14 +9,13 @@ import { PublicationsDrawer, ClinvarStars, LabelChip, + DetailPopover, } from "ui"; -import { Box, Typography, Popover } from "@mui/material"; +import { Box, Typography } from "@mui/material"; import CREDIBLE_SET_PROFILE_HEADER_FRAGMENT from "./ProfileHeader.gql"; import { getStudyCategory } from "sections/src/utils/getStudyCategory"; import { epmcUrl } from "../../utils/urls"; import { credsetConfidenceMap, poulationMap } from "../../constants"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faCaretDown, faTriangleExclamation } from "@fortawesome/free-solid-svg-icons"; import { v1 } from "uuid"; type ProfileHeaderProps = { @@ -44,72 +43,34 @@ const dicSummary = [ }, ]; -function SummaryStatisticsField({ sumstatQCValues }: any) { - const [anchorEl, setAnchorEl] = useState(null); - if (!sumstatQCValues) return null; - - const handleClick = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget); - }; - - const handleClose = () => { - setAnchorEl(null); - }; - - const open = Boolean(anchorEl); - const id = open ? "simple-popover" : undefined; - +function SummaryStatsTable({ sumstatQCValues }: any) { return ( - - - Available + <> + + Harmonised summary statistics - - - - - Harmonised summary statistics - - - - {dicSummary.map((sumstat: any) => { - const summStatValue = sumstatQCValues.find( - (v: any) => v.QCCheckName === sumstat.id - ).QCCheckValue; - return ( - - - - {summStatValue} - - - ); - })} - -
- - {sumstat.label} - -
-
-
-
+ + + {dicSummary.map((sumstat: any) => { + const summStatValue = sumstatQCValues.find( + (v: any) => v.QCCheckName === sumstat.id + ).QCCheckValue; + return ( + + + + {summStatValue} + + + ); + })} + +
+ + {sumstat.label} + +
+ ); } @@ -128,7 +89,7 @@ function ProfileHeader({ variantId }: ProfileHeaderProps) { const standardError = leadVariant?.standardError ?? credibleSet?.standardError; const { pValueMantissa, pValueExponent } = typeof leadVariant?.pValueMantissa === "number" && - typeof leadVariant?.pValueExponent === "number" + typeof leadVariant?.pValueExponent === "number" ? leadVariant : credibleSet ?? {}; @@ -265,7 +226,24 @@ function ProfileHeader({ variantId }: ProfileHeaderProps) { > {credibleSet?.purityMinR2?.toPrecision(3)} - + {credibleSet?.qualityControls?.length > 0 && + + +
    + {credibleSet.qualityControls.map(warning => ( +
  • {warning}
  • + ))} +
+
+
+ } + @@ -342,14 +320,16 @@ function ProfileHeader({ variantId }: ProfileHeaderProps) { {study?.analysisFlags ? study.analysisFlags : "Not Available"} )} - {study?.hasSumstats && ( - - - - )} + + {!study?.hasSumstats + ? "Not Available" + : study?.sumstatQCValues + ? + + + : "Available" + } + {study?.nSamples.toLocaleString()} @@ -364,20 +344,9 @@ function ProfileHeader({ variantId }: ProfileHeaderProps) { tooltip={`LD reference population: ${poulationMap[ldPopulation]}`} /> ))} - {/* Quality controls */} - {study?.qualityControls?.length > 0 && ( - - } - value={study?.qualityControls.length + " issue"} - tooltip={study?.qualityControls.join("; ")} - color="orange" - /> - - )} - + ); } diff --git a/packages/ui/src/components/DetailPopover.tsx b/packages/ui/src/components/DetailPopover.tsx new file mode 100644 index 000000000..562da1186 --- /dev/null +++ b/packages/ui/src/components/DetailPopover.tsx @@ -0,0 +1,67 @@ +import { ReactNode, useState } from "react"; +import { Typography, Popover, Box } from "@mui/material"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faCaretDown, faCaretRight } from "@fortawesome/free-solid-svg-icons"; + +type DetailPopoverProps = { + title: string; + children: ReactNode; + popoverId?: string; +}; + +export default function DetailPopover({ + title, + children, + popoverId = "simple-popover", +}: DetailPopoverProps) { + + const [anchorEl, setAnchorEl] = useState(null); + + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + + const open = Boolean(anchorEl); + const id = open ? popoverId : undefined; + + return ( + <> + + {title} + {" "} + + + + {children} + + + ); +} \ No newline at end of file diff --git a/packages/ui/src/index.tsx b/packages/ui/src/index.tsx index 818efb463..c0e9e419b 100644 --- a/packages/ui/src/index.tsx +++ b/packages/ui/src/index.tsx @@ -27,6 +27,7 @@ export { default as PrivateRoute } from "./components/PrivateRoute"; export { default as EllsWrapper } from "./components/EllsWrapper"; export { default as ErrorBoundary } from "./components/ErrorBoundary"; export { default as GlobalSearch } from "./components/GlobalSearch/GlobalSearch"; +export { default as DetailPopover } from "./components/DetailPopover"; export { default as PrivateWrapper } from "./components/PrivateWrapper"; export { default as NavBar } from "./components/NavBar";