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

CRDCDH-603 Batch File List #256

Merged
merged 24 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4f327ab
Updated batch table context and small table styling
Alejandro-Vega Dec 26, 2023
eef3db5
Created FileListDialog for Batch Table
Alejandro-Vega Dec 26, 2023
9207d74
Added FileListDialog to Batch Table
Alejandro-Vega Dec 26, 2023
f0c01ca
Merge branch 'mvp-2.1.0' of https://github.com/CBIIT/crdc-datahub-ui …
Alejandro-Vega Jan 3, 2024
bd963cc
Rename batches state
Alejandro-Vega Jan 3, 2024
3d7def1
Added defaultOrder to GenericTable and loading height
Alejandro-Vega Jan 3, 2024
9a44ba9
Added listBatchFiles query and types
Alejandro-Vega Jan 3, 2024
9385c64
Updated FileListDialog to use API and updated design
Alejandro-Vega Jan 3, 2024
4e8153d
Merge branch 'CRDCDH-660' of https://github.com/CBIIT/crdc-datahub-ui…
Alejandro-Vega Jan 3, 2024
00192e8
Added displayID to FileListDialog
Alejandro-Vega Jan 3, 2024
c938e9f
Added time to date
Alejandro-Vega Jan 4, 2024
834d6ac
Merge branch 'mvp-2.1.0' into CRDCDH-603
Alejandro-Vega Jan 4, 2024
d2ac594
Added missing border to GenericTable. Also adjusted loading content
Alejandro-Vega Jan 4, 2024
ffa285c
Merge branch 'CRDCDH-603' of https://github.com/CBIIT/crdc-datahub-ui…
Alejandro-Vega Jan 4, 2024
8123694
Merge branch 'mvp-2.1.0' of https://github.com/CBIIT/crdc-datahub-ui …
Alejandro-Vega Jan 11, 2024
f51164e
Removed listBatchFiles query
Alejandro-Vega Jan 11, 2024
06f1972
Added nodeType to listBatches files and type
Alejandro-Vega Jan 11, 2024
4b3c0cd
Created utility function for paginateAndSort for client side
Alejandro-Vega Jan 11, 2024
2e012a0
Updated FileListDialog to use client side pagination and sorting
Alejandro-Vega Jan 11, 2024
b372d2c
Added ability to add props to table container. Updated table styling
Alejandro-Vega Jan 11, 2024
265824a
Added prop to specify pagination placement
Alejandro-Vega Jan 11, 2024
e25ed61
Remove dialog max height
Alejandro-Vega Jan 12, 2024
0cb299a
Added scroll body
Alejandro-Vega Jan 12, 2024
ad64f6d
fix: Recenter button
amattu2 Jan 12, 2024
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
84 changes: 51 additions & 33 deletions src/components/DataSubmissions/GenericTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
TableCell,
TableCellProps,
TableContainer,
TableContainerProps,
TableHead,
TablePagination,
TablePaginationProps,
Expand All @@ -13,20 +14,22 @@ import {
Typography,
styled,
} from "@mui/material";
import { ElementType, forwardRef, useEffect, useImperativeHandle, useMemo, useState } from "react";
import { CSSProperties, ElementType, forwardRef, useEffect, useImperativeHandle, useMemo, useState } from "react";
import { useAuthContext } from "../Contexts/AuthContext";
import PaginationActions from "./PaginationActions";
import SuspenseLoader from '../SuspenseLoader';

const StyledTableContainer = styled(TableContainer)({
borderRadius: "8px",
border: 0,
border: "1px solid #6CACDA",
marginBottom: "25px",
position: "relative",
overflowX: "auto",
overflowY: "hidden",
"& .MuiTableRow-root:nth-of-type(2n)": {
background: "#E3EEF9",
},
" .MuiTableCell-root:first-of-type": {
"& .MuiTableCell-root:first-of-type": {
paddingLeft: "40.44px",
},
"& .MuiTableCell-root:last-of-type": {
Expand Down Expand Up @@ -74,11 +77,11 @@ const StyledTableCell = styled(TableCell)({
},
});

const StyledTablePagination = styled(TablePagination)<
TablePaginationProps & { component: ElementType }
>({
"& .MuiTablePagination-displayedRows, & .MuiTablePagination-selectLabel, & .MuiTablePagination-select":
{
const StyledTablePagination = styled(TablePagination, {
shouldForwardProp: (prop) => prop !== "placement"
})<TablePaginationProps & { component: ElementType; placement: CSSProperties["justifyContent"]; }>(
({ placement }) => ({
"& .MuiTablePagination-displayedRows, & .MuiTablePagination-selectLabel, & .MuiTablePagination-select": {
height: "27px",
display: "flex",
alignItems: "center",
Expand All @@ -93,24 +96,31 @@ const StyledTablePagination = styled(TablePagination)<
lineHeight: "14.913px",
letterSpacing: "0.14px",
},
"& .MuiToolbar-root .MuiInputBase-root": {
height: "27px",
marginLeft: 0,
marginRight: "16px",
},
"& .MuiToolbar-root p": {
marginTop: 0,
marginBottom: 0,
},
"& .MuiToolbar-root": {
minHeight: "45px",
height: "fit-content",
paddingTop: "7px",
paddingBottom: "6px",
borderTop: "2px solid #083A50",
background: "#F5F7F8",
},
});
"& .MuiToolbar-root .MuiInputBase-root": {
height: "27px",
marginLeft: 0,
marginRight: "16px",
},
"& .MuiToolbar-root p": {
marginTop: 0,
marginBottom: 0,
},
"& .MuiToolbar-root": {
minHeight: "45px",
height: "fit-content",
paddingTop: "7px",
paddingBottom: "6px",
borderTop: "2px solid #083A50",
background: "#F5F7F8",
...(placement && {
justifyContent: placement,
"& .MuiTablePagination-spacer": {
display: "none"
}
})
},
})
);

export type Order = "asc" | "desc";

Expand Down Expand Up @@ -140,34 +150,41 @@ type Props<T> = {
total: number;
loading?: boolean;
noContentText?: string;
defaultOrder?: Order;
defaultRowsPerPage?: number;
paginationPlacement?: CSSProperties["justifyContent"];
containerProps?: TableContainerProps;
setItemKey?: (item: T, index: number) => string;
onFetchData?: (params: FetchListing<T>, force: boolean) => void;
onOrderChange?: (order: Order) => void;
onOrderByChange?: (orderBy: Column<T>) => void;
onPerPageChange?: (perPage: number) => void;
};

const DataSubmissionBatchTable = <T,>({
const GenericTable = <T,>({
columns,
data,
total = 0,
loading,
noContentText,
defaultOrder = "desc",
defaultRowsPerPage = 10,
paginationPlacement,
containerProps,
setItemKey,
onFetchData,
onOrderChange,
onOrderByChange,
onPerPageChange,
}: Props<T>, ref: React.Ref<TableMethods>) => {
const { user } = useAuthContext();
const [order, setOrder] = useState<Order>("desc");
const [order, setOrder] = useState<Order>(defaultOrder);
const [orderBy, setOrderBy] = useState<Column<T>>(
columns.find((c) => c.default) || columns.find((c) => c.field)
);
const [page, setPage] = useState<number>(0);
const [perPage, setPerPage] = useState<number>(defaultRowsPerPage);
const numRowsNoContent = 10;

useEffect(() => {
fetchData();
Expand Down Expand Up @@ -219,7 +236,7 @@ const DataSubmissionBatchTable = <T,>({
};

return (
<StyledTableContainer>
<StyledTableContainer {...containerProps}>
{loading && (<SuspenseLoader fullscreen={false} />)}
<Table>
<StyledTableHead>
Expand All @@ -242,7 +259,7 @@ const DataSubmissionBatchTable = <T,>({
</TableRow>
</StyledTableHead>
<TableBody>
{loading ? Array.from(Array(perPage).keys())?.map((_, idx) => (
{loading && total === 0 ? Array.from(Array(numRowsNoContent).keys())?.map((_, idx) => (
<StyledTableRow key={`loading_row_${idx}`}>
<TableCell colSpan={columns.length} />
</StyledTableRow>
Expand Down Expand Up @@ -271,7 +288,7 @@ const DataSubmissionBatchTable = <T,>({

{/* No content message */}
{!loading && (!total || total === 0) && (
<TableRow style={{ height: 46 * 10 }}>
<TableRow style={{ height: 46 * numRowsNoContent }}>
<TableCell colSpan={columns.length}>
<Typography
variant="h6"
Expand All @@ -294,6 +311,7 @@ const DataSubmissionBatchTable = <T,>({
page={page}
onPageChange={(e, newPage) => setPage(newPage - 1)}
onRowsPerPageChange={handleChangeRowsPerPage}
placement={paginationPlacement}
nextIconButtonProps={{
disabled: perPage === -1
|| !data
Expand All @@ -310,6 +328,6 @@ const DataSubmissionBatchTable = <T,>({
);
};

const BatchTableWithRef = forwardRef(DataSubmissionBatchTable) as <T>(props: Props<T> & { ref?: React.Ref<TableMethods> }) => ReturnType<typeof DataSubmissionBatchTable>;
const TableWithRef = forwardRef(GenericTable) as <T>(props: Props<T> & { ref?: React.Ref<TableMethods> }) => ReturnType<typeof GenericTable>;

export default BatchTableWithRef;
export default TableWithRef;
11 changes: 11 additions & 0 deletions src/config/TableConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Order } from "../components/DataSubmissions/GenericTable";

export const SORT: { [key in Order as Uppercase<Order>]: Order } = {
ASC: "asc",
DESC: "desc",
};

export const DIRECTION: { [key in Order as Uppercase<Order>]: number } = {
ASC: 1,
DESC: -1,
};
1 change: 1 addition & 0 deletions src/content/dataSubmissions/Contexts/BatchTableContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";

const BatchTableContext = React.createContext<{
handleOpenErrorDialog?:(data: Batch) => void;
handleOpenFileListDialog?:(data: Batch) => void;
}>({});

export default BatchTableContext;
68 changes: 57 additions & 11 deletions src/content/dataSubmissions/DataSubmission.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import BatchTableContext from "./Contexts/BatchTableContext";
import DataSubmissionStatistics from '../../components/DataSubmissions/ValidationStatistics';
import ValidationControls from '../../components/DataSubmissions/ValidationControls';
import { useAuthContext } from "../../components/Contexts/AuthContext";
import FileListDialog from "./FileListDialog";
import { shouldDisableSubmit } from "../../utils/dataSubmissionUtils";

const StyledBanner = styled("div")(({ bannerSrc }: { bannerSrc: string }) => ({
Expand Down Expand Up @@ -224,6 +225,23 @@ const StyledErrorDetailsButton = styled(Button)(() => ({
},
}));

const StyledFileCountButton = styled(Button)(() => ({
color: "#0D78C5",
fontFamily: "Inter",
fontSize: "16px",
fontStyle: "normal",
fontWeight: 600,
lineHeight: "19px",
textDecorationLine: "underline",
textTransform: "none",
padding: 0,
justifyContent: "flex-start",
"&:hover": {
background: "transparent",
textDecorationLine: "underline",
},
}));

const columns: Column<Batch>[] = [
{
label: "Batch ID",
Expand All @@ -242,7 +260,23 @@ const columns: Column<Batch>[] = [
},
{
label: "File Count",
renderValue: (data) => Intl.NumberFormat("en-US", { maximumFractionDigits: 0 }).format(data?.fileCount || 0),
renderValue: (data) => (
<BatchTableContext.Consumer>
{({ handleOpenFileListDialog }) => (
<StyledFileCountButton
onClick={() => handleOpenFileListDialog && handleOpenFileListDialog(data)}
variant="text"
disableRipple
disableTouchRipple
disableFocusRipple
>
{Intl.NumberFormat("en-US", { maximumFractionDigits: 0 }).format(
data?.fileCount || 0
)}
</StyledFileCountButton>
)}
</BatchTableContext.Consumer>
),
field: "fileCount",
},
{
Expand Down Expand Up @@ -298,13 +332,14 @@ const DataSubmission = () => {
const { submissionId, tab } = useParams();
const { user } = useAuthContext();

const [batchFiles, setBatchFiles] = useState<Batch[]>([]);
const [totalBatchFiles, setTotalBatchFiles] = useState<number>(0);
const [batches, setBatches] = useState<Batch[]>([]);
const [totalBatches, setTotalBatches] = useState<number>(0);
const [prevBatchFetch, setPrevBatchFetch] = useState<FetchListing<Batch>>(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const [changesAlert, setChangesAlert] = useState<AlertState>(null);
const [openErrorDialog, setOpenErrorDialog] = useState<boolean>(false);
const [openFileListDialog, setOpenFileListDialog] = useState<boolean>(false);
const [selectedRow, setSelectedRow] = useState<Batch | null>(null);

const {
Expand Down Expand Up @@ -344,13 +379,13 @@ const DataSubmission = () => {
fetchPolicy: 'no-cache'
});

const handleFetchBatchFiles = async (fetchListing: FetchListing<Batch>, force: boolean) => {
const handleFetchBatches = async (fetchListing: FetchListing<Batch>, force: boolean) => {
const { first, offset, sortDirection, orderBy } = fetchListing || {};
if (!submissionId) {
setError("Invalid submission ID provided.");
return;
}
if (!force && batchFiles?.length > 0 && isEqual(fetchListing, prevBatchFetch)) {
if (!force && batches?.length > 0 && isEqual(fetchListing, prevBatchFetch)) {
return;
}

Expand All @@ -373,8 +408,8 @@ const DataSubmission = () => {
setError("Unable to retrieve batch data.");
return;
}
setBatchFiles(newBatchFiles.listBatches.batches);
setTotalBatchFiles(newBatchFiles.listBatches.total);
setBatches(newBatchFiles.listBatches.batches);
setTotalBatches(newBatchFiles.listBatches.total);
} catch (err) {
setError("Unable to retrieve batch data.");
} finally {
Expand Down Expand Up @@ -431,6 +466,11 @@ const DataSubmission = () => {
setSelectedRow(data);
};

const handleOpenFileListDialog = (data: Batch) => {
setOpenFileListDialog(true);
setSelectedRow(data);
};

const handleOnValidate = (status: boolean) => {
if (!status) {
return;
Expand All @@ -440,7 +480,8 @@ const DataSubmission = () => {
};

const providerValue = useMemo(() => ({
handleOpenErrorDialog
handleOpenErrorDialog,
handleOpenFileListDialog
}), [handleOpenErrorDialog]);

useEffect(() => {
Expand Down Expand Up @@ -515,11 +556,11 @@ const DataSubmission = () => {
<GenericTable
ref={tableRef}
columns={columns}
data={batchFiles || []}
total={totalBatchFiles || 0}
data={batches || []}
total={totalBatches || 0}
loading={loading}
defaultRowsPerPage={20}
onFetchData={handleFetchBatchFiles}
onFetchData={handleFetchBatches}
/>
</BatchTableContext.Provider>
) : <QualityControl />}
Expand All @@ -545,6 +586,11 @@ const DataSubmission = () => {
errors={selectedRow?.errors}
uploadedDate={data?.getSubmission?.createdAt}
/>
<FileListDialog
open={openFileListDialog}
batch={selectedRow}
onClose={() => setOpenFileListDialog(false)}
/>
</StyledWrapper>
);
};
Expand Down
Loading