From 17a585e6295d651ae26ee01ecdb104d292712260 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Wed, 12 Oct 2022 10:45:18 +1100 Subject: [PATCH 01/26] clarify subTable url structure --- src/components/fields/SubTable/utils.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/fields/SubTable/utils.ts b/src/components/fields/SubTable/utils.ts index 1c1dcae0..e62e0a45 100644 --- a/src/components/fields/SubTable/utils.ts +++ b/src/components/fields/SubTable/utils.ts @@ -20,8 +20,7 @@ export const useSubTableData = ( location.pathname.split("/" + ROUTES.subTable)[0] ); - // const [searchParams] = useSearchParams(); - // const parentLabels = searchParams.get("parentLabel"); + // Get params from URL: /table/:tableId/subTable/:docPath/:subTableKey let subTablePath = [ rootTablePath, ROUTES.subTable, @@ -29,8 +28,6 @@ export const useSubTableData = ( column.key, ].join("/"); - // if (parentLabels) subTablePath += `${parentLabels ?? ""},${label ?? ""}`; - // else subTablePath += "?parentLabel=" + encodeURIComponent(label ?? ""); return { documentCount, label, subTablePath }; From bebde59147d807b272e3a184c4a46050422f1dad Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Wed, 12 Oct 2022 10:45:41 +1100 Subject: [PATCH 02/26] =?UTF-8?q?fix=20useOffline=20having=20incorrect=20s?= =?UTF-8?q?tate=20when=20listener=20isn=E2=80=99t=20fired?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useOffline.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hooks/useOffline.ts b/src/hooks/useOffline.ts index f5f09ce3..ad5cb199 100644 --- a/src/hooks/useOffline.ts +++ b/src/hooks/useOffline.ts @@ -1,11 +1,14 @@ import { useState, useEffect } from "react"; export default function useOffline() { - const [isOffline, setIsOffline] = useState(true); + const [isOffline, setIsOffline] = useState(false); const handleOffline = () => setIsOffline(true); const handleOnline = () => setIsOffline(false); useEffect(() => { + // Need to set here because the listener doesn’t fire on initial load + setIsOffline(!window.navigator.onLine); + window.addEventListener("offline", handleOffline); window.addEventListener("online", handleOnline); From a24f2bd227a617d031ff0df684bcb147d76b9b17 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Wed, 12 Oct 2022 10:46:48 +1100 Subject: [PATCH 03/26] DebugPage: fix animations --- src/pages/Settings/DebugPage.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/pages/Settings/DebugPage.tsx b/src/pages/Settings/DebugPage.tsx index d3ec7ad1..e5c64fa6 100644 --- a/src/pages/Settings/DebugPage.tsx +++ b/src/pages/Settings/DebugPage.tsx @@ -41,7 +41,7 @@ export default function DebugPage() { {userRoles.includes("ADMIN") && } - + - )} - - + {!hideCancel && ( + + )} + + + + ); } From 94e8a46c253136744b618596b95b4d164c942bce Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Wed, 19 Oct 2022 12:03:05 +1100 Subject: [PATCH 09/26] fix main content causing horizontal scroll --- src/layouts/Navigation/Navigation.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/Navigation/Navigation.tsx b/src/layouts/Navigation/Navigation.tsx index f17053a1..3f967301 100644 --- a/src/layouts/Navigation/Navigation.tsx +++ b/src/layouts/Navigation/Navigation.tsx @@ -62,7 +62,7 @@ export default function Navigation({ children }: React.PropsWithChildren<{}>) { } > -
+
{children}
From 23bf2876b25114ab9b57c6312bdcb64e404e91f8 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Thu, 20 Oct 2022 11:13:07 +1100 Subject: [PATCH 10/26] ConfirmDialog: fix command not typeable --- src/components/ConfirmDialog.tsx | 57 +++++++++++++++++++------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/src/components/ConfirmDialog.tsx b/src/components/ConfirmDialog.tsx index e9e210df..f7de2a03 100644 --- a/src/components/ConfirmDialog.tsx +++ b/src/components/ConfirmDialog.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; import { useAtom } from "jotai"; import { @@ -49,10 +49,15 @@ export default function ConfirmDialog({ const handleClose = () => { setState({ open: false }); - setDryText(""); + setDisableConfirm(false); }; - const [dryText, setDryText] = useState(""); + const [disableConfirm, setDisableConfirm] = useState( + Boolean(confirmationCommand) + ); + useEffect(() => { + setDisableConfirm(Boolean(confirmationCommand)); + }, [confirmationCommand]); return ( theme.zIndex.modal + 50 }} > - - <> + <> + {title} + + {typeof body === "string" ? ( {body} ) : ( body )} + {confirmationCommand && ( setDryText(e.target.value)} - autoFocus + onChange={(e) => + setDisableConfirm(e.target.value !== confirmationCommand) + } label={`Type “${confirmationCommand}” below to continue:`} placeholder={confirmationCommand} fullWidth @@ -87,16 +95,18 @@ export default function ConfirmDialog({ /> )} + - :not(:first-of-type)": { ml: 0, mt: 1 }, - }, - ]} - > + :not(:first-of-type)": { ml: 0, mt: 1 }, + }, + ]} + > + {!hideCancel && ( )} + + + - - - + + + ); } From 7a4bac367313e986d3f747d5c57a065e2579c805 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Thu, 20 Oct 2022 11:25:34 +1100 Subject: [PATCH 11/26] CircularProgressTimed: fix tick position in webkit --- src/components/CircularProgressTimed.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/CircularProgressTimed.tsx b/src/components/CircularProgressTimed.tsx index 11959f37..109a0963 100644 --- a/src/components/CircularProgressTimed.tsx +++ b/src/components/CircularProgressTimed.tsx @@ -71,6 +71,8 @@ export default function CircularProgressTimed({ sx={{ position: "absolute", inset: size * 0.33 * 0.5, + width: size * 0.67, + height: size * 0.67, "& .tick": { stroke: (theme) => theme.palette.success.main, From 7fa0955dce15001607d036e7989b4b1ab4011daf Mon Sep 17 00:00:00 2001 From: Shams Date: Thu, 20 Oct 2022 18:35:48 +1100 Subject: [PATCH 12/26] Merge pull request #10 from rowyio/feat/table-information Feat: Table Information Drawer --- src/assets/icons/index.ts | 3 + src/atoms/tableScope/ui.ts | 6 + .../TableInformationDrawer/Details.tsx | 178 ++++++++++++++++++ .../TableInformationDrawer/SideDrawer.tsx | 134 +++++++++++++ .../TableInformationDrawer/index.ts | 2 + .../TableInformationDrawer/withTemplate.tsx | 61 ++++++ .../TableSettingsDialog/TableDetails.tsx | 43 +++++ .../TableSettingsDialog.tsx | 26 ++- .../TableSettingsDialog/TableThumbnail.tsx | 126 +++++++++++++ src/components/TableSettingsDialog/form.tsx | 18 +- src/components/TableSettingsDialog/utils.ts | 14 ++ .../TableToolbar/TableInformation.tsx | 25 +++ src/components/TableToolbar/TableToolbar.tsx | 6 + src/components/Tables/TableGrid/TableCard.tsx | 63 ++++--- src/pages/Table/TablePage.tsx | 7 + src/pages/TablesPage.tsx | 15 +- .../useTableFunctions.ts | 8 +- src/types/table.d.ts | 12 ++ 18 files changed, 719 insertions(+), 28 deletions(-) create mode 100644 src/components/TableInformationDrawer/Details.tsx create mode 100644 src/components/TableInformationDrawer/SideDrawer.tsx create mode 100644 src/components/TableInformationDrawer/index.ts create mode 100644 src/components/TableInformationDrawer/withTemplate.tsx create mode 100644 src/components/TableSettingsDialog/TableDetails.tsx create mode 100644 src/components/TableSettingsDialog/TableThumbnail.tsx create mode 100644 src/components/TableSettingsDialog/utils.ts create mode 100644 src/components/TableToolbar/TableInformation.tsx diff --git a/src/assets/icons/index.ts b/src/assets/icons/index.ts index 3503e99b..4e60591f 100644 --- a/src/assets/icons/index.ts +++ b/src/assets/icons/index.ts @@ -103,6 +103,9 @@ export { FileTableBoxOutline as Project }; import { TableColumn } from "mdi-material-ui"; export { TableColumn }; +import { InformationOutline } from "mdi-material-ui"; +export { InformationOutline as TableInformation }; + export * from "./AddRow"; export * from "./AddRowTop"; export * from "./ChevronDown"; diff --git a/src/atoms/tableScope/ui.ts b/src/atoms/tableScope/ui.ts index fa987118..b5aaf882 100644 --- a/src/atoms/tableScope/ui.ts +++ b/src/atoms/tableScope/ui.ts @@ -121,6 +121,12 @@ export const importAirtableAtom = atom<{ tableId: string; }>({ airtableData: null, apiKey: "", baseId: "", tableId: "" }); +/** Store side drawer open state */ +export const sideDrawerAtom = atomWithHash<"table-information" | null>( + "sideDrawer", + null, + { replaceState: true } +); /** Store side drawer open state */ export const sideDrawerOpenAtom = atom(false); diff --git a/src/components/TableInformationDrawer/Details.tsx b/src/components/TableInformationDrawer/Details.tsx new file mode 100644 index 00000000..a3d4640d --- /dev/null +++ b/src/components/TableInformationDrawer/Details.tsx @@ -0,0 +1,178 @@ +import { useMemo } from "react"; +import { format } from "date-fns"; +import MDEditor from "@uiw/react-md-editor"; + +import { + Box, + Grid, + IconButton, + Stack, + Typography, + useTheme, +} from "@mui/material"; + +import EditIcon from "@mui/icons-material/EditOutlined"; + +import { tableScope, tableSettingsAtom } from "@src/atoms/tableScope"; +import { useAtom, useSetAtom } from "jotai"; +import { + projectScope, + tablesAtom, + tableSettingsDialogAtom, + userRolesAtom, +} from "@src/atoms/projectScope"; +import { find } from "lodash-es"; + +export interface IDetailsProps { + handleOpenTemplate?: any; +} + +export default function Details({ handleOpenTemplate }: IDetailsProps) { + const [userRoles] = useAtom(userRolesAtom, projectScope); + const [tableSettings] = useAtom(tableSettingsAtom, tableScope); + const [tables] = useAtom(tablesAtom, projectScope); + const openTableSettingsDialog = useSetAtom( + tableSettingsDialogAtom, + projectScope + ); + + const settings = useMemo( + () => find(tables, ["id", tableSettings.id]), + [tables, tableSettings.id] + ); + + const theme = useTheme(); + + if (!settings) { + return null; + } + + const editButton = userRoles.includes("ADMIN") && ( + + openTableSettingsDialog({ + mode: "update", + data: settings, + }) + } + disabled={!openTableSettingsDialog || settings.id.includes("/")} + > + + + ); + + const { description, details, _createdBy } = settings; + + return ( + .MuiGrid-root": { + position: "relative", + }, + }} + > + {/* Description */} + + + + Description + + {editButton} + + + {description ? description : "No description"} + + + + {/* Details */} + + + + Details + + {editButton} + + {!details ? ( + + No details + + ) : ( + + + + )} + + + {/* Table Audits */} + {_createdBy && ( + + + Created by{" "} + + {_createdBy.displayName} + {" "} + at{" "} + + {format(_createdBy.timestamp.toDate(), "LLL d, yyyy · p")} + + + + )} + + {/* Template Settings */} + {/* {handleOpenTemplate && ( + + + + + + ); +} diff --git a/src/components/TableSettingsDialog/form.tsx b/src/components/TableSettingsDialog/form.tsx index 7b62176b..190b02bf 100644 --- a/src/components/TableSettingsDialog/form.tsx +++ b/src/components/TableSettingsDialog/form.tsx @@ -244,7 +244,23 @@ export const tableSettings = ( type: FieldType.paragraph, name: "description", label: "Description (optional)", - minRows: 2, + }, + { + step: "display", + type: "tableDetails", + name: "details", + label: "Details (optional)", + }, + { + step: "display", + type: "tableThumbnail", + name: "thumbnailFile", + label: "Thumbnail Image (optional)", + }, + { + step: "display", + type: FieldType.hidden, + name: "thumbnailURL", }, // Step 3: Access controls diff --git a/src/components/TableSettingsDialog/utils.ts b/src/components/TableSettingsDialog/utils.ts new file mode 100644 index 00000000..b70cfe07 --- /dev/null +++ b/src/components/TableSettingsDialog/utils.ts @@ -0,0 +1,14 @@ +import { + FirebaseStorage, + getDownloadURL, + ref, + uploadBytes, +} from "firebase/storage"; + +export const uploadTableThumbnail = + (storage: FirebaseStorage) => (tableId: string, imageFile: File) => { + const storageRef = ref(storage, `__thumbnails__/${tableId}`); + return uploadBytes(storageRef, imageFile).then(({ ref }) => + getDownloadURL(ref) + ); + }; diff --git a/src/components/TableToolbar/TableInformation.tsx b/src/components/TableToolbar/TableInformation.tsx new file mode 100644 index 00000000..f53688f1 --- /dev/null +++ b/src/components/TableToolbar/TableInformation.tsx @@ -0,0 +1,25 @@ +import { useAtom } from "jotai"; +import { RESET } from "jotai/utils"; + +import { + sideDrawerAtom, + tableScope, + tableSettingsAtom, +} from "@src/atoms/tableScope"; + +import TableToolbarButton from "@src/components/TableToolbar/TableToolbarButton"; +import { TableInformation as TableInformationIcon } from "@src/assets/icons"; + +export default function TableInformation() { + const [tableSettings] = useAtom(tableSettingsAtom, tableScope); + const [sideDrawer, setSideDrawer] = useAtom(sideDrawerAtom, tableScope); + + return ( + } + onClick={() => setSideDrawer(sideDrawer ? RESET : "table-information")} + disabled={!setSideDrawer || tableSettings.id.includes("/")} + /> + ); +} diff --git a/src/components/TableToolbar/TableToolbar.tsx b/src/components/TableToolbar/TableToolbar.tsx index e940e92b..3e288a88 100644 --- a/src/components/TableToolbar/TableToolbar.tsx +++ b/src/components/TableToolbar/TableToolbar.tsx @@ -36,6 +36,9 @@ import { FieldType } from "@src/constants/fields"; const Filters = lazy(() => import("./Filters" /* webpackChunkName: "Filters" */)); // prettier-ignore const ImportData = lazy(() => import("./ImportData/ImportData" /* webpackChunkName: "ImportData" */)); +// prettier-ignore +const TableInformation = lazy(() => import("./TableInformation" /* webpackChunkName: "TableInformation" */)); + // prettier-ignore const ReExecute = lazy(() => import("./ReExecute" /* webpackChunkName: "ReExecute" */)); @@ -147,6 +150,9 @@ export default function TableToolbar() { )} + }> + +
); diff --git a/src/components/Tables/TableGrid/TableCard.tsx b/src/components/Tables/TableGrid/TableCard.tsx index 21be4ece..b601b90a 100644 --- a/src/components/Tables/TableGrid/TableCard.tsx +++ b/src/components/Tables/TableGrid/TableCard.tsx @@ -7,10 +7,9 @@ import { Typography, CardActions, Button, + Box, } from "@mui/material"; import { Go as GoIcon } from "@src/assets/icons"; - -import RenderedMarkdown from "@src/components/RenderedMarkdown"; import { TableSettings } from "@src/types/table"; export interface ITableCardProps extends TableSettings { @@ -19,6 +18,7 @@ export interface ITableCardProps extends TableSettings { } export default function TableCard({ + thumbnailURL, section, name, description, @@ -37,27 +37,46 @@ export default function TableCard({ - - - - (theme.typography.body2.lineHeight as number) * 2 + "em", - display: "flex", - flexDirection: "column", - gap: 1, - }} - component="div" - > - {description && ( - + + - )} - - + + + )} + {description && ( + + + {description} + + + )}