diff --git a/src/Providers.tsx b/src/Providers.tsx
index c30e05f4..c71630fa 100644
--- a/src/Providers.tsx
+++ b/src/Providers.tsx
@@ -5,6 +5,7 @@ import { BrowserRouter } from "react-router-dom";
import { HelmetProvider } from "react-helmet-async";
import { Provider, Atom } from "jotai";
import { globalScope } from "@src/atoms/globalScope";
+import { DebugAtoms } from "@src/atoms/utils";
import LocalizationProvider from "@mui/lab/LocalizationProvider";
import AdapterDateFns from "@mui/lab/AdapterDateFns";
import createCache from "@emotion/cache";
@@ -36,6 +37,7 @@ export default function Providers({
scope={globalScope}
initialValues={initialAtomValues}
>
+
diff --git a/src/atoms/tableScope/ui.ts b/src/atoms/tableScope/ui.ts
index 25aecd2a..aca5aae6 100644
--- a/src/atoms/tableScope/ui.ts
+++ b/src/atoms/tableScope/ui.ts
@@ -5,6 +5,12 @@ import type { PopoverProps } from "@mui/material";
import type { ColumnConfig, TableFilter } from "@src/types/table";
import { SEVERITY_LEVELS } from "@src/components/TableToolbar/CloudLogs/CloudLogSeverityIcon";
+function beforeUnloadHandler(event: BeforeUnloadEvent) {
+ event.preventDefault();
+ return (event.returnValue =
+ "Are you sure you want to leave? You may have unsaved changes.");
+}
+
/**
* Open table column menu. Set to `null` to close.
*
@@ -36,7 +42,8 @@ export const columnMenuAtom = atom<{
*
* @example Close:
* ```
- * openColumnModal(null)
+ * import { RESET } from "jotai/utils";
+ * openColumnModal(RESET)
* ```
*/
export const columnModalAtom = atomWithHash<{
diff --git a/src/atoms/utils.ts b/src/atoms/utils.ts
new file mode 100644
index 00000000..7903ca86
--- /dev/null
+++ b/src/atoms/utils.ts
@@ -0,0 +1,9 @@
+import { Scope } from "jotai/core/atom";
+import { useAtomsDebugValue } from "jotai/devtools";
+
+export function DebugAtoms(
+ options: { scope: Scope } & Parameters[0]
+) {
+ useAtomsDebugValue(options);
+ return null;
+}
diff --git a/src/components/ColumnModals/ColumnModals.tsx b/src/components/ColumnModals/ColumnModals.tsx
index d7f00489..1d20a536 100644
--- a/src/components/ColumnModals/ColumnModals.tsx
+++ b/src/components/ColumnModals/ColumnModals.tsx
@@ -1,4 +1,5 @@
import { useAtom } from "jotai";
+import { RESET } from "jotai/utils";
import NewColumnModal from "./NewColumnModal";
import NameChangeModal from "./NameChangeModal";
@@ -23,7 +24,7 @@ export default function ColumnModals() {
if (!columnModal) return null;
- const handleClose = () => setColumnModal(null);
+ const handleClose = () => setColumnModal(RESET);
if (columnModal.type === "new")
return ;
diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx
index 3b291ddf..bfb7146b 100644
--- a/src/components/Table/Table.tsx
+++ b/src/components/Table/Table.tsx
@@ -274,16 +274,21 @@ export default function Table({
value,
});
}}
- onSelectedCellChange={({ rowIdx, idx }) =>
- setSelectedCell({
- path: rows[rowIdx]._rowy_ref.path,
- columnKey: tableColumnsOrdered.filter((col) =>
- userDocHiddenFields
- ? !userDocHiddenFields.includes(col.key)
- : true
- )[idx].key,
- })
- }
+ onSelectedCellChange={({ rowIdx, idx }) => {
+ if (!rows[rowIdx]?._rowy_ref) return; // May be the header row
+
+ const path = rows[rowIdx]._rowy_ref.path;
+ if (!path) return;
+
+ const columnKey = tableColumnsOrdered.filter((col) =>
+ userDocHiddenFields
+ ? !userDocHiddenFields.includes(col.key)
+ : true
+ )[idx]?.key;
+ if (!columnKey) return; // May be the final column
+
+ setSelectedCell({ path, columnKey });
+ }}
/>
diff --git a/src/components/TableToolbar/CloudLogs/CloudLogs.tsx b/src/components/TableToolbar/CloudLogs/CloudLogs.tsx
index 0b215329..1316339f 100644
--- a/src/components/TableToolbar/CloudLogs/CloudLogs.tsx
+++ b/src/components/TableToolbar/CloudLogs/CloudLogs.tsx
@@ -1,4 +1,5 @@
import { useAtom, useSetAtom } from "jotai";
+import { RESET } from "jotai/utils";
import TableToolbarButton from "@src/components/TableToolbar/TableToolbarButton";
import { CloudLogs as LogsIcon } from "@src/assets/icons";
@@ -17,7 +18,7 @@ export default function CloudLogs() {
const [modal, setModal] = useAtom(tableModalAtom, tableScope);
const open = modal === "cloudLogs";
- const setOpen = (open: boolean) => setModal(open ? "cloudLogs" : null);
+ const setOpen = (open: boolean) => setModal(open ? "cloudLogs" : RESET);
return (
<>
diff --git a/src/components/TableToolbar/Export/Export.tsx b/src/components/TableToolbar/Export/Export.tsx
index d8a2619e..9e20e705 100644
--- a/src/components/TableToolbar/Export/Export.tsx
+++ b/src/components/TableToolbar/Export/Export.tsx
@@ -1,5 +1,6 @@
import { useState, useMemo } from "react";
import { useAtom } from "jotai";
+import { RESET } from "jotai/utils";
import {
query as firestoreQuery,
Query,
@@ -42,7 +43,7 @@ export interface IExportModalContentsProps {
export default function Export() {
const [modal, setModal] = useAtom(tableModalAtom, tableScope);
const open = modal === "export";
- const setOpen = (open: boolean) => setModal(open ? "export" : null);
+ const setOpen = (open: boolean) => setModal(open ? "export" : RESET);
const [mode, setMode] = useState<"Export" | "Download">("Export");
const [firebaseDb] = useAtom(firebaseDbAtom, globalScope);
diff --git a/src/components/TableToolbar/Extensions/Extensions.tsx b/src/components/TableToolbar/Extensions/Extensions.tsx
index c4b4881b..b5b2e29a 100644
--- a/src/components/TableToolbar/Extensions/Extensions.tsx
+++ b/src/components/TableToolbar/Extensions/Extensions.tsx
@@ -1,5 +1,6 @@
import { useState } from "react";
import { useAtom, useSetAtom } from "jotai";
+import { RESET } from "jotai/utils";
import { isEqual } from "lodash-es";
import TableToolbarButton from "@src/components/TableToolbar/TableToolbarButton";
@@ -50,7 +51,7 @@ export default function Extensions() {
);
const open = modal === "extensions";
- const setOpen = (open: boolean) => setModal(open ? "extensions" : null);
+ const setOpen = (open: boolean) => setModal(open ? "extensions" : RESET);
const [openMigrationGuide, setOpenMigrationGuide] = useState(false);
const [extensionModal, setExtensionModal] = useState<{
diff --git a/src/components/TableToolbar/Webhooks/Webhooks.tsx b/src/components/TableToolbar/Webhooks/Webhooks.tsx
index 48566b1b..c8079703 100644
--- a/src/components/TableToolbar/Webhooks/Webhooks.tsx
+++ b/src/components/TableToolbar/Webhooks/Webhooks.tsx
@@ -1,5 +1,6 @@
import { useState } from "react";
import { useAtom, useSetAtom } from "jotai";
+import { RESET } from "jotai/utils";
import { isEqual } from "lodash-es";
import { useSnackbar } from "notistack";
@@ -50,7 +51,7 @@ export default function Webhooks() {
useState(currentWebhooks);
const open = modal === "webhooks";
- const setOpen = (open: boolean) => setModal(open ? "webhooks" : null);
+ const setOpen = (open: boolean) => setModal(open ? "webhooks" : RESET);
const [webhookModal, setWebhookModal] = useState<{
mode: "add" | "update";
diff --git a/src/index.tsx b/src/index.tsx
index f4d7b2c9..5d545f47 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -8,11 +8,11 @@ import reportWebVitals from "./reportWebVitals";
const container = document.getElementById("root")!;
const root = createRoot(container);
root.render(
- //
-
-
-
- //
+
+
+
+
+
);
// If you want to start measuring performance in your app, pass a function
diff --git a/src/pages/Table.tsx b/src/pages/Table.tsx
index b053036e..c6b5caa0 100644
--- a/src/pages/Table.tsx
+++ b/src/pages/Table.tsx
@@ -1,5 +1,6 @@
import { useRef, Suspense } from "react";
import { useAtom, Provider } from "jotai";
+import { DebugAtoms } from "@src/atoms/utils";
import { useParams } from "react-router-dom";
import { DataGridHandle } from "react-data-grid";
import { isEmpty } from "lodash-es";
@@ -89,6 +90,7 @@ export default function ProvidedTablePage() {
[currentUserAtom, currentUser],
]}
>
+