Skip to content

Commit

Permalink
[Platform]: table loading state (#627)
Browse files Browse the repository at this point in the history
* feat: table skeleton loading row

* feat: downloads page loading table

* fix: table loading

* feat: using table and chart loading
  • Loading branch information
chinmehta authored Jan 15, 2025
1 parent 1dec32b commit 622d918
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 67 deletions.
15 changes: 4 additions & 11 deletions apps/platform/src/pages/DownloadsPage/DownloadsPage.jsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -183,21 +183,14 @@ function DownloadsPage() {
</Alert>
) : null}

{loadingDownloadsData && (
<Box display="flex" justifyContent="center">
<CircularProgress />
</Box>
)}

{loadingDownloadsData || loading || error ? null : (
{error ? null : (
<Paper variant="outlined" elevation={0}>
<Box m={2}>
<OtTable
showGlobalFilter
columns={columns}
rows={rows}
loading={loadingDownloadsData}
rowsPerPageOptions={defaultRowsPerPageOptions}
loading={loadingDownloadsData || loading}
/>
</Box>
</Paper>
Expand Down
1 change: 0 additions & 1 deletion packages/sections/src/study/GWASCredibleSets/Body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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={() => <Description studyId={request.data?.study.id} />}
renderBody={() => (
Expand Down
2 changes: 1 addition & 1 deletion packages/sections/src/variant/GWASCredibleSets/Body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ function getColumns({ id, referenceAllele, alternateAllele }: getColumnsType) {
filterValue: ({ confidence }) => credsetConfidenceMap[confidence],
},
{
id: "topL2G",
id: "l2Gpredictions",
label: "Top L2G",
filterValue: ({ l2GPredictions }) => l2GPredictions?.rows[0]?.target?.approvedSymbol,
tooltip: "Top gene prioritised by our locus-to-gene model",
Expand Down
4 changes: 2 additions & 2 deletions packages/sections/src/variant/InSilicoPredictors/Body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ export function Body({ id, entity }: BodyProps): ReactElement {
variables,
});

const rows = getSortedRows(request);

return (
<SectionItem
definition={definition}
Expand All @@ -84,7 +86,6 @@ export function Body({ id, entity }: BodyProps): ReactElement {
/>
)}
renderChart={() => {
const rows = getSortedRows(request);
return (
<InSilicoPredictorsVisualisation
data={rows}
Expand All @@ -95,7 +96,6 @@ export function Body({ id, entity }: BodyProps): ReactElement {
);
}}
renderBody={() => {
const rows = getSortedRows(request);
return (
<OtTable
columns={columns}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useRef, useEffect } from "react";
import * as PlotLib from "@observablehq/plot";
import { rgb } from "d3";
import { useMeasure } from "@uidotdev/usehooks";
import { Box, Fade, linkClasses } from "@mui/material";
import { Box, Fade, linkClasses, Skeleton } from "@mui/material";
import { grey } from "@mui/material/colors";
import { DataDownloader } from "ui";

Expand All @@ -20,8 +20,9 @@ const PRIORITISATION_COLORS = [
rgb("#2f735f"),
];

function InSilicoPredictorsPlot({ data, query, variables, columns }) {
function InSilicoPredictorsPlot({ data, query, variables, columns, loading }) {
const [ref, { width }] = useMeasure();
if (loading) return <Skeleton sx={{ height: 325 }} variant="rectangular" />;
return (
<div>
<Box>
Expand Down
38 changes: 24 additions & 14 deletions packages/ui/src/components/OtTable/OtTable.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -79,7 +79,6 @@ const searchFilter: FilterFn<any> = (row, columnId, value, addMeta) => {

function OtTable({
showGlobalFilter = true,
tableDataLoading = false,
columns = [],
rows = [],
verticalHeaders = false,
Expand All @@ -97,18 +96,25 @@ function OtTable({
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);

const mappedColumns = mapTableColumnToTanstackColumns(columns);
// const loadingRows = getLoadingRows(mappedColumns, 10);
const loadingRows = getLoadingRows(10);
const loadingCells = getLoadingCells(mappedColumns);

const tableData = useMemo(() => (loading ? loadingRows : rows), [loading]);
const tableColumns = useMemo(() => (loading ? loadingCells : mappedColumns), [loading]);

function getCellData(cell: Record<string, unknown>): 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),
Expand Down Expand Up @@ -208,11 +214,8 @@ function OtTable({
return (
<OtTD key={cell.id} stickyColumn={cell.column.columnDef.sticky}>
<OtTableCellContainer numeric={cell.column.columnDef.numeric}>
{table.getState().loading ? (
<Skeleton sx={{ minWidth: "50px" }} variant="text" />
) : (
<>{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} */}
Expand Down Expand Up @@ -241,11 +244,11 @@ function OtTable({
padding: theme => `${theme.spacing(2)} 0 `,
}}
>
{tableDataLoading && <CircularProgress sx={{ mx: theme => theme.spacing(2) }} size={25} />}
<div>
<span>Rows per page:</span>
<NativeSelect
disableUnderline
disabled={loading}
sx={{ pl: theme => theme.spacing(2) }}
value={table.getState().pagination.pageSize}
onChange={e => {
Expand Down Expand Up @@ -305,4 +308,11 @@ function OtTable({
);
}

function getLoadingCells(columms: Array<Record<string, unknown>>) {
return columms.map(column => ({
...column,
cell: () => <Skeleton sx={{ minWidth: "50px" }} variant="text" />,
}));
}

export default OtTable;
2 changes: 1 addition & 1 deletion packages/ui/src/components/OtTable/table.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export type OtTableProps = {
};

export type loadingTableRows = {
id: string;
id: Record<string, unknown>;
};

/*************************
Expand Down
11 changes: 4 additions & 7 deletions packages/ui/src/components/OtTable/tableUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, null> = {};
for (const e in columns) {
const item = columns[e].id;
rowObject[item] = null;
}
return new Array(size).fill(rowObject);
export function getLoadingRows(size = 10): loadingTableRows[] {
const rows = new Array(size).fill({});
console.log(rows);
return rows;
}

/***********************************
Expand Down
57 changes: 29 additions & 28 deletions packages/ui/src/components/Section/SectionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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 {
Expand All @@ -55,13 +55,39 @@ 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]);
}

if (!hasData && !showEmptySection && !loading) return null;

function getSelectedView(): ReactNode {
if (error) return <SectionError error={error} />;
if (showContentLoading && loading)
return (
<>
<Box sx={{ display: "flex", justifyContent: "center" }}>
{showDelayLoadingMessage && loadingMessage}
</Box>
<Skeleton sx={{ height: 390 }} variant="rectangular" />
</>
);
if (selectedView === VIEW.table) return renderBody();
if (selectedView === VIEW.chart) return renderChart();
// if (!loading && !hasData && showEmptySection)
return <div className={classes.noData}> No data available for this {entity}. </div>;
}

return (
<Grid item xs={12}>
<section>
Expand Down Expand Up @@ -109,32 +135,7 @@ function SectionItem({
</Box>
</Box>
<Divider />
<CardContent className={classes.cardContent}>
<>
{error && <SectionError error={error} />}
{showContentLoading &&
loading &&
(loadingMessage ? (
<Box
width="100%"
height={390}
bgcolor={theme => theme.palette.grey[100]}
display="flex"
flexDirection="column"
justifyContent="center"
>
<SummaryLoader message={loadingMessage} />
</Box>
) : (
<Skeleton sx={{ height: 390 }} variant="rectangular" />
))}
{hasData && selectedView === VIEW.table && renderBody()}
{hasData && selectedView === VIEW.chart && renderChart()}
{showEmptySection && (
<div className={classes.noData}> No data available for this {entity}. </div>
)}
</>
</CardContent>
<CardContent className={classes.cardContent}>{getSelectedView()}</CardContent>
</ErrorBoundary>
</Card>
</Element>
Expand Down

0 comments on commit 622d918

Please sign in to comment.