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

[Platform]: Adding search by study to platform #633

Merged
merged 6 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
45 changes: 31 additions & 14 deletions apps/platform/src/components/Search/SearchQuery.gql
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
query SearchQuery($queryString: String!) {
topHit: search(
queryString: $queryString
entityNames: ["target", "disease", "drug", "variant"]
entityNames: ["target", "disease", "drug", "variant", "study"]
page: { index: 0, size: 1 }
) {
hits {
Expand All @@ -14,9 +14,18 @@ query SearchQuery($queryString: String!) {
referenceAllele
alternateAllele
rsIds
__typename
}


... on Study {
# entity
id
hasSumstats
traitFromSource
credibleSets {
count
}
}

... on Target {
id
approvedSymbol
Expand Down Expand Up @@ -46,7 +55,7 @@ query SearchQuery($queryString: String!) {
variants: search(
queryString: $queryString
entityNames: ["variant"]
page: {index: 0, size: 3}
page: { index: 0, size: 3 }
) {
hits {
id
Expand All @@ -62,11 +71,23 @@ query SearchQuery($queryString: String!) {
}
}
}
targets: search(
queryString: $queryString
entityNames: ["target"]
page: { index: 0, size: 3 }
) {
studies: search(queryString: $queryString, entityNames: ["study"], page: { index: 0, size: 3 }) {
hits {
id
entity
object {
... on Study {
id
hasSumstats
traitFromSource
credibleSets {
credibleSetsCount: count
}
}
}
}
}
targets: search(queryString: $queryString, entityNames: ["target"], page: { index: 0, size: 3 }) {
hits {
id
entity
Expand Down Expand Up @@ -95,11 +116,7 @@ query SearchQuery($queryString: String!) {
}
}
}
drugs: search(
queryString: $queryString
entityNames: ["drug"]
page: { index: 0, size: 3 }
) {
drugs: search(queryString: $queryString, entityNames: ["drug"], page: { index: 0, size: 3 }) {
hits {
id
entity
Expand Down
16 changes: 16 additions & 0 deletions apps/platform/src/pages/SearchPage/SearchContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import { makeStyles } from "@mui/styles";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faChartBar,
faDna,
faMapPin,
faPrescriptionBottleAlt,
Expand All @@ -25,6 +26,7 @@ import TargetDetail from "./TargetDetail";
import TargetResult from "./TargetResult";
import VariantDetail from "./VariantDetail";
import VariantResult from "./VariantResult";
import StudyResult from "./StudyResult";

const getCounts = entities => {
const counts = {
Expand Down Expand Up @@ -83,6 +85,18 @@ const SearchFilters = ({ entities, entitiesCount, setEntity }) => {
</>
}
/>
<FormControlLabel
className={classes.label}
control={<Checkbox checked={entities.includes("study")} onChange={setEntity("study")} />}
label={
<>
<FontAwesomeIcon icon={faChartBar} fixedWidth className={classes.labelIcon} />
<Typography variant="body2" display="inline">
Study ({counts.study})
</Typography>
</>
}
/>
<FormControlLabel
className={classes.label}
control={
Expand Down Expand Up @@ -136,6 +150,8 @@ function SearchResults({ results, page, onPageChange }) {
return <DiseaseResult key={object.id} data={object} highlights={highlights} />;
if (object[TYPE_NAME] === "Variant")
return <VariantResult key={object.id} data={object} highlights={highlights} />;
if (object[TYPE_NAME] === "Study")
return <StudyResult key={object.id} data={object} highlights={highlights} />;
return <DrugResult key={object.id} data={object} highlights={highlights} />;
})}

Expand Down
29 changes: 19 additions & 10 deletions apps/platform/src/pages/SearchPage/SearchPageQuery.gql
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
query SearchPageQuery(
$queryString: String!
$index: Int!
$entityNames: [String!]!
) {
search(
queryString: $queryString
entityNames: $entityNames
page: { index: $index, size: 10 }
) {
query SearchPageQuery($queryString: String!, $index: Int!, $entityNames: [String!]!) {
search(queryString: $queryString, entityNames: $entityNames, page: { index: $index, size: 10 }) {
total
aggregations {
entities {
Expand All @@ -27,6 +19,15 @@ query SearchPageQuery(
rsIds
}

... on Study {
id
hasSumstats
traitFromSource
credibleSets {
credibleSetsCount: count
}
}

... on Target {
id
approvedSymbol
Expand Down Expand Up @@ -66,6 +67,14 @@ query SearchPageQuery(
label
}
}
... on Study {
id
hasSumstats
traitFromSource
credibleSets {
count
}
}
... on Target {
id
approvedSymbol
Expand Down
39 changes: 39 additions & 0 deletions apps/platform/src/pages/SearchPage/StudyResult.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { makeStyles, useTheme } from "@mui/styles";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChartBar } from "@fortawesome/free-solid-svg-icons";
import { Highlights, Link } from "ui";
import { Typography } from "@mui/material";

const useStyles = makeStyles(theme => ({
container: {
marginBottom: "30px",
},
subtitle: {
fontSize: "20px",
fontWeight: 500,
},
icon: {
color: theme.palette.primary.main,
},
}));

function StudyResult({ data, highlights }) {
const classes = useStyles();
const theme = useTheme();

return (
<div className={classes.container}>
<Link to={`/variant/${data.id}`} className={classes.subtitle}>
<FontAwesomeIcon icon={faChartBar} className={classes.icon} /> <>{data.id}</>
</Link>
<Typography className={classes.subtitle} variant="subtitle1">
{data.credibleSets.credibleSetsCount > -1 && (
<>Credible sets count: {data.credibleSets.credibleSetsCount}</>
)}
</Typography>
<Highlights highlights={highlights} />
</div>
);
}

export default StudyResult;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useContext, useEffect, useState } from "react";
import { useContext, useState } from "react";
import { Box, Dialog, DialogContent, DialogTitle, styled } from "@mui/material";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons";
Expand Down
34 changes: 27 additions & 7 deletions packages/ui/src/components/GlobalSearch/GlobalSearchListHeader.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { makeStyles } from "@mui/styles";
import { Button, Typography, styled } from "@mui/material";
import { Button, Chip, Typography, styled } from "@mui/material";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faPrescriptionBottleAlt,
Expand Down Expand Up @@ -40,7 +40,19 @@ const ClearAllButton = styled(Button)`
function GlobalSearchListHeader({ listHeader, children }) {
const classes = useStyles();

if (listHeader === "") return { children };
const NewChip = (
<Chip
style={{
fontSize: "0.7rem",
margin: "0",
}}
size="small"
color="primary"
label="new"
/>
);

if (!listHeader) return { children };

const getIcon = () => {
switch (listHeader) {
Expand All @@ -60,12 +72,8 @@ function GlobalSearchListHeader({ listHeader, children }) {
return <FontAwesomeIcon icon={faDna} fixedWidth className={classes.labelIcon} />;
case "variants":
return <FontAwesomeIcon icon={faMapPin} fixedWidth className={classes.labelIcon} />;
case "Study":
case "studies":
return <FontAwesomeIcon icon={faChartBar} fixedWidth className={classes.labelIcon} />;
case "Gene":
return <FontAwesomeIcon icon={faDna} fixedWidth className={classes.labelIcon} />;
case "Variant":
return <FontAwesomeIcon icon={faMapPin} fixedWidth className={classes.labelIcon} />;
case "recent":
return null;
case "Search Suggestions":
Expand All @@ -75,13 +83,25 @@ function GlobalSearchListHeader({ listHeader, children }) {
}
};

function getIconTag() {
switch (listHeader) {
case "variants":
return NewChip;
case "studies":
return NewChip;
default:
return null;
}
}

return (
<div tabIndex="-1" className={classes.sectionHeader}>
<div className={classes.label}>
{getIcon()}
<Typography sx={{ fontWeight: "bold" }} variant="caption">
{listHeader}
</Typography>
<div>{getIconTag()}</div>
</div>
{listHeader === "recent" && (
<ClearAllButton onClick={clearAllRecent}>
Expand Down
29 changes: 14 additions & 15 deletions packages/ui/src/components/GlobalSearch/GlobalSearchListItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const TopHitItem = styled("li")(({ theme }) => ({
const TopHitItemContainer = styled("div")(({ theme }) => ({
cursor: "pointer",
width: "100%",
padding: `${theme.spacing(1.5)}`,
padding: `${theme.spacing(1.5)} 0`,
borderRadius: theme.spacing(1),
}));

Expand Down Expand Up @@ -235,15 +235,14 @@ function GlobalSearchListItem({ item, isTopHit = false, onItemClick }) {
return (
<>
<Typography variant="subtitle1">{symbolNameOrId(item)}</Typography>
{item.entity === "variant" && item.rsIds.length > 0 && (
<Typography variant="subtitle2" textTransform="lowercase">
&nbsp;({item.rsIds.join(", ")})
</Typography>
)}
</>
);
};

function getVariantRsIds() {
if (item.entity === "variant" && item.rsIds.length > 0) return item.rsIds.join(", ");
}

if (item.type === "recent") {
return <RecentListItem item={item} onItemClick={onItemClick} />;
}
Expand Down Expand Up @@ -286,7 +285,7 @@ function GlobalSearchListItem({ item, isTopHit = false, onItemClick }) {
</Typography>
</JustifyBetween>

<JustifyBetween>
{/* <JustifyBetween>
<Typography variant="caption">
<FlexSpan>
{item.pubAuthor && item.pubAuthor}
Expand All @@ -299,19 +298,20 @@ function GlobalSearchListItem({ item, isTopHit = false, onItemClick }) {
</FlexSpan>
</Typography>
<Typography variant="caption">{item.pubJournal && item.pubJournal}</Typography>
</JustifyBetween>
</JustifyBetween> */}

{item.rsId && (
{/* {item.rsId && (
<Typography variant="caption">
<strong>
<div className="loci"> Ensembl: {item.rsId}</div>
</strong>
</Typography>
)}
)} */}

<JustifyBetween>
<Typography variant="caption">
{item.numAssocLoci > -1 && <strong>{item.numAssocLoci} associated loci</strong>}
{item.credibleSetsCount > -1 && <>Credible sets count: {item.credibleSetsCount}</>}
{getVariantRsIds()}
</Typography>

{item.hasSumstats && (
Expand All @@ -321,19 +321,18 @@ function GlobalSearchListItem({ item, isTopHit = false, onItemClick }) {
fontSize: "0.8rem",
margin: "0",
}}
color="primary"
label="summary statistics"
/>
)}
</JustifyBetween>

{item.nInitial && <Typography variant="caption">N Study: {item.nInitial}</Typography>}
{/* {item.nInitial && <Typography variant="caption">N Study: {item.nInitial}</Typography>} */}

<div className="numbers">
{/* <div className="numbers">
<Typography variant="caption">
{item.start} {item.start && item.end && `-`} {item.end}
</Typography>
</div>
</div> */}
</ListItem>
);
}
Expand Down
Loading