diff --git a/src/components/Table/Column.tsx b/src/components/Table/Column.tsx index c916eeb4..11996145 100644 --- a/src/components/Table/Column.tsx +++ b/src/components/Table/Column.tsx @@ -4,6 +4,8 @@ import { alpha } from "@mui/material/styles"; import { FieldType } from "@src/constants/fields"; import { getFieldProp } from "@src/components/fields"; +export const COLUMN_HEADER_HEIGHT = 42; + export interface IColumnProps extends Partial { label: string; type?: FieldType; @@ -29,7 +31,7 @@ export default function Column({ sx={[ { width: "100%", - height: 42, + height: COLUMN_HEADER_HEIGHT, border: (theme) => `1px solid ${theme.palette.divider}`, backgroundColor: "background.default", diff --git a/src/components/Table/ColumnHeader/ColumnHeader.tsx b/src/components/Table/ColumnHeader/ColumnHeader.tsx index 22d36d1d..95e4cf17 100644 --- a/src/components/Table/ColumnHeader/ColumnHeader.tsx +++ b/src/components/Table/ColumnHeader/ColumnHeader.tsx @@ -26,10 +26,12 @@ import { import { tableScope, updateColumnAtom } from "@src/atoms/tableScope"; import { FieldType } from "@src/constants/fields"; import { getFieldProp } from "@src/components/fields"; -import { DEFAULT_ROW_HEIGHT } from "@src/components/Table"; +import { COLUMN_HEADER_HEIGHT } from "@src/components/Table/Column"; import { ColumnConfig } from "@src/types/table"; import useKeyPress from "@src/hooks/useKeyPress"; +export { COLUMN_HEADER_HEIGHT }; + const LightTooltip = styled(({ className, ...props }: TooltipProps) => ( ))(({ theme }) => ({ @@ -37,7 +39,7 @@ const LightTooltip = styled(({ className, ...props }: TooltipProps) => ( backgroundColor: theme.palette.background.default, color: theme.palette.text.primary, - margin: `-${DEFAULT_ROW_HEIGHT - 2}px 0 0 !important`, + margin: `-${COLUMN_HEADER_HEIGHT - 1 - 2}px 0 0 !important`, padding: 0, paddingRight: theme.spacing(1.5), }, @@ -83,6 +85,7 @@ export default function DraggableHeaderRenderer({ return ( { dragRef(ref); dropRef(ref); @@ -164,7 +167,7 @@ export default function DraggableHeaderRenderer({ sx={{ typography: "caption", fontWeight: "fontWeightMedium", - lineHeight: `${DEFAULT_ROW_HEIGHT - 1 - 4}px`, + lineHeight: `${COLUMN_HEADER_HEIGHT - 2 - 4}px`, textOverflow: "clip", }} color="inherit" @@ -182,7 +185,7 @@ export default function DraggableHeaderRenderer({ sx={{ typography: "caption", fontWeight: "fontWeightMedium", - lineHeight: `${DEFAULT_ROW_HEIGHT + 1}px`, + lineHeight: `${COLUMN_HEADER_HEIGHT}px`, textOverflow: "clip", }} component="div" diff --git a/src/components/Table/EmptyTable.tsx b/src/components/Table/EmptyTable.tsx index b9893dd5..935e715d 100644 --- a/src/components/Table/EmptyTable.tsx +++ b/src/components/Table/EmptyTable.tsx @@ -1,9 +1,10 @@ -import { useAtom } from "jotai"; +import { useAtom, useSetAtom } from "jotai"; import { Grid, Stack, Typography, Button, Divider } from "@mui/material"; import ImportIcon from "@src/assets/icons/Import"; import AddColumnIcon from "@src/assets/icons/AddColumn"; +import { globalScope, columnModalAtom } from "@src/atoms/globalScope"; import { tableScope, tableSettingsAtom, @@ -17,6 +18,8 @@ import { APP_BAR_HEIGHT } from "@src/layouts/Navigation"; // import ImportCSV from "@src/components/TableToolbar/ImportCsv"; export default function EmptyTable() { + const openColumnModal = useSetAtom(columnModalAtom, globalScope); + const [tableSettings] = useAtom(tableSettingsAtom, tableScope); const [tableRows] = useAtom(tableRowsAtom, tableScope); // const { tableState, importWizardRef, columnMenuRef } = useProjectContext(); @@ -115,19 +118,10 @@ export default function EmptyTable() { variant="contained" color="primary" startIcon={} - // onClick={(event) => - // columnMenuRef?.current?.setSelectedColumnHeader({ - // column: { isNew: true, key: "new", type: "LAST" } as any, - // anchorEl: event.currentTarget, - // }) - // } - // disabled={!columnMenuRef?.current} - disabled + onClick={() => openColumnModal({ type: "new" })} > Add column - - {/* */} diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index a0925b62..a7abd01a 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -1,8 +1,7 @@ import React, { useRef, useMemo, useState } from "react"; -import { find, difference, get } from "lodash-es"; +import { find, difference } from "lodash-es"; import { useAtom, useSetAtom } from "jotai"; import { useDebouncedCallback } from "use-debounce"; - import { DndProvider } from "react-dnd"; import { HTML5Backend } from "react-dnd-html5-backend"; @@ -11,14 +10,18 @@ import DataGrid, { Column, // SelectColumn as _SelectColumn, } from "react-data-grid"; +import { LinearProgress } from "@mui/material"; import TableContainer, { OUT_OF_ORDER_MARGIN } from "./TableContainer"; -import ColumnHeader from "./ColumnHeader"; +import ColumnHeader, { COLUMN_HEADER_HEIGHT } from "./ColumnHeader"; // import ContextMenu from "./ContextMenu"; import FinalColumnHeader from "./FinalColumnHeader"; import FinalColumn from "./formatters/FinalColumn"; import TableRow from "./TableRow"; +import EmptyState from "@src/components/EmptyState"; // import BulkActions from "./BulkActions"; +import AddRow from "@src/components/TableToolbar/AddRow"; +import AddRowIcon from "@src/assets/icons/AddRow"; import { globalScope, @@ -152,7 +155,7 @@ export default function Table() { // { ...row } // ) // ); - }, [columns, tableRows]) ?? []; + }, [tableRows]) ?? []; const rowsContainerRef = useRef(null); const [selectedRowsSet, setSelectedRowsSet] = useState>(); @@ -166,8 +169,6 @@ export default function Table() { const isAtBottom = target.clientHeight + target.scrollTop >= target.scrollHeight - offset; if (!isAtBottom) return; - // Prevent calling more rows when they’ve already been called - if (tableLoadingMore) return; // Call for the next page setTablePageAtom((p) => p + 1); }; @@ -271,6 +272,26 @@ export default function Table() { // } /> + + {tableRows.length === 0 && ( + +
+ + + } + style={{ + position: "absolute", + inset: 0, + top: COLUMN_HEADER_HEIGHT, + height: "auto", + }} + /> + )} + {tableLoadingMore && } {/* diff --git a/src/components/Table/TableContainer.tsx b/src/components/Table/TableContainer.tsx index 8d8f46e9..7b939a0c 100644 --- a/src/components/Table/TableContainer.tsx +++ b/src/components/Table/TableContainer.tsx @@ -13,6 +13,7 @@ export const TableContainer = styled("div", { shouldForwardProp: (prop) => prop !== "rowHeight", })<{ rowHeight: number }>(({ theme, rowHeight }) => ({ display: "flex", + position: "relative", flexDirection: "column", height: `calc(100vh - ${APP_BAR_HEIGHT}px - ${TABLE_TOOLBAR_HEIGHT}px)`, diff --git a/src/components/TableToolbar/Filters/Filters.tsx b/src/components/TableToolbar/Filters/Filters.tsx index e95d05a9..f7ca3267 100644 --- a/src/components/TableToolbar/Filters/Filters.tsx +++ b/src/components/TableToolbar/Filters/Filters.tsx @@ -85,7 +85,6 @@ export default function Filters() { // Set the local table filter useEffect(() => { - console.log("Filters effect"); // Set local state for UI setTableQuery( Array.isArray(tableFilters) && tableFilters[0] diff --git a/src/components/TableToolbar/ImportCsv.tsx b/src/components/TableToolbar/ImportCsv.tsx index 7a8464c7..53e3dfcc 100644 --- a/src/components/TableToolbar/ImportCsv.tsx +++ b/src/components/TableToolbar/ImportCsv.tsx @@ -180,6 +180,8 @@ export default function ImportCsv({ render, PopoverProps }: IImportCsvProps) { title="Import CSV or TSV" onClick={handleOpen} icon={} + // FIXME: + disabled /> )} diff --git a/src/components/TableToolbar/LoadedRowsStatus.tsx b/src/components/TableToolbar/LoadedRowsStatus.tsx index 4f96a35d..6bec483c 100644 --- a/src/components/TableToolbar/LoadedRowsStatus.tsx +++ b/src/components/TableToolbar/LoadedRowsStatus.tsx @@ -1,6 +1,7 @@ +import { Suspense, forwardRef } from "react"; import { useAtom } from "jotai"; -import { Tooltip, Typography } from "@mui/material"; +import { Tooltip, Typography, TypographyProps } from "@mui/material"; import { tableScope, @@ -10,7 +11,23 @@ import { } from "@src/atoms/tableScope"; import { COLLECTION_PAGE_SIZE } from "@src/config/db"; -export default function LoadedRowsStatus() { +const StatusText = forwardRef(function StatusText( + props: TypographyProps, + ref: React.Ref +) { + return ( + + ); +}); + +function LoadedRowsStatus() { const [tableRows] = useAtom(tableRowsAtom, tableScope); const [tableLoadingMore] = useAtom(tableLoadingMoreAtom, tableScope); const [tablePage] = useAtom(tablePageAtom, tableScope); @@ -18,23 +35,28 @@ export default function LoadedRowsStatus() { const allLoaded = !tableLoadingMore && tableRows.length < COLLECTION_PAGE_SIZE * tablePage; + if (tableLoadingMore) return Loading more…; + return ( - + Loaded {allLoaded && "all "} {tableRows.length} row{tableRows.length !== 1 && "s"} - + ); } + +export default function SuspendedLoadedRowsStatus() { + return ( + Loading…}> + + + ); +} diff --git a/src/hooks/useFirestoreCollectionWithAtom.ts b/src/hooks/useFirestoreCollectionWithAtom.ts index 4a6c0992..d5ed02f3 100644 --- a/src/hooks/useFirestoreCollectionWithAtom.ts +++ b/src/hooks/useFirestoreCollectionWithAtom.ts @@ -130,6 +130,7 @@ export function useFirestoreCollectionWithAtom( isLastPage || queryEqual(next?.query as any, prev?.query as any) ); + // Create listener useEffect(() => { // If path is invalid and no memoizedQuery was created, don’t continue if (!memoizedQuery) return; @@ -244,7 +245,6 @@ export function useFirestoreCollectionWithAtom( setUpdateDocAtom, deleteDocAtom, setDeleteDocAtom, - loadingMoreAtom, ]); } diff --git a/src/pages/Table.tsx b/src/pages/Table.tsx index ed8a7116..bb6fd7b9 100644 --- a/src/pages/Table.tsx +++ b/src/pages/Table.tsx @@ -28,11 +28,17 @@ function TablePage() { if (isEmpty(tableSchema.columns)) return ( - -
- -
-
+ + +
+ + + + + +
+
+
); return ( @@ -45,7 +51,7 @@ function TablePage() { - + diff --git a/src/theme/components.tsx b/src/theme/components.tsx index c43f2385..4cd6a7ba 100644 --- a/src/theme/components.tsx +++ b/src/theme/components.tsx @@ -1224,7 +1224,7 @@ export const components = (theme: Theme): ThemeOptions => { MuiAvatar: { styleOverrides: { root: { - ...theme.typography.button, + fontWeight: theme.typography.fontWeightMedium, }, colorDefault: { backgroundColor: theme.palette.action.selected,