mirror of
https://github.com/rowyio/rowy.git
synced 2025-12-29 00:16:39 +01:00
move ExportModal to TableModals
This commit is contained in:
172
src/components/TableModals/ExportModal/ExportModal.tsx
Normal file
172
src/components/TableModals/ExportModal/ExportModal.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
2
src/components/TableModals/ExportModal/index.ts
Normal file
2
src/components/TableModals/ExportModal/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./ExportModal";
|
||||
export { default } from "./ExportModal";
|
||||
@@ -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} />;
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from "./Export";
|
||||
export { default } from "./Export";
|
||||
@@ -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") && (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user