diff --git a/apps/platform/src/pages/CredibleSetPage/ProfileHeader.tsx b/apps/platform/src/pages/CredibleSetPage/ProfileHeader.tsx index ad4091c35..f92061eaf 100644 --- a/apps/platform/src/pages/CredibleSetPage/ProfileHeader.tsx +++ b/apps/platform/src/pages/CredibleSetPage/ProfileHeader.tsx @@ -12,6 +12,7 @@ import { DetailPopover, SummaryStatsTable, DisplaySampleSize, + StudyPublication, } from "ui"; import { Box, Typography } from "@mui/material"; import CREDIBLE_SET_PROFILE_HEADER_FRAGMENT from "./ProfileHeader.gql"; @@ -248,8 +249,11 @@ function ProfileHeader() { )} {study?.publicationFirstAuthor && ( - {study?.publicationFirstAuthor} et al. {study?.publicationJournal} ( - {study?.publicationDate?.slice(0, 4)}) + )} {study?.pubmedId && ( diff --git a/apps/platform/src/pages/SearchPage/SearchContainer.jsx b/apps/platform/src/pages/SearchPage/SearchContainer.jsx index 45320f937..3fae24531 100644 --- a/apps/platform/src/pages/SearchPage/SearchContainer.jsx +++ b/apps/platform/src/pages/SearchPage/SearchContainer.jsx @@ -229,7 +229,6 @@ function SearchContainer({ q, page, entities, data, onPageChange, onSetEntity }) md={6} sx={{ display: "flex", - alignItems: "center", justifyContent: "center", }} > diff --git a/apps/platform/src/pages/SearchPage/StudyResult.jsx b/apps/platform/src/pages/SearchPage/StudyResult.jsx index 71e88c722..dbb0d8782 100644 --- a/apps/platform/src/pages/SearchPage/StudyResult.jsx +++ b/apps/platform/src/pages/SearchPage/StudyResult.jsx @@ -1,7 +1,7 @@ -import { makeStyles, useTheme } from "@mui/styles"; +import { makeStyles } from "@mui/styles"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faChartBar } from "@fortawesome/free-solid-svg-icons"; -import { Highlights, Link } from "ui"; +import { Highlights, Link, StudyPublication } from "ui"; import { Box, Typography } from "@mui/material"; import { getStudyItemMetaData } from "@ot/utils"; @@ -20,7 +20,6 @@ const useStyles = makeStyles(theme => ({ function StudyResult({ data, highlights }) { const classes = useStyles(); - const theme = useTheme(); return (
@@ -42,12 +41,11 @@ function StudyResult({ data, highlights }) {
{" "} - {data.publicationFirstAuthor && ( - <> - {data.publicationFirstAuthor} et al. {data.publicationJournal} ( - {data.publicationDate?.slice(0, 4)}) - - )} +
diff --git a/apps/platform/src/pages/StudyPage/StudyProfileHeader.tsx b/apps/platform/src/pages/StudyPage/StudyProfileHeader.tsx index a55679b1a..4968036c6 100644 --- a/apps/platform/src/pages/StudyPage/StudyProfileHeader.tsx +++ b/apps/platform/src/pages/StudyPage/StudyProfileHeader.tsx @@ -9,6 +9,7 @@ import { LabelChip, DisplaySampleSize, PublicationsDrawer, + StudyPublication, } from "ui"; import { Box } from "@mui/material"; import { populationMap } from "@ot/constants"; @@ -106,8 +107,11 @@ function ProfileHeader() { )} {publicationFirstAuthor && ( - {publicationFirstAuthor} et al. {publicationJournal} ( - {publicationDate?.slice(0, 4)}) + )} {pubmedId && ( diff --git a/packages/ui/src/components/GlobalSearch/GlobalSearchListItem.jsx b/packages/ui/src/components/GlobalSearch/GlobalSearchListItem.jsx index f30091d29..ea33ac4e1 100644 --- a/packages/ui/src/components/GlobalSearch/GlobalSearchListItem.jsx +++ b/packages/ui/src/components/GlobalSearch/GlobalSearchListItem.jsx @@ -7,6 +7,7 @@ import { faXmark, faClockRotateLeft, faArrowTrendUp } from "@fortawesome/free-so import { clearRecentItem } from "./utils/searchUtils"; import DisplayVariantId from "../DisplayVariantId"; import { getStudyItemMetaData } from "@ot/utils"; +import StudyPublication from "../StudyPublication"; const ListItem = styled("li")(({ theme }) => ({ cursor: "pointer", @@ -215,12 +216,11 @@ function TopHitListItem({ item, onItemClick }) { {item.symbol && item.name} - {item.publicationFirstAuthor && ( - <> - {item.publicationFirstAuthor} et al. {item.publicationJournal} ( - {item.publicationDate?.slice(0, 4)}) - - )} + diff --git a/packages/ui/src/components/Navigate.tsx b/packages/ui/src/components/Navigate.tsx index d4df3b0c6..3aea1e300 100644 --- a/packages/ui/src/components/Navigate.tsx +++ b/packages/ui/src/components/Navigate.tsx @@ -1,13 +1,7 @@ import { Box } from "@mui/material"; import Link from "./Link"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { - faArrowRight, - faArrowRightToBracket, - faCaretRight, - faChevronRight, - faArrowUpRightFromSquare, -} from "@fortawesome/free-solid-svg-icons"; +import { faArrowRightToBracket } from "@fortawesome/free-solid-svg-icons"; type NavigateProps = { to: string; @@ -15,7 +9,7 @@ type NavigateProps = { export default function Navigate({ to }: NavigateProps) { return ( - + View diff --git a/packages/ui/src/components/OtAsyncTooltip/OtAsyncTooltip.tsx b/packages/ui/src/components/OtAsyncTooltip/OtAsyncTooltip.tsx index 0109dbb8a..d638ada4b 100644 --- a/packages/ui/src/components/OtAsyncTooltip/OtAsyncTooltip.tsx +++ b/packages/ui/src/components/OtAsyncTooltip/OtAsyncTooltip.tsx @@ -10,10 +10,15 @@ import { TooltipProps, } from "@mui/material"; import { useLazyQuery } from "@apollo/client"; -import { getEntityIcon, getEntityQuery, getQueryVariables } from "./utils/asyncTooltipUtil"; +import { + getEntityDescription, + getEntityIcon, + getEntityQuery, + getQueryVariables, +} from "./utils/asyncTooltipUtil"; import { naLabel } from "@ot/constants"; -import { getStudyItemMetaData } from "@ot/utils"; +import StudyPublication from "../StudyPublication"; const DELAY_REQUEST = 1000; @@ -56,8 +61,10 @@ function OtAsyncTooltip({ children, entity, id }: OtAsyncTooltipProps): ReactEle }); function getTooltipContent() { + let entityAccessor = entity; if (loading || !data) return ; - return ; + if (entity === "credible-set") entityAccessor = "credibleSet"; + return ; } function abortApiCall() { @@ -119,41 +126,33 @@ function AsyncTooltipDataView({ entity: string; data: Record; }): ReactElement { - function getLabel() { - return data?.name || data?.id || naLabel; - } - - function getDescription() { - let descText = ""; - - if (Array.isArray(data.description) && data.description.length) - descText = data?.description[0].substring(0, 150); - else if (Array.isArray(data.description) && !data.description.length) descText = ""; - else if (data.description) descText = data?.description.substring(0, 150); - - // study subtext - descText += getStudyItemMetaData({ - studyType: data?.studyType, - nSamples: data?.nSamples, - credibleSetsCount: data?.credibleSets?.credibleSetsCount, - }); - - if (!descText) return "No description available."; - - return descText; - } + const showSubText = !!data?.mostSevereConsequence?.label || data?.publicationFirstAuthor; function getSubtext() { - let finalSubText = ""; + let finalSubText; + // variant subtext const mostSevereConsequence = data?.mostSevereConsequence?.label; + if (mostSevereConsequence) finalSubText = `Most severe consequence: ${mostSevereConsequence}`; - if (mostSevereConsequence) finalSubText += `Most severe consequence: ${mostSevereConsequence}`; + // study subtext + const publicationData = data?.publicationFirstAuthor; + if (publicationData) + finalSubText = ( + + ); return finalSubText; } - const showSubText = !!data?.mostSevereConsequence?.label; + function getLabel() { + if (entity === "credible-set") return "Credible set"; + return data?.name || data?.id || naLabel; + } return ( @@ -184,7 +183,7 @@ function AsyncTooltipDataView({ {getLabel()} {" "} theme.palette.grey[800] }}> - {getDescription()} + {getEntityDescription(entity, data)} diff --git a/packages/ui/src/components/OtAsyncTooltip/queries/CredibleSetsTooltipQuery.gql b/packages/ui/src/components/OtAsyncTooltip/queries/CredibleSetsTooltipQuery.gql index e69de29bb..f3e7320c9 100644 --- a/packages/ui/src/components/OtAsyncTooltip/queries/CredibleSetsTooltipQuery.gql +++ b/packages/ui/src/components/OtAsyncTooltip/queries/CredibleSetsTooltipQuery.gql @@ -0,0 +1,12 @@ +query CredibleSetsTooltipQuery($studyLocusId: String!) { + credibleSet(studyLocusId: $studyLocusId) { + id: studyLocusId + variant { + id + } + study { + id + studyType + } + } +} diff --git a/packages/ui/src/components/OtAsyncTooltip/queries/StudyTooltipQuery.gql b/packages/ui/src/components/OtAsyncTooltip/queries/StudyTooltipQuery.gql index 0090fb719..33036a8cb 100644 --- a/packages/ui/src/components/OtAsyncTooltip/queries/StudyTooltipQuery.gql +++ b/packages/ui/src/components/OtAsyncTooltip/queries/StudyTooltipQuery.gql @@ -7,5 +7,8 @@ query StudyTooltipQuery($studyId: String!) { credibleSets { credibleSetsCount: count } + publicationFirstAuthor + publicationDate + publicationJournal } } diff --git a/packages/ui/src/components/OtAsyncTooltip/utils/asyncTooltipUtil.ts b/packages/ui/src/components/OtAsyncTooltip/utils/asyncTooltipUtil.ts index 89434102d..5df8064af 100644 --- a/packages/ui/src/components/OtAsyncTooltip/utils/asyncTooltipUtil.ts +++ b/packages/ui/src/components/OtAsyncTooltip/utils/asyncTooltipUtil.ts @@ -3,14 +3,17 @@ import DISEASE_TOOLTIP_QUERY from "../queries/DiseaseTooltipQuery.gql"; import STUDY_TOOLTIP_QUERY from "../queries/StudyTooltipQuery.gql"; import TARGET_TOOLTIP_QUERY from "../queries/TargetTooltipQuery.gql"; import VARIANT_TOOLTIP_QUERY from "../queries/VariantTooltipQuery.gql"; +import CREDIBLE_SETS_TOOLTIP_QUERY from "../queries/CredibleSetsTooltipQuery.gql"; import { faChartBar, + faDiagramProject, faDna, faMapPin, faPrescriptionBottleAlt, faStethoscope, faTag, } from "@fortawesome/free-solid-svg-icons"; +import { getStudyItemMetaData } from "@ot/utils"; export function getQueryVariables(entity: string, id: string): Record { switch (entity) { @@ -24,6 +27,8 @@ export function getQueryVariables(entity: string, id: string): Record { return TARGET_TOOLTIP_QUERY; case "variant": return VARIANT_TOOLTIP_QUERY; + case "credible-set": + return CREDIBLE_SETS_TOOLTIP_QUERY; default: return; } @@ -58,7 +65,48 @@ export const getEntityIcon = (entity: string) => { return faDna; case "variant": return faMapPin; + case "credible-set": + return faDiagramProject; default: return faTag; } }; + +export const getEntityDescription = (entity, data) => { + switch (entity) { + case "drug": + return getTrimmedDescription(data?.description); + case "disease": + return getTrimmedDescription(data?.description); + case "study": + return getStudyItemMetaData({ + studyType: data?.studyType, + nSamples: data?.nSamples, + credibleSetsCount: data?.credibleSets?.credibleSetsCount, + }); + case "target": + return getTrimmedDescription(data?.description[0] || ""); + case "variant": + return getTrimmedDescription(data?.description); + case "credible-set": + return getCredibleSetsDescription({ + variantId: data?.variant.id, + studyId: data?.study.id, + }); + default: + return "No description available."; + } +}; + +const getTrimmedDescription = (description: string | null) => { + if (!description || description.length < 1) return "No description available."; + return description.substring(0, 150); +}; + +export const getCredibleSetsDescription = ({ variantId, studyId }): string => { + let metaData = ""; + if (variantId) metaData += `Lead Variant: ${variantId}`; + if (studyId) metaData += ` • Study ID: ${studyId}`; + + return metaData; +}; diff --git a/packages/ui/src/components/StudyPublication.tsx b/packages/ui/src/components/StudyPublication.tsx new file mode 100644 index 000000000..a53706ad5 --- /dev/null +++ b/packages/ui/src/components/StudyPublication.tsx @@ -0,0 +1,26 @@ +import { ReactNode } from "react"; + +type StudyPublicationProps = { + publicationFirstAuthor: string; + publicationJournal: string; + publicationDate: string; +}; + +function StudyPublication({ + publicationFirstAuthor, + publicationJournal, + publicationDate, +}: StudyPublicationProps): ReactNode { + if (!publicationFirstAuthor) return ""; + return ( + <> + {publicationFirstAuthor && ( + <> + {publicationFirstAuthor} et al. {publicationJournal} ( + {publicationDate?.slice(0, 4)}) + + )} + + ); +} +export default StudyPublication; diff --git a/packages/ui/src/index.tsx b/packages/ui/src/index.tsx index f951563f4..25abf101a 100644 --- a/packages/ui/src/index.tsx +++ b/packages/ui/src/index.tsx @@ -48,6 +48,7 @@ export { default as OtScoreLinearBar } from "./components/OtScoreLinearBar"; export { default as OtTableSSP } from "./components/OtTable/OtTableSSP"; export { default as EntityPanel } from "./components/EntityPanel/EntityPanel"; export { default as Page } from "./pages/Page"; +export { default as StudyPublication } from "./components/StudyPublication"; export * as summaryUtils from "./components/Summary/utils"; export * from "./components/Footer";