From 64ef628ee4b03aaacc9b6c3669ce9231b249db50 Mon Sep 17 00:00:00 2001 From: Chintan Mehta Date: Sat, 23 Nov 2024 01:04:24 +0000 Subject: [PATCH 1/4] feat: table skeleton loading row --- .../src/variant/GWASCredibleSets/Body.tsx | 2 +- .../ui/src/components/OtTable/OtTable.tsx | 38 ++++++++++++------- .../ui/src/components/OtTable/table.types.ts | 2 +- .../ui/src/components/OtTable/tableUtil.ts | 4 +- .../ui/src/components/Section/SectionItem.tsx | 24 ++++++------ 5 files changed, 39 insertions(+), 31 deletions(-) diff --git a/packages/sections/src/variant/GWASCredibleSets/Body.tsx b/packages/sections/src/variant/GWASCredibleSets/Body.tsx index c7970476a..dddb14d6e 100644 --- a/packages/sections/src/variant/GWASCredibleSets/Body.tsx +++ b/packages/sections/src/variant/GWASCredibleSets/Body.tsx @@ -178,7 +178,7 @@ function getColumns({ id, referenceAllele, alternateAllele }: getColumnsType) { label: "Fine-mapping method", }, { - id: "topL2G", + id: "l2Gpredictions", label: "Top L2G", filterValue: ({ l2Gpredictions }) => l2Gpredictions?.target.approvedSymbol, tooltip: "Top gene prioritised by our locus-to-gene model", diff --git a/packages/ui/src/components/OtTable/OtTable.tsx b/packages/ui/src/components/OtTable/OtTable.tsx index e5763d013..b0cf162cb 100644 --- a/packages/ui/src/components/OtTable/OtTable.tsx +++ b/packages/ui/src/components/OtTable/OtTable.tsx @@ -1,5 +1,5 @@ -import { ReactElement, ReactNode, useEffect, useState } from "react"; -import { Box, CircularProgress, Grid, IconButton, NativeSelect, Skeleton } from "@mui/material"; +import { ReactElement, ReactNode, useEffect, useMemo, useState } from "react"; +import { Box, Grid, IconButton, NativeSelect, Skeleton } from "@mui/material"; import { useReactTable, ColumnFiltersState, @@ -26,7 +26,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import OtTableColumnFilter from "./OtTableColumnFilter"; // import { naLabel } from "../../constants"; import OtTableSearch from "./OtTableSearch"; -import { loadingTableRows, OtTableProps } from "./table.types"; +import { OtTableProps } from "./table.types"; import { FontAwesomeIconPadded, OtTableContainer, @@ -79,7 +79,6 @@ const searchFilter: FilterFn = (row, columnId, value, addMeta) => { function OtTable({ showGlobalFilter = true, - tableDataLoading = false, columns = [], rows = [], verticalHeaders = false, @@ -97,18 +96,25 @@ function OtTable({ const [columnFilters, setColumnFilters] = useState([]); const mappedColumns = mapTableColumnToTanstackColumns(columns); - // const loadingRows = getLoadingRows(mappedColumns, 10); + const loadingRows = getLoadingRows(mappedColumns, 10); + const loadingCells = getLoadingCells(mappedColumns); + + const tableData = useMemo(() => (loading ? loadingRows : rows), [loading]); + const tableColumns = useMemo(() => (loading ? loadingCells : mappedColumns), [loading]); + + function getCellData(cell: Record): ReactNode { + return <>{flexRender(cell.column.columnDef.cell, cell.getContext())}; + } const table = useReactTable({ - data: rows, - columns: mappedColumns, + data: tableData, + columns: tableColumns, filterFns: { searchFilterFn: searchFilter, }, state: { columnFilters, globalFilter, - loading, }, initialState: { sorting: getDefaultSortObj(sortBy, order), @@ -208,11 +214,8 @@ function OtTable({ return ( - {table.getState().loading ? ( - - ) : ( - <>{flexRender(cell.column.columnDef.cell, cell.getContext())} - )} + {getCellData(cell)} + {/* {flexRender(cell.column.columnDef.cell, cell.getContext())} */} {/* TODO: check NA value */} {/* {Boolean(flexRender(cell.column.columnDef.cell, cell.getContext())) || naLabel} */} @@ -241,11 +244,11 @@ function OtTable({ padding: theme => `${theme.spacing(2)} 0 `, }} > - {tableDataLoading && theme.spacing(2) }} size={25} />}
Rows per page: theme.spacing(2) }} value={table.getState().pagination.pageSize} onChange={e => { @@ -305,4 +308,11 @@ function OtTable({ ); } +function getLoadingCells(columms) { + return columms.map(column => ({ + ...column, + cell: () => , + })); +} + export default OtTable; diff --git a/packages/ui/src/components/OtTable/table.types.ts b/packages/ui/src/components/OtTable/table.types.ts index 9c706c9d5..26534e28b 100644 --- a/packages/ui/src/components/OtTable/table.types.ts +++ b/packages/ui/src/components/OtTable/table.types.ts @@ -33,7 +33,7 @@ export type OtTableProps = { }; export type loadingTableRows = { - id: string; + id: Record; }; /************************* diff --git a/packages/ui/src/components/OtTable/tableUtil.ts b/packages/ui/src/components/OtTable/tableUtil.ts index c5bc58e6e..ebddb9587 100644 --- a/packages/ui/src/components/OtTable/tableUtil.ts +++ b/packages/ui/src/components/OtTable/tableUtil.ts @@ -105,10 +105,10 @@ export function getCurrentPagePosition( * CREATES EMPTY ROWS WITH COLUMN OBJECT TO IMITATE LOADING ROWS * *****************************************************************/ export function getLoadingRows(columns, size = 10): loadingTableRows[] { - const rowObject: Record = {}; + const rowObject: Record = {}; for (const e in columns) { const item = columns[e].id; - rowObject[item] = null; + rowObject[item] = new Object(); } return new Array(size).fill(rowObject); } diff --git a/packages/ui/src/components/Section/SectionItem.tsx b/packages/ui/src/components/Section/SectionItem.tsx index e1193d034..21426c4f5 100644 --- a/packages/ui/src/components/Section/SectionItem.tsx +++ b/packages/ui/src/components/Section/SectionItem.tsx @@ -59,6 +59,16 @@ function SectionItem({ if (!hasData && !showEmptySection && !loading) return null; + function getSelectedView(): ReactNode { + if (error) return ; + if (showContentLoading && loading) + return ; + if (selectedView === VIEW.table) return renderBody(); + if (selectedView === VIEW.chart) return renderChart(); + // if (!loading && !hasData && showEmptySection) + return
No data available for this {entity}.
; + } + return (
@@ -106,19 +116,7 @@ function SectionItem({ - - <> - {error && } - {showContentLoading && loading && ( - - )} - {hasData && selectedView === VIEW.table && renderBody()} - {hasData && selectedView === VIEW.chart && renderChart()} - {showEmptySection && ( -
No data available for this {entity}.
- )} - -
+ {getSelectedView()} From d12514b2437f86d048aab1b64d1b81134840c1a7 Mon Sep 17 00:00:00 2001 From: Chintan Mehta Date: Sat, 23 Nov 2024 01:20:41 +0000 Subject: [PATCH 2/4] feat: downloads page loading table --- .../src/pages/DownloadsPage/DownloadsPage.jsx | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/apps/platform/src/pages/DownloadsPage/DownloadsPage.jsx b/apps/platform/src/pages/DownloadsPage/DownloadsPage.jsx index 1ffbb9044..880dc803c 100644 --- a/apps/platform/src/pages/DownloadsPage/DownloadsPage.jsx +++ b/apps/platform/src/pages/DownloadsPage/DownloadsPage.jsx @@ -1,12 +1,12 @@ import { Fragment, useState, useEffect } from "react"; import { gql, useQuery } from "@apollo/client"; -import { Paper, Box, Chip, Typography, Alert, AlertTitle, CircularProgress } from "@mui/material"; +import { Paper, Box, Chip, Typography, Alert, AlertTitle } from "@mui/material"; import { makeStyles } from "@mui/styles"; import { Link, OtTable } from "ui"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faAlignLeft } from "@fortawesome/free-solid-svg-icons"; -import { defaultRowsPerPageOptions, formatMap } from "../../constants"; +import { formatMap } from "../../constants"; import DownloadsDrawer from "./DownloadsDrawer"; import datasetMappings from "./dataset-mappings.json"; import config from "../../config"; @@ -183,21 +183,14 @@ function DownloadsPage() { ) : null} - {loadingDownloadsData && ( - - - - )} - - {loadingDownloadsData || loading || error ? null : ( + {error ? null : ( From deb57eaf575c2836a38274166417714109960699 Mon Sep 17 00:00:00 2001 From: Chintan Mehta Date: Tue, 7 Jan 2025 15:07:19 +0000 Subject: [PATCH 3/4] fix: table loading --- .../src/variant/InSilicoPredictors/Body.tsx | 4 +- .../InSilicoPredictorsPlot.tsx | 5 +- .../ui/src/components/OtTable/OtTable.tsx | 4 +- .../ui/src/components/OtTable/tableUtil.ts | 11 ++--- .../ui/src/components/Section/SectionItem.tsx | 49 ++++++++----------- 5 files changed, 31 insertions(+), 42 deletions(-) diff --git a/packages/sections/src/variant/InSilicoPredictors/Body.tsx b/packages/sections/src/variant/InSilicoPredictors/Body.tsx index e51efdcc2..78c14c217 100644 --- a/packages/sections/src/variant/InSilicoPredictors/Body.tsx +++ b/packages/sections/src/variant/InSilicoPredictors/Body.tsx @@ -70,6 +70,8 @@ export function Body({ id, entity }: BodyProps): ReactElement { variables, }); + const rows = getSortedRows(request); + return ( )} renderChart={() => { - const rows = getSortedRows(request); return ( { - const rows = getSortedRows(request); return ( ; return (
diff --git a/packages/ui/src/components/OtTable/OtTable.tsx b/packages/ui/src/components/OtTable/OtTable.tsx index b0cf162cb..c590406b4 100644 --- a/packages/ui/src/components/OtTable/OtTable.tsx +++ b/packages/ui/src/components/OtTable/OtTable.tsx @@ -96,7 +96,7 @@ function OtTable({ const [columnFilters, setColumnFilters] = useState([]); const mappedColumns = mapTableColumnToTanstackColumns(columns); - const loadingRows = getLoadingRows(mappedColumns, 10); + const loadingRows = getLoadingRows(10); const loadingCells = getLoadingCells(mappedColumns); const tableData = useMemo(() => (loading ? loadingRows : rows), [loading]); @@ -308,7 +308,7 @@ function OtTable({ ); } -function getLoadingCells(columms) { +function getLoadingCells(columms: Array>) { return columms.map(column => ({ ...column, cell: () => , diff --git a/packages/ui/src/components/OtTable/tableUtil.ts b/packages/ui/src/components/OtTable/tableUtil.ts index ebddb9587..ce3491c00 100644 --- a/packages/ui/src/components/OtTable/tableUtil.ts +++ b/packages/ui/src/components/OtTable/tableUtil.ts @@ -104,13 +104,10 @@ export function getCurrentPagePosition( /***************************************************************** * CREATES EMPTY ROWS WITH COLUMN OBJECT TO IMITATE LOADING ROWS * *****************************************************************/ -export function getLoadingRows(columns, size = 10): loadingTableRows[] { - const rowObject: Record = {}; - for (const e in columns) { - const item = columns[e].id; - rowObject[item] = new Object(); - } - return new Array(size).fill(rowObject); +export function getLoadingRows(size = 10): loadingTableRows[] { + const rows = new Array(size).fill({}); + console.log(rows); + return rows; } /*********************************** diff --git a/packages/ui/src/components/Section/SectionItem.tsx b/packages/ui/src/components/Section/SectionItem.tsx index e3cefd906..df6aedfeb 100644 --- a/packages/ui/src/components/Section/SectionItem.tsx +++ b/packages/ui/src/components/Section/SectionItem.tsx @@ -8,7 +8,7 @@ import sectionStyles from "./sectionStyles"; import { createShortName } from "../Summary/utils"; import PartnerLockIcon from "../PartnerLockIcon"; import SectionViewToggle from "./SectionViewToggle"; -import { ReactNode, useState } from "react"; +import { ReactNode, useEffect, useState } from "react"; import { VIEW } from "../../constants"; import { SummaryLoader } from "../PublicationsDrawer"; @@ -46,7 +46,7 @@ function SectionItem({ entity, showEmptySection = false, showContentLoading = false, - loadingMessage, + loadingMessage = "Loading data. This may take some time...", renderChart, defaultView = VIEW.table, }: SectionItemProps): ReactNode { @@ -55,6 +55,15 @@ function SectionItem({ const shortName = createShortName(definition); let hasData = false; const [selectedView, setSelectedView] = useState(defaultView); + const [showDelayLoadingMessage, setShowDelayLoadingMessage] = useState(false); + + useEffect(() => { + const delayLoaderTimer = setTimeout(() => setShowDelayLoadingMessage(true), 5000); + + return () => { + clearTimeout(delayLoaderTimer); + }; + }, []); if (data && entity && data[entity]) { hasData = definition.hasData(data[entity]); @@ -65,7 +74,14 @@ function SectionItem({ function getSelectedView(): ReactNode { if (error) return ; if (showContentLoading && loading) - return ; + return ( + <> + + {showDelayLoadingMessage && loadingMessage} + + + + ); if (selectedView === VIEW.table) return renderBody(); if (selectedView === VIEW.chart) return renderChart(); // if (!loading && !hasData && showEmptySection) @@ -119,32 +135,7 @@ function SectionItem({ - - <> - {error && } - {showContentLoading && - loading && - (loadingMessage ? ( - theme.palette.grey[100]} - display="flex" - flexDirection="column" - justifyContent="center" - > - - - ) : ( - - ))} - {hasData && selectedView === VIEW.table && renderBody()} - {hasData && selectedView === VIEW.chart && renderChart()} - {showEmptySection && ( -
No data available for this {entity}.
- )} - -
+ {getSelectedView()} From bd1f791e8a8874723f4234af70b37c3ba546e77c Mon Sep 17 00:00:00 2001 From: Chintan Mehta Date: Tue, 7 Jan 2025 16:22:42 +0000 Subject: [PATCH 4/4] feat: using table and chart loading --- packages/sections/src/study/GWASCredibleSets/Body.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/sections/src/study/GWASCredibleSets/Body.tsx b/packages/sections/src/study/GWASCredibleSets/Body.tsx index 575f8fe09..e5fae3f36 100644 --- a/packages/sections/src/study/GWASCredibleSets/Body.tsx +++ b/packages/sections/src/study/GWASCredibleSets/Body.tsx @@ -186,7 +186,6 @@ function Body({ id, entity }: BodyProps): ReactElement { definition={definition} entity={entity} request={request} - showContentLoading loadingMessage="Loading data. This may take some time..." renderDescription={() => } renderBody={() => (