move ExportModal to TableModals

This commit is contained in:
Sidney Alcantara
2022-06-08 14:25:20 +10:00
parent 1c77c6f17d
commit d04c332d50
8 changed files with 183 additions and 191 deletions

View File

@@ -0,0 +1,172 @@
import { useState, useMemo } from "react";
import { useAtom, useSetAtom } from "jotai";
import { RESET } from "jotai/utils";
import { ITableModalProps } from "@src/components/TableModals/TableModals";
import {
query as firestoreQuery,
Query,
collection,
collectionGroup,
where,
orderBy,
limit,
} from "firebase/firestore";
import { DialogContent, Tab, Divider } from "@mui/material";
import TabContext from "@mui/lab/TabContext";
import TabList from "@mui/lab/TabList";
import TabPanel from "@mui/lab/TabPanel";
import Modal from "@src/components/Modal";
import ExportDetails from "./ModalContentsExport";
import DownloadDetails from "./ModalContentsDownload";
import { globalScope } from "@src/atoms/globalScope";
import {
tableScope,
tableSettingsAtom,
tableFiltersAtom,
tableOrdersAtom,
tableModalAtom,
} from "@src/atoms/tableScope";
import { firebaseDbAtom } from "@src/sources/ProjectSourceFirebase";
import { TableRow } from "@src/types/table";
export interface IExportModalContentsProps {
query: Query<TableRow>;
closeModal: () => void;
}
// TODO: Generalize and remove Firestore dependencies
export default function Export({ onClose }: ITableModalProps) {
const setModal = useSetAtom(tableModalAtom, tableScope);
const [mode, setMode] = useState<"Export" | "Download">("Export");
const [firebaseDb] = useAtom(firebaseDbAtom, globalScope);
const [tableSettings] = useAtom(tableSettingsAtom, tableScope);
const [tableFilters] = useAtom(tableFiltersAtom, tableScope);
const [tableOrders] = useAtom(tableOrdersAtom, tableScope);
const tableCollection = tableSettings.collection;
const isCollectionGroup = tableSettings.tableType === "collectionGroup";
const query = useMemo(() => {
const _path = tableCollection.replaceAll("~2F", "/") ?? "";
let collectionRef = isCollectionGroup
? (collectionGroup(firebaseDb, _path) as Query<TableRow>)
: (collection(firebaseDb, _path) as Query<TableRow>);
// add filters
const filters = tableFilters.map((filter) =>
where(filter.key, filter.operator, filter.value)
);
// optional order results
const orders = tableOrders.map((order) =>
orderBy(order.key, order.direction)
);
// TODO: paginate
return firestoreQuery(collectionRef, ...filters, ...orders, limit(10_000));
}, [
firebaseDb,
tableCollection,
isCollectionGroup,
tableFilters,
tableOrders,
]);
const handleClose = () => {
setModal(RESET);
setMode("Export");
};
return (
<TabContext value={mode}>
<Modal
onClose={handleClose}
sx={{
"& .MuiDialog-paper": {
maxWidth: { sm: 440 },
height: { sm: 640 },
},
}}
title={mode}
header={
<>
<DialogContent style={{ flexGrow: 0, flexShrink: 0 }}>
{tableFilters.length !== 0 || tableOrders.length !== 0
? "The filters and sorting applied to the table will be applied to the export"
: "No filters or sorting will be applied on the exported data"}
. Limited to 10,000 rows.
</DialogContent>
<TabList
onChange={(_, v) => setMode(v)}
indicatorColor="primary"
textColor="primary"
variant="fullWidth"
aria-label="Modal tabs"
action={(actions) =>
setTimeout(() => actions?.updateIndicator(), 200)
}
sx={{ mt: 1 }}
>
<Tab style={{ minWidth: 0 }} label="Export" value="Export" />
<Tab
style={{ minWidth: 0 }}
label="Download attachments"
value="Download"
/>
</TabList>
<Divider style={{ marginTop: -1 }} />
</>
}
ScrollableDialogContentProps={{
disableTopDivider: true,
disableBottomDivider: true,
}}
>
<TabPanel
value="Export"
sx={{
marginTop: "var(--dialog-contents-spacing)",
marginBottom: "calc(var(--dialog-spacing) * -1)",
padding: 0,
flexGrow: 1,
display: "flex",
flexDirection: "column",
height:
"calc(100% - var(--dialog-contents-spacing) + var(--dialog-spacing))",
"& > * + *": {
marginTop: "var(--dialog-contents-spacing)",
},
"&[hidden]": { display: "none" },
}}
>
<ExportDetails query={query} closeModal={handleClose} />
</TabPanel>
<TabPanel
value="Download"
sx={{
marginTop: "var(--dialog-contents-spacing)",
marginBottom: "calc(var(--dialog-spacing) * -1)",
padding: 0,
flexGrow: 1,
display: "flex",
flexDirection: "column",
height:
"calc(100% - var(--dialog-contents-spacing) + var(--dialog-spacing))",
"& > * + *": {
marginTop: "var(--dialog-contents-spacing)",
},
"&[hidden]": { display: "none" },
}}
>
<DownloadDetails query={query} closeModal={handleClose} />
</TabPanel>
</Modal>
</TabContext>
);
}

View File

@@ -0,0 +1,2 @@
export * from "./ExportModal";
export { default } from "./ExportModal";

View File

@@ -8,6 +8,8 @@ const CloudLogsModal = lazy(() => import("./CloudLogsModal" /* webpackChunkName:
// prettier-ignore
const ExtensionsModal = lazy(() => import("./ExtensionsModal" /* webpackChunkName: "TableModals-ExtensionsModal" */));
// prettier-ignore
const ExportModal = lazy(() => import("./ExportModal" /* webpackChunkName: "TableModals-ExportModal" */));
// prettier-ignore
const WebhooksModal = lazy(() => import("./WebhooksModal" /* webpackChunkName: "TableModals-WebhooksModal" */));
// prettier-ignore
const ImportExistingWizard = lazy(() => import("./ImportExistingWizard" /* webpackChunkName: "TableModals-ImportExistingWizard" */));
@@ -28,6 +30,7 @@ export default function TableModals() {
if (tableModal === "cloudLogs") return <CloudLogsModal onClose={onClose} />;
if (tableModal === "extensions") return <ExtensionsModal onClose={onClose} />;
if (tableModal === "webhooks") return <WebhooksModal onClose={onClose} />;
if (tableModal === "export") return <ExportModal onClose={onClose} />;
if (tableModal === "importExisting")
return <ImportExistingWizard onClose={onClose} />;
if (tableModal === "importCsv") return <ImportCsvWizard onClose={onClose} />;

View File

@@ -1,186 +0,0 @@
import { useState, useMemo } from "react";
import { useAtom } from "jotai";
import { RESET } from "jotai/utils";
import {
query as firestoreQuery,
Query,
collection,
collectionGroup,
where,
orderBy,
limit,
} from "firebase/firestore";
import { DialogContent, Tab, Divider } from "@mui/material";
import TabContext from "@mui/lab/TabContext";
import TabList from "@mui/lab/TabList";
import TabPanel from "@mui/lab/TabPanel";
import TableToolbarButton from "@src/components/TableToolbar/TableToolbarButton";
import { Export as ExportIcon } from "@src/assets/icons";
import Modal from "@src/components/Modal";
import ExportDetails from "./ModalContentsExport";
import DownloadDetails from "./ModalContentsDownload";
import { globalScope } from "@src/atoms/globalScope";
import {
tableScope,
tableSettingsAtom,
tableFiltersAtom,
tableOrdersAtom,
tableModalAtom,
} from "@src/atoms/tableScope";
import { firebaseDbAtom } from "@src/sources/ProjectSourceFirebase";
import { TableRow } from "@src/types/table";
export interface IExportModalContentsProps {
query: Query<TableRow>;
closeModal: () => void;
}
// TODO: Generalize and remove Firestore dependencies
export default function Export() {
const [modal, setModal] = useAtom(tableModalAtom, tableScope);
const open = modal === "export";
const setOpen = (open: boolean) => setModal(open ? "export" : RESET);
const [mode, setMode] = useState<"Export" | "Download">("Export");
const [firebaseDb] = useAtom(firebaseDbAtom, globalScope);
const [tableSettings] = useAtom(tableSettingsAtom, tableScope);
const [tableFilters] = useAtom(tableFiltersAtom, tableScope);
const [tableOrders] = useAtom(tableOrdersAtom, tableScope);
const tableCollection = tableSettings.collection;
const isCollectionGroup = tableSettings.tableType === "collectionGroup";
const query = useMemo(() => {
const _path = tableCollection.replaceAll("~2F", "/") ?? "";
let collectionRef = isCollectionGroup
? (collectionGroup(firebaseDb, _path) as Query<TableRow>)
: (collection(firebaseDb, _path) as Query<TableRow>);
// add filters
const filters = tableFilters.map((filter) =>
where(filter.key, filter.operator, filter.value)
);
// optional order results
const orders = tableOrders.map((order) =>
orderBy(order.key, order.direction)
);
// TODO: paginate
return firestoreQuery(collectionRef, ...filters, ...orders, limit(10_000));
}, [
firebaseDb,
tableCollection,
isCollectionGroup,
tableFilters,
tableOrders,
]);
const handleClose = () => {
setOpen(false);
setMode("Export");
};
return (
<>
<TableToolbarButton
title="Export/Download"
onClick={() => setOpen(true)}
icon={<ExportIcon />}
/>
{open && (
<TabContext value={mode}>
<Modal
onClose={handleClose}
sx={{
"& .MuiDialog-paper": {
maxWidth: { sm: 440 },
height: { sm: 640 },
},
}}
title={mode}
header={
<>
<DialogContent style={{ flexGrow: 0, flexShrink: 0 }}>
{tableFilters.length !== 0 || tableOrders.length !== 0
? "The filters and sorting applied to the table will be applied to the export"
: "No filters or sorting will be applied on the exported data"}
. Limited to 10,000 rows.
</DialogContent>
<TabList
onChange={(_, v) => setMode(v)}
indicatorColor="primary"
textColor="primary"
variant="fullWidth"
aria-label="Modal tabs"
action={(actions) =>
setTimeout(() => actions?.updateIndicator(), 200)
}
sx={{ mt: 1 }}
>
<Tab style={{ minWidth: 0 }} label="Export" value="Export" />
<Tab
style={{ minWidth: 0 }}
label="Download attachments"
value="Download"
/>
</TabList>
<Divider style={{ marginTop: -1 }} />
</>
}
ScrollableDialogContentProps={{
disableTopDivider: true,
disableBottomDivider: true,
}}
>
<TabPanel
value="Export"
sx={{
marginTop: "var(--dialog-contents-spacing)",
marginBottom: "calc(var(--dialog-spacing) * -1)",
padding: 0,
flexGrow: 1,
display: "flex",
flexDirection: "column",
height:
"calc(100% - var(--dialog-contents-spacing) + var(--dialog-spacing))",
"& > * + *": {
marginTop: "var(--dialog-contents-spacing)",
},
"&[hidden]": { display: "none" },
}}
>
<ExportDetails query={query} closeModal={handleClose} />
</TabPanel>
<TabPanel
value="Download"
sx={{
marginTop: "var(--dialog-contents-spacing)",
marginBottom: "calc(var(--dialog-spacing) * -1)",
padding: 0,
flexGrow: 1,
display: "flex",
flexDirection: "column",
height:
"calc(100% - var(--dialog-contents-spacing) + var(--dialog-spacing))",
"& > * + *": {
marginTop: "var(--dialog-contents-spacing)",
},
"&[hidden]": { display: "none" },
}}
>
<DownloadDetails query={query} closeModal={handleClose} />
</TabPanel>
</Modal>
</TabContext>
)}
</>
);
}

View File

@@ -1,2 +0,0 @@
export * from "./Export";
export { default } from "./Export";

View File

@@ -4,6 +4,7 @@ import { useAtom, useSetAtom } from "jotai";
import { Stack } from "@mui/material";
import WebhookIcon from "@mui/icons-material/Webhook";
import {
Export as ExportIcon,
Extension as ExtensionIcon,
CloudLogs as CloudLogsIcon,
} from "@src/assets/icons";
@@ -34,8 +35,6 @@ import { FieldType } from "@src/constants/fields";
// prettier-ignore
const Filters = lazy(() => import("./Filters" /* webpackChunkName: "Filters" */));
// prettier-ignore
const Export = lazy(() => import("./Export" /* webpackChunkName: "Export" */));
// prettier-ignore
const ImportCsv = lazy(() => import("./ImportCsv" /* webpackChunkName: "ImportCsv" */));
// prettier-ignore
const ReExecute = lazy(() => import("./ReExecute" /* webpackChunkName: "ReExecute" */));
@@ -101,7 +100,11 @@ export default function TableToolbar() {
</Suspense>
)}
<Suspense fallback={<ButtonSkeleton />}>
<Export />
<TableToolbarButton
title="Export/Download"
onClick={() => openTableModal("export")}
icon={<ExportIcon />}
/>
</Suspense>
{userRoles.includes("ADMIN") && (
<>