From d2984c0885442a22ea7279a50869682439d29928 Mon Sep 17 00:00:00 2001 From: Chintan Mehta <22376522+chinmehta@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:58:19 +0000 Subject: [PATCH] [Platform]: Sections updated with Server side table added (#630) * feat: table skeleton loading row * feat: downloads page loading table * fix: table loading * feat: using table and chart loading * feat: ssp table init * feat: ssp table merge * feat: ssp initial loading skeleton * feat: evidence page ssp table updated * feat: disabled hiding column prop * feat: replaced common known drugs with ssp component * fix: target profile page revert --- .../sections/src/common/KnownDrugs/Body.jsx | 323 ------------------ .../sections/src/common/KnownDrugs/index.js | 1 - .../sections/src/disease/KnownDrugs/Body.jsx | 162 ++++++++- .../sections/src/drug/KnownDrugs/Body.jsx | 105 +++++- .../sections/src/evidence/Chembl/Body.jsx | 161 ++------- packages/sections/src/evidence/EVA/Body.jsx | 149 +------- .../sections/src/evidence/EVASomatic/Body.jsx | 198 +++-------- packages/sections/src/evidence/Impc/Body.jsx | 136 +------- .../sections/src/target/KnownDrugs/Body.jsx | 146 +++++++- .../components/KnownDrugsSourceDrawer.jsx} | 4 +- .../ui/src/components/OtTable/OtTableSSP.tsx | 1 + .../ui/src/components/Section/SectionItem.tsx | 2 +- packages/ui/src/index.tsx | 1 + 13 files changed, 474 insertions(+), 915 deletions(-) delete mode 100644 packages/sections/src/common/KnownDrugs/Body.jsx delete mode 100644 packages/sections/src/common/KnownDrugs/index.js rename packages/{sections/src/common/KnownDrugs/SourceDrawer.jsx => ui/src/components/KnownDrugsSourceDrawer.jsx} (98%) diff --git a/packages/sections/src/common/KnownDrugs/Body.jsx b/packages/sections/src/common/KnownDrugs/Body.jsx deleted file mode 100644 index 8a9133dd4..000000000 --- a/packages/sections/src/common/KnownDrugs/Body.jsx +++ /dev/null @@ -1,323 +0,0 @@ -import { useState, useEffect } from "react"; - -import { Link, Table, getPage, getComparator, useCursorBatchDownloader } from "ui"; -import { naLabel, phaseMap } from "../../constants"; -import { sentenceCase } from "../../utils/global"; -import SourceDrawer from "./SourceDrawer"; -import { SectionItem } from "ui"; - -function getColumnPool(id, entity) { - return { - clinicalTrials: { - label: "Clinical trials information", - columns: [ - { - id: "phase", - label: "Phase", - sortable: true, - renderCell: ({ phase }) => phaseMap(phase), - filterValue: ({ phase }) => phaseMap(phase), - }, - { - id: "status", - renderCell: d => (d.status ? d.status : naLabel), - }, - { - id: "sources", - label: "Source", - exportValue: d => d.urls.map(reference => reference.url), - renderCell: d => , - }, - ], - }, - disease: { - label: "Disease information", - columns: [ - { - id: "disease", - propertyPath: "disease.id", - renderCell: d => {d.disease.name}, - }, - ], - }, - drug: { - label: "Drug information", - columns: [ - { - id: "drug", - propertyPath: "drug.id", - renderCell: d => - d.drug ? {d.drug.name} : naLabel, - }, - { - id: "type", - propertyPath: "drugType", - renderCell: d => d.drugType, - }, - { - id: "mechanismOfAction", - }, - { - id: "Action type", - renderCell: ({ drug, target }) => { - if (!drug?.mechanismsOfAction) return naLabel; - const at = new Set(); - - const targetId = entity === "target" ? id : target.id; - - drug.mechanismsOfAction.rows.forEach(row => { - row.targets.forEach(t => { - if (t.id === targetId) { - at.add(row.actionType); - } - }); - }); - - const actionTypes = Array.from(at); - - return actionTypes.length > 0 ? ( - - ) : ( - naLabel - ); - }, - }, - ], - }, - target: { - label: "Target information", - columns: [ - { - id: "targetSymbol", - label: "Symbol", - propertyPath: "target.approvedSymbol", - renderCell: d => {d.target.approvedSymbol}, - }, - { - id: "targetName", - label: "Name", - propertyPath: "target.approvedName", - hidden: ["lgDown"], - renderCell: d => d.target.approvedName, - }, - ], - }, - }; -} - -const INIT_PAGE_SIZE = 10; - -function Body({ - definition, - entity, - variables, - BODY_QUERY, - Description, - columnsToShow, - stickyColumn, - exportColumns, - client, -}) { - const [initialLoading, setInitialLoading] = useState(true); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(false); - const [count, setCount] = useState(0); - const [cursor, setCursor] = useState(""); - const [rows, setRows] = useState([]); - const [page, setPage] = useState(0); - const [pageSize, setPageSize] = useState(INIT_PAGE_SIZE); - const [globalFilter, setGlobalFilter] = useState(""); - const [sortColumn, setSortColumn] = useState(null); - const [sortOrder, setSortOrder] = useState("asc"); - - const id = variables[Object.keys(variables)[0]]; - const columnPool = getColumnPool(id, entity); - const columns = []; - - columnsToShow.forEach(columnGroupName => { - columns.push( - ...columnPool[columnGroupName].columns.map(column => - column.id === stickyColumn ? { ...column, sticky: true } : column - ) - ); - }); - - const headerGroups = [ - ...columnsToShow.map(columnGroupName => ({ - colspan: columnPool[columnGroupName].columns.length, - label: columnPool[columnGroupName].label, - })), - ]; - - const fetchDrugs = (newVariables, newCursor, size, freeTextQuery) => - client.query({ - query: BODY_QUERY, - fetchPolicy: "no-cache", - variables: { - ...newVariables, - cursor: newCursor, - size, - freeTextQuery, - }, - }); - - useEffect( - () => { - let isCurrent = true; - - fetchDrugs(variables, null, pageSize) - .then(res => { - setInitialLoading(false); - if (res.data[entity].knownDrugs && isCurrent) { - const { - cursor: newCursor, - count: newCount, - rows: newRows, - } = res.data[entity].knownDrugs; - setCursor(newCursor); - setCount(newCount); - setRows(newRows); - } - }) - .catch(e => { - setInitialLoading(false); - setError(e); - }); - - return () => { - isCurrent = false; - }; - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [variables] - ); - - const getWholeDataset = useCursorBatchDownloader( - BODY_QUERY, - { ...variables, freeTextQuery: globalFilter }, - `data[${entity}].knownDrugs` - ); - - const handlePageChange = newPage => { - const numNewPageSize = parseInt(newPage, 10); - if (pageSize * numNewPageSize + pageSize > rows.length && cursor !== null) { - setLoading(true); - fetchDrugs(variables, cursor, pageSize, globalFilter).then(res => { - const { cursor: newCursor, rows: newRows } = res.data[entity].knownDrugs; - setCursor(newCursor); - setPage(numNewPageSize); - setRows([...rows, ...newRows]); - setLoading(false); - }); - } else { - setPage(numNewPageSize); - } - }; - - const handleRowsPerPageChange = newPageSize => { - const numNewPageSize = parseInt(newPageSize, 10); - if (numNewPageSize > rows.length && cursor !== null) { - setLoading(true); - fetchDrugs(variables, cursor, numNewPageSize, globalFilter).then(res => { - const { cursor: newCursor, rows: newRows } = res.data[entity].knownDrugs; - setCursor(newCursor); - setPage(0); - setPageSize(numNewPageSize); - setRows([...rows, ...newRows]); - setLoading(false); - }); - } else { - setPage(0); - setPageSize(numNewPageSize); - } - }; - - const handleGlobalFilterChange = newGlobalFilter => { - setLoading(true); - fetchDrugs(variables, null, pageSize, newGlobalFilter).then(res => { - const { - cursor: newCursor, - count: newCount, - rows: newRows = [], - } = res.data[entity].knownDrugs ?? {}; - setLoading(false); - setPage(0); - setCursor(newCursor); - setCount(newCount); - setGlobalFilter(newGlobalFilter); - setRows(newRows); - }); - }; - - const handleSortBy = sortBy => { - setSortColumn(sortBy); - setSortOrder( - // eslint-disable-next-line - sortColumn === sortBy ? (sortOrder === "asc" ? "desc" : "asc") : "asc" - ); - }; - const processedRows = [...rows]; - - if (sortColumn) { - processedRows.sort(getComparator(columns, sortOrder, sortColumn)); - } - - return ( - ( - - )} - /> - ); -} - -export default Body; diff --git a/packages/sections/src/common/KnownDrugs/index.js b/packages/sections/src/common/KnownDrugs/index.js deleted file mode 100644 index 15b1fb2bb..000000000 --- a/packages/sections/src/common/KnownDrugs/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default as Body } from "./Body"; diff --git a/packages/sections/src/disease/KnownDrugs/Body.jsx b/packages/sections/src/disease/KnownDrugs/Body.jsx index b491bf981..1bc3fd67c 100644 --- a/packages/sections/src/disease/KnownDrugs/Body.jsx +++ b/packages/sections/src/disease/KnownDrugs/Body.jsx @@ -1,10 +1,128 @@ -import { Body as KnownDrugsBody } from "../../common/KnownDrugs"; import Description from "./Description"; import { sentenceCase } from "../../utils/global"; import { definition } from "./index"; -import client from "../../client"; import KNOWN_DRUGS_BODY_QUERY from "./KnownDrugsQuery.gql"; +import { naLabel, phaseMap } from "../../constants"; +import { KnownDrugsSourceDrawer, Link, OtTableSSP, SectionItem } from "ui"; +import { useState } from "react"; + +function getColumnPool(id, entity) { + return [ + { + label: "Disease information", + columns: [ + { + id: "disease", + label: "Disease", + propertyPath: "disease.id", + renderCell: d => {d.disease.name}, + }, + ], + }, + { + label: "Drug information", + columns: [ + { + id: "drug", + label: "Drug", + enableHiding: false, + propertyPath: "drug.id", + sticky: true, + renderCell: d => + d.drug ? {d.drug.name} : naLabel, + }, + { + id: "type", + label: "Type", + propertyPath: "drugType", + renderCell: d => d.drugType, + }, + { + id: "mechanismOfAction", + label: "Mechanism Of Action", + }, + { + id: "actionType", + label: "Action Type", + renderCell: ({ drug, target }) => { + if (!drug?.mechanismsOfAction) return naLabel; + const at = new Set(); + + const targetId = entity === "target" ? id : target.id; + + drug.mechanismsOfAction.rows.forEach(row => { + row.targets.forEach(t => { + if (t.id === targetId) { + at.add(row.actionType); + } + }); + }); + + const actionTypes = Array.from(at); + + return actionTypes.length > 0 ? ( + + ) : ( + naLabel + ); + }, + }, + ], + }, + { + label: "Target information", + columns: [ + { + id: "targetSymbol", + label: "Symbol", + propertyPath: "target.approvedSymbol", + renderCell: d => {d.target.approvedSymbol}, + }, + { + id: "targetName", + label: "Name", + propertyPath: "target.approvedName", + hidden: ["lgDown"], + renderCell: d => d.target.approvedName, + }, + ], + }, + { + label: "Clinical trials information", + columns: [ + { + id: "phase", + label: "Phase", + sortable: true, + renderCell: ({ phase }) => phaseMap(phase), + filterValue: ({ phase }) => phaseMap(phase), + }, + { + id: "status", + label: "Status", + renderCell: d => (d.status ? d.status : naLabel), + }, + { + id: "sources", + label: "Source", + exportValue: d => d.urls.map(reference => reference.url), + renderCell: d => , + }, + ], + }, + ]; +} const exportColumns = [ { @@ -69,20 +187,34 @@ const exportColumns = [ }, ]; -function Body({ id: efoId, label: name }) { +function Body({ id: efoId, label: name, entity }) { + const columnPool = getColumnPool(efoId, entity); + const [request, setRequest] = useState({ loading: true, data: null, error: false }); + return ( - } - columnsToShow={["disease", "drug", "target", "clinicalTrials"]} - stickyColumn="drug" - exportColumns={exportColumns} - /> + <> + } + renderBody={() => ( + { + setRequest(dd); + }} + variables={{ efoId }} + /> + )} + /> + ); } diff --git a/packages/sections/src/drug/KnownDrugs/Body.jsx b/packages/sections/src/drug/KnownDrugs/Body.jsx index da45d345c..c2318b3ca 100644 --- a/packages/sections/src/drug/KnownDrugs/Body.jsx +++ b/packages/sections/src/drug/KnownDrugs/Body.jsx @@ -1,9 +1,70 @@ -import { definition } from "."; -import client from "../../client"; -import { Body as KnownDrugsBody } from "../../common/KnownDrugs"; import Description from "./Description"; +import { definition } from "./index"; import KNOWN_DRUGS_BODY_QUERY from "./KnownDrugsQuery.gql"; +import { naLabel, phaseMap } from "../../constants"; +import { KnownDrugsSourceDrawer, Link, OtTableSSP, SectionItem } from "ui"; +import { useState } from "react"; + +function getColumnPool(id, entity) { + return [ + { + label: "Disease information", + columns: [ + { + id: "disease", + sticky: true, + enableHiding: false, + label: "Disease", + propertyPath: "disease.id", + renderCell: d => {d.disease.name}, + }, + ], + }, + + { + label: "Target information", + columns: [ + { + id: "targetSymbol", + label: "Symbol", + propertyPath: "target.approvedSymbol", + renderCell: d => {d.target.approvedSymbol}, + }, + { + id: "targetName", + label: "Name", + propertyPath: "target.approvedName", + hidden: ["lgDown"], + renderCell: d => d.target.approvedName, + }, + ], + }, + { + label: "Clinical trials information", + columns: [ + { + id: "phase", + label: "Phase", + sortable: true, + renderCell: ({ phase }) => phaseMap(phase), + filterValue: ({ phase }) => phaseMap(phase), + }, + { + id: "status", + label: "Status", + renderCell: d => (d.status ? d.status : naLabel), + }, + { + id: "sources", + label: "Source", + exportValue: d => d.urls.map(reference => reference.url), + renderCell: d => , + }, + ], + }, + ]; +} const exportColumns = [ { @@ -37,19 +98,33 @@ const exportColumns = [ ]; function Body({ id: chemblId, label: name, entity }) { + const columnPool = getColumnPool(chemblId, entity); + const [request, setRequest] = useState({ loading: true, data: null, error: false }); + return ( - } - columnsToShow={["disease", "target", "clinicalTrials"]} - stickyColumn="disease" - exportColumns={exportColumns} - client={client} - /> + <> + } + renderBody={() => ( + { + setRequest(dd); + }} + variables={{ chemblId }} + /> + )} + /> + ); } diff --git a/packages/sections/src/evidence/Chembl/Body.jsx b/packages/sections/src/evidence/Chembl/Body.jsx index f8a4c1b54..c35c67d8f 100644 --- a/packages/sections/src/evidence/Chembl/Body.jsx +++ b/packages/sections/src/evidence/Chembl/Body.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState } from "react"; import { makeStyles } from "@mui/styles"; import { Link, @@ -6,18 +6,14 @@ import { Tooltip, ChipList, TableDrawer, - Table, - useCursorBatchDownloader, - getComparator, - getPage, DirectionOfEffectIcon, DirectionOfEffectTooltip, + OtTableSSP, } from "ui"; -import { defaultRowsPerPageOptions, phaseMap, sourceMap, naLabel } from "../../constants"; +import { phaseMap, sourceMap, naLabel } from "../../constants"; import { dataTypesMap } from "../../dataTypes"; import Description from "./Description"; import { definition } from "."; -import client from "../../client"; import CHEMBL_QUERY from "./ChemblQuery.gql"; import { Box, Typography } from "@mui/material"; @@ -79,6 +75,7 @@ function getColumns(classes) { { id: "disease.name", label: "Disease/phenotype", + enableHiding: false, renderCell: ({ disease, cohortPhenotypes }) => { let displayElement = naLabel; if (disease) displayElement = {disease.name}; @@ -153,6 +150,7 @@ function getColumns(classes) { { id: "drug.name", label: "Drug", + enableHiding: false, renderCell: ({ drug }) => {drug.name}, }, { @@ -272,146 +270,39 @@ function getColumns(classes) { ]; } -function fetchData({ ensemblId, efoId, cursor, size }) { - return client.query({ - query: CHEMBL_QUERY, - fetchPolicy: "no-cache", - variables: { - ensemblId, - efoId, - cursor, - size, - }, - }); -} - function Body({ id, label, entity }) { const { ensgId: ensemblId, efoId } = id; - const [initialLoading, setInitialLoading] = useState(true); - const [loading, setLoading] = useState(false); - const [count, setCount] = useState(0); - const [cursor, setCursor] = useState(""); - const [rows, setRows] = useState([]); - const [page, setPage] = useState(0); - const [size, setPageSize] = useState(10); - const [sortColumn, setSortColumn] = useState(null); - const [sortOrder, setSortOrder] = useState("asc"); + const [request, setRequest] = useState({ loading: true, data: null, error: false }); const classes = useStyles(); const columns = getColumns(classes); - useEffect(() => { - let isCurrent = true; - - fetchData({ ensemblId, efoId, cursor: "", size }).then(res => { - const { cursor: newCursor, rows: newRows, count: newCount } = res.data.disease.chembl; - if (isCurrent) { - setInitialLoading(false); - setCursor(newCursor); - setCount(newCount); - setRows(newRows); - } - }); - - return () => { - isCurrent = false; - }; - }, []); - - const getWholeDataset = useCursorBatchDownloader( - CHEMBL_QUERY, - { - ensemblId, - efoId, - }, - `data.disease.chembl` - ); - - const handlePageChange = newPage => { - const newPageInt = Number(newPage); - if (size * newPageInt + size > rows.length && cursor !== null) { - setLoading(true); - fetchData({ ensemblId, efoId, cursor, size }).then(res => { - const { cursor: newCursor, rows: newRows } = res.data.disease.chembl; - setRows([...rows, ...newRows]); - setLoading(false); - setCursor(newCursor); - setPage(newPageInt); - }); - } else { - setPage(newPageInt); - } - }; - - const handleRowsPerPageChange = newPageSize => { - const newPageSizeInt = Number(newPageSize); - if (newPageSizeInt > rows.length && cursor !== null) { - setLoading(true); - fetchData({ ensemblId, efoId, cursor, size: newPageSizeInt }).then(res => { - const { cursor: newCursor, rows: newRows } = res.data.disease.chembl; - setRows([...rows, ...newRows]); - setLoading(false); - setCursor(newCursor); - setPage(0); - setPageSize(newPageSizeInt); - }); - } else { - setPage(0); - setPageSize(newPageSizeInt); - } - }; - - const handleSortBy = sortBy => { - setSortColumn(sortBy); - setSortOrder( - // eslint-disable-next-line - sortColumn === sortBy ? (sortOrder === "asc" ? "desc" : "asc") : "asc" - ); - }; - - const processedRows = [...rows]; - - if (sortColumn) { - processedRows.sort(getComparator(columns, sortOrder, sortColumn)); - } - return ( } - renderBody={() => { - return ( -
- ); - }} + renderBody={() => ( + { + setRequest(req); + }} + variables={{ + ensemblId, + efoId, + }} + /> + )} /> ); } diff --git a/packages/sections/src/evidence/EVA/Body.jsx b/packages/sections/src/evidence/EVA/Body.jsx index ab6dd0e6d..4fcdb607e 100644 --- a/packages/sections/src/evidence/EVA/Body.jsx +++ b/packages/sections/src/evidence/EVA/Body.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState } from "react"; import { Typography } from "@mui/material"; import { Link, @@ -6,25 +6,15 @@ import { Tooltip, LabelChip, PublicationsDrawer, - getPage, - Table, - getComparator, - useCursorBatchDownloader, ClinvarStars, DirectionOfEffectIcon, DirectionOfEffectTooltip, DisplayVariantId, + OtTableSSP, } from "ui"; -import { - clinvarStarMap, - naLabel, - defaultRowsPerPageOptions, - variantConsequenceSource, -} from "../../constants"; +import { clinvarStarMap, naLabel, variantConsequenceSource } from "../../constants"; import { definition } from "."; - -import client from "../../client"; import Description from "./Description"; import { epmcUrl } from "../../utils/urls"; import CLINVAR_QUERY from "./ClinvarQuery.gql"; @@ -111,6 +101,7 @@ function getColumns(label) { { id: "variantId", label: "Variant", + enableHiding: false, renderCell: ({ variant }) => { if (!variant) return naLabel; const { id: variantId, referenceAllele, alternateAllele } = variant; @@ -303,144 +294,34 @@ function getColumns(label) { ]; } -function fetchClinvar({ ensemblId, efoId, cursor, size, freeTextQuery }) { - return client.query({ - query: CLINVAR_QUERY, - variables: { - ensemblId, - efoId, - cursor, - size, - freeTextQuery, - }, - }); -} - function Body({ id, label, entity }) { const { ensgId: ensemblId, efoId } = id; - const [initialLoading, setInitialLoading] = useState(true); // state variable to keep track of initial loading of rows - const [loading, setLoading] = useState(false); // state variable to keep track of loading state on page chage - const [count, setCount] = useState(0); - const [cursor, setCursor] = useState(""); - const [rows, setRows] = useState([]); - const [page, setPage] = useState(0); - const [size, setPageSize] = useState(10); - const [sortColumn, setSortColumn] = useState(null); - const [sortOrder, setSortOrder] = useState("asc"); - + const [request, setRequest] = useState({ loading: true, data: null, error: false }); const columns = getColumns(label); - useEffect(() => { - let isCurrent = true; - - fetchClinvar({ ensemblId, efoId, cursor: "", size }).then(res => { - const { cursor: newCursor, rows: newRows, count: newCount } = res.data.disease.eva; - if (isCurrent) { - setInitialLoading(false); - setCursor(newCursor); - setCount(newCount); - setRows(newRows); - } - }); - - return () => { - isCurrent = false; - }; - }, []); - - const getWholeDataset = useCursorBatchDownloader( - CLINVAR_QUERY, - { - ensemblId, - efoId, - }, - `data.disease.eva` - ); - - const handlePageChange = newPage => { - const newPageInt = Number(newPage); - if (size * newPageInt + size > rows.length && cursor !== null) { - setLoading(true); - fetchClinvar({ ensemblId, efoId, cursor, size }).then(res => { - const { cursor: newCursor, rows: newRows } = res.data.disease.eva; - setRows([...rows, ...newRows]); - setLoading(false); - setCursor(newCursor); - setPage(newPageInt); - }); - } else { - setPage(newPageInt); - } - }; - - const handleRowsPerPageChange = newPageSize => { - const newPageSizeInt = Number(newPageSize); - if (newPageSizeInt > rows.length && cursor !== null) { - setLoading(true); - fetchClinvar({ ensemblId, efoId, cursor, size: newPageSizeInt }).then(res => { - const { cursor: newCursor, rows: newRows } = res.data.disease.eva; - setRows([...rows, ...newRows]); - setLoading(false); - setCursor(newCursor); - setPage(0); - setPageSize(newPageSizeInt); - }); - } else { - setPage(0); - setPageSize(newPageSizeInt); - } - }; - - const handleSortBy = sortBy => { - setSortColumn(sortBy); - setSortOrder( - // eslint-disable-next-line - sortColumn === sortBy ? (sortOrder === "asc" ? "desc" : "asc") : "asc" - ); - }; - - const processedRows = [...rows]; - - if (sortColumn) { - processedRows.sort(getComparator(columns, sortOrder, sortColumn)); - } - return ( } renderBody={() => ( -
{ + setRequest(req); + }} variables={{ ensemblId, efoId, - cursor, - size, }} /> )} diff --git a/packages/sections/src/evidence/EVASomatic/Body.jsx b/packages/sections/src/evidence/EVASomatic/Body.jsx index a81725fa1..5b8d69592 100644 --- a/packages/sections/src/evidence/EVASomatic/Body.jsx +++ b/packages/sections/src/evidence/EVASomatic/Body.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState } from "react"; import { Box, Typography } from "@mui/material"; import { makeStyles } from "@mui/styles"; import { @@ -8,19 +8,15 @@ import { Link, PublicationsDrawer, ClinvarStars, - Table, - useCursorBatchDownloader, - getComparator, - getPage, DirectionOfEffectIcon, DirectionOfEffectTooltip, + OtTableSSP, } from "ui"; -import client from "../../client"; import { sentenceCase } from "../../utils/global"; import { epmcUrl } from "../../utils/urls"; -import { clinvarStarMap, naLabel, defaultRowsPerPageOptions } from "../../constants"; +import { clinvarStarMap, naLabel } from "../../constants"; import Description from "./Description"; import { dataTypesMap } from "../../dataTypes"; import EVA_SOMATIC_QUERY from "./EvaSomaticQuery.gql"; @@ -66,6 +62,7 @@ const getColumns = label => [ { id: "variantId", label: "Variant", + enableHiding: false, renderCell: ({ variant: { id: variantId } }) => variantId ? ( <> @@ -249,19 +246,6 @@ const exportColumns = [ }, ]; -function fetchData({ ensemblId, efoId, cursor, size }) { - return client.query({ - query: EVA_SOMATIC_QUERY, - fetchPolicy: "no-cache", - variables: { - ensemblId, - efoId, - cursor, - size, - }, - }); -} - const useStyles = makeStyles({ roleInCancerBox: { display: "flex", @@ -275,152 +259,64 @@ function Body({ id, label, entity }) { const classes = useStyles(); const { ensgId: ensemblId, efoId } = id; - - const [initialLoading, setInitialLoading] = useState(true); - const [loading, setLoading] = useState(false); - const [count, setCount] = useState(0); - const [cursor, setCursor] = useState(""); - const [rows, setRows] = useState([]); - const [page, setPage] = useState(0); - const [size, setPageSize] = useState(10); - const [sortColumn, setSortColumn] = useState(null); - const [sortOrder, setSortOrder] = useState("asc"); - const [target, setTarget] = useState({}); + const [request, setRequest] = useState({ loading: true, data: null, error: false }); const columns = getColumns(label); - useEffect(() => { - let isCurrent = true; - - fetchData({ ensemblId, efoId, cursor: "", size }).then(res => { - const { cursor: newCursor, rows: newRows, count: newCount } = res.data.disease.eva_somatic; - if (isCurrent) { - setInitialLoading(false); - setCursor(newCursor); - setCount(newCount); - setRows(newRows); - setTarget(res.data.target); - } - }); - - return () => { - isCurrent = false; - }; - }, []); - - const getWholeDataset = useCursorBatchDownloader( - EVA_SOMATIC_QUERY, - { - ensemblId, - efoId, - }, - `data.disease.eva_somatic` - ); - - const handlePageChange = newPage => { - const newPageInt = Number(newPage); - if (size * newPageInt + size > rows.length && cursor !== null) { - setLoading(true); - fetchData({ ensemblId, efoId, cursor, size }).then(res => { - const { cursor: newCursor, rows: newRows } = res.data.disease.eva_somatic; - setRows([...rows, ...newRows]); - setLoading(false); - setCursor(newCursor); - setPage(newPageInt); - }); - } else { - setPage(newPageInt); - } - }; + function getRoleInCancer() { + if (!request.data) return null; - const handleRowsPerPageChange = newPageSize => { - const newPageSizeInt = Number(newPageSize); - if (newPageSizeInt > rows.length && cursor !== null) { - setLoading(true); - fetchData({ ensemblId, efoId, cursor, size: newPageSizeInt }).then(res => { - const { cursor: newCursor, rows: newRows } = res.data.disease.eva_somatic; - setRows([...rows, ...newRows]); - setLoading(false); - setCursor(newCursor); - setPage(0); - setPageSize(newPageSizeInt); - }); - } else { - setPage(0); - setPageSize(newPageSizeInt); + const { hallmarks } = request.data?.target; + let roleInCancerItems = [{ label: "Unknown" }]; + if (hallmarks && hallmarks.attributes.length > 0) { + roleInCancerItems = hallmarks.attributes + .filter(attribute => attribute.name === "role in cancer") + .map(attribute => ({ + label: attribute.description, + url: epmcUrl(attribute.pmid), + })); } - }; - const handleSortBy = sortBy => { - setSortColumn(sortBy); - setSortOrder( - // eslint-disable-next-line - sortColumn === sortBy ? (sortOrder === "asc" ? "desc" : "asc") : "asc" + return ( + <> + + {label.symbol} role in cancer: + + + ); - }; - - const processedRows = [...rows]; - - if (sortColumn) { - processedRows.sort(getComparator(columns, sortOrder, sortColumn)); } return ( } - renderBody={() => { - const { hallmarks } = target; - const roleInCancerItems = - hallmarks && hallmarks.attributes.length > 0 - ? hallmarks.attributes - .filter(attribute => attribute.name === "role in cancer") - .map(attribute => ({ - label: attribute.description, - url: epmcUrl(attribute.pmid), - })) - : [{ label: "Unknown" }]; - return ( - <> - - - {label.symbol} role in cancer: - - - -
- - ); - }} + renderBody={() => ( + <> + {getRoleInCancer()} + + { + setRequest(req); + }} + variables={{ + ensemblId, + efoId, + }} + /> + + )} /> ); } diff --git a/packages/sections/src/evidence/Impc/Body.jsx b/packages/sections/src/evidence/Impc/Body.jsx index e6b81540a..49e5d3b7c 100644 --- a/packages/sections/src/evidence/Impc/Body.jsx +++ b/packages/sections/src/evidence/Impc/Body.jsx @@ -1,27 +1,23 @@ import { Typography } from "@mui/material"; -import { useState, useEffect } from "react"; import { Link, SectionItem, Tooltip, - Table, TableDrawer, MouseModelAllelicComposition, - useCursorBatchDownloader, - getComparator, - getPage, DirectionOfEffectIcon, DirectionOfEffectTooltip, + OtTableSSP, } from "ui"; -import client from "../../client"; import { definition } from "."; import Description from "./Description"; import INTOGEN_QUERY from "./sectionQuery.gql"; import { dataTypesMap } from "../../dataTypes"; import { sentenceCase } from "../../utils/global"; -import { defaultRowsPerPageOptions, naLabel } from "../../constants"; +import { naLabel } from "../../constants"; +import { useState } from "react"; const columns = [ { @@ -100,6 +96,7 @@ const columns = [ { id: "literature", label: "Mouse model allelic composition", + enableHiding: false, renderCell: ({ biologicalModelAllelicComposition, biologicalModelGeneticBackground, @@ -156,138 +153,33 @@ const exportColumns = [ }, ]; -function fetchData({ ensemblId, efoId, cursor, size }) { - return client.query({ - query: INTOGEN_QUERY, - variables: { - ensemblId, - efoId, - cursor, - size, - }, - }); -} - function Body({ id, label, entity }) { const { ensgId: ensemblId, efoId } = id; - const [initialLoading, setInitialLoading] = useState(true); - const [loading, setLoading] = useState(false); - const [count, setCount] = useState(0); - const [cursor, setCursor] = useState(""); - const [rows, setRows] = useState([]); - const [page, setPage] = useState(0); - const [size, setPageSize] = useState(10); - const [sortColumn, setSortColumn] = useState(null); - const [sortOrder, setSortOrder] = useState("asc"); - - useEffect(() => { - let isCurrent = true; - - fetchData({ ensemblId, efoId, cursor: "", size }).then(res => { - const { cursor: newCursor, rows: newRows, count: newCount } = res.data.disease.impc; - if (isCurrent) { - setInitialLoading(false); - setCursor(newCursor); - setCount(newCount); - setRows(newRows); - } - }); - - return () => { - isCurrent = false; - }; - }, []); - - const getWholeDataset = useCursorBatchDownloader( - INTOGEN_QUERY, - { - ensemblId, - efoId, - }, - `data.disease.impc` - ); - - const handlePageChange = newPage => { - const newPageInt = Number(newPage); - if (size * newPageInt + size > rows.length && cursor !== null) { - setLoading(true); - fetchData({ ensemblId, efoId, cursor, size }).then(res => { - const { cursor: newCursor, rows: newRows } = res.data.disease.impc; - setRows([...rows, ...newRows]); - setLoading(false); - setCursor(newCursor); - setPage(newPageInt); - }); - } else { - setPage(newPageInt); - } - }; - - const handleRowsPerPageChange = newPageSize => { - const newPageSizeInt = Number(newPageSize); - if (newPageSizeInt > rows.length && cursor !== null) { - setLoading(true); - fetchData({ ensemblId, efoId, cursor, size: newPageSizeInt }).then(res => { - const { cursor: newCursor, rows: newRows } = res.data.disease.impc; - setRows([...rows, ...newRows]); - setLoading(false); - setCursor(newCursor); - setPage(0); - setPageSize(newPageSizeInt); - }); - } else { - setPage(0); - setPageSize(newPageSizeInt); - } - }; - - const handleSortBy = sortBy => { - setSortColumn(sortBy); - setSortOrder( - // eslint-disable-next-line - sortColumn === sortBy ? (sortOrder === "asc" ? "desc" : "asc") : "asc" - ); - }; - - const processedRows = [...rows]; - - if (sortColumn) { - processedRows.sort(getComparator(columns, sortOrder, sortColumn)); - } + const [request, setRequest] = useState({ loading: true, data: null, error: false }); return ( } renderBody={() => ( -
{ + setRequest(req); + }} variables={{ ensemblId, efoId, - cursor, - size, }} /> )} diff --git a/packages/sections/src/target/KnownDrugs/Body.jsx b/packages/sections/src/target/KnownDrugs/Body.jsx index da34433b1..a36e5c376 100644 --- a/packages/sections/src/target/KnownDrugs/Body.jsx +++ b/packages/sections/src/target/KnownDrugs/Body.jsx @@ -1,10 +1,110 @@ -import { Body as KnownDrugsBody } from "../../common/KnownDrugs"; import Description from "./Description"; import { sentenceCase } from "../../utils/global"; +import { definition } from "./index"; -import { definition } from "."; import KNOWN_DRUGS_BODY_QUERY from "./KnownDrugsQuery.gql"; -import client from "../../client"; +import { naLabel, phaseMap } from "../../constants"; +import { KnownDrugsSourceDrawer, Link, OtTableSSP, SectionItem } from "ui"; +import { useState } from "react"; + +function getColumnPool(id, entity) { + return [ + { + label: "Drug information", + columns: [ + { + id: "drug", + label: "Drug", + enableHiding: false, + propertyPath: "drug.id", + sticky: true, + renderCell: d => + d.drug ? {d.drug.name} : naLabel, + }, + { + id: "type", + label: "Type", + propertyPath: "drugType", + renderCell: d => d.drugType, + }, + { + id: "mechanismOfAction", + label: "Mechanism Of Action", + }, + { + id: "actionType", + label: "Action Type", + renderCell: ({ drug, target }) => { + if (!drug?.mechanismsOfAction) return naLabel; + const at = new Set(); + + const targetId = entity === "target" ? id : target.id; + + drug.mechanismsOfAction.rows.forEach(row => { + row.targets.forEach(t => { + if (t.id === targetId) { + at.add(row.actionType); + } + }); + }); + + const actionTypes = Array.from(at); + + return actionTypes.length > 0 ? ( + + ) : ( + naLabel + ); + }, + }, + ], + }, + { + label: "Disease information", + columns: [ + { + id: "disease", + label: "Disease", + propertyPath: "disease.id", + renderCell: d => {d.disease.name}, + }, + ], + }, + { + label: "Clinical trials information", + columns: [ + { + id: "phase", + label: "Phase", + sortable: true, + renderCell: ({ phase }) => phaseMap(phase), + filterValue: ({ phase }) => phaseMap(phase), + }, + { + id: "status", + label: "Status", + renderCell: d => (d.status ? d.status : naLabel), + }, + { + id: "sources", + label: "Source", + exportValue: d => d.urls.map(reference => reference.url), + renderCell: d => , + }, + ], + }, + ]; +} const exportColumns = id => [ { @@ -61,20 +161,34 @@ const exportColumns = id => [ }, ]; -function Body({ id: ensgId, label: symbol, entity }) { +function Body({ id: ensgId, label: name, entity }) { + const columnPool = getColumnPool(ensgId, entity); + const [request, setRequest] = useState({ loading: true, data: null, error: false }); + return ( - } - columnsToShow={["drug", "disease", "clinicalTrials"]} - stickyColumn="drug" - exportColumns={exportColumns(ensgId)} - client={client} - /> + <> + } + renderBody={() => ( + { + setRequest(req); + }} + variables={{ ensgId }} + /> + )} + /> + ); } diff --git a/packages/sections/src/common/KnownDrugs/SourceDrawer.jsx b/packages/ui/src/components/KnownDrugsSourceDrawer.jsx similarity index 98% rename from packages/sections/src/common/KnownDrugs/SourceDrawer.jsx rename to packages/ui/src/components/KnownDrugsSourceDrawer.jsx index 3fce20291..ef0f80736 100644 --- a/packages/sections/src/common/KnownDrugs/SourceDrawer.jsx +++ b/packages/ui/src/components/KnownDrugsSourceDrawer.jsx @@ -97,7 +97,7 @@ const drawerSourceLabel = (name, url) => { return `${name} entry`; }; -function SourceDrawer({ references }) { +function KnownDrugsSourceDrawer({ references }) { const [open, setOpen] = useState(false); const classes = sourceDrawerStyles(); @@ -196,4 +196,4 @@ function SourceDrawer({ references }) { ); } -export default SourceDrawer; +export default KnownDrugsSourceDrawer; diff --git a/packages/ui/src/components/OtTable/OtTableSSP.tsx b/packages/ui/src/components/OtTable/OtTableSSP.tsx index 18e3a0d06..702b81bb5 100644 --- a/packages/ui/src/components/OtTable/OtTableSSP.tsx +++ b/packages/ui/src/components/OtTable/OtTableSSP.tsx @@ -318,6 +318,7 @@ function OtTableSSP({ Rows per page: theme.spacing(2) }} value={pagination.pageSize} onChange={e => { diff --git a/packages/ui/src/components/Section/SectionItem.tsx b/packages/ui/src/components/Section/SectionItem.tsx index df6aedfeb..2031213bc 100644 --- a/packages/ui/src/components/Section/SectionItem.tsx +++ b/packages/ui/src/components/Section/SectionItem.tsx @@ -83,7 +83,7 @@ function SectionItem({ ); if (selectedView === VIEW.table) return renderBody(); - if (selectedView === VIEW.chart) return renderChart(); + if (selectedView === VIEW.chart && renderChart) return renderChart(); // if (!loading && !hasData && showEmptySection) return
No data available for this {entity}.
; } diff --git a/packages/ui/src/index.tsx b/packages/ui/src/index.tsx index 534e7e146..6b20954de 100644 --- a/packages/ui/src/index.tsx +++ b/packages/ui/src/index.tsx @@ -30,6 +30,7 @@ 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 SummaryStatsTable } from "./components/SummaryStatsTable"; +export { default as KnownDrugsSourceDrawer } from "./components/KnownDrugsSourceDrawer"; export { default as PrivateWrapper } from "./components/PrivateWrapper"; export { default as NavBar } from "./components/NavBar";