mirror of
https://github.com/rowyio/rowy.git
synced 2025-12-29 00:16:39 +01:00
show save state for column sizing
This commit is contained in:
@@ -68,10 +68,11 @@ import { formatSubTableName } from "@src/utils/table";
|
||||
import { TableRow, ColumnConfig } from "@src/types/table";
|
||||
import { StyledCell } from "./Styled/StyledCell";
|
||||
import { useKeyboardNavigation } from "./useKeyboardNavigation";
|
||||
import { useSaveColumnSizing } from "./useSaveColumnSizing";
|
||||
|
||||
export const DEFAULT_ROW_HEIGHT = 41;
|
||||
export const DEFAULT_COL_WIDTH = 150;
|
||||
export const MIN_COL_WIDTH = 32;
|
||||
export const MIN_COL_WIDTH = 80;
|
||||
export const TABLE_PADDING = 16;
|
||||
export const TABLE_GUTTER = 8;
|
||||
export const DEBOUNCE_DELAY = 500;
|
||||
@@ -84,8 +85,6 @@ const columnHelper = createColumnHelper<TableRow>();
|
||||
const getRowId = (row: TableRow) => row._rowy_ref.path || row._rowy_ref.id;
|
||||
|
||||
export default function TableComponent() {
|
||||
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
|
||||
|
||||
const [userRoles] = useAtom(userRolesAtom, projectScope);
|
||||
const [userSettings] = useAtom(userSettingsAtom, projectScope);
|
||||
|
||||
@@ -199,43 +198,7 @@ export default function TableComponent() {
|
||||
onColumnSizingChange: setColumnSizing,
|
||||
}));
|
||||
|
||||
// Debounce for saving to schema
|
||||
const [debouncedColumnSizing] = useDebounce(columnSizing, DEBOUNCE_DELAY, {
|
||||
equalityFn: isEqual,
|
||||
});
|
||||
// Offer to save when column sizing changes
|
||||
useEffect(() => {
|
||||
if (!canEditColumn || isEmpty(debouncedColumnSizing)) return;
|
||||
|
||||
const snackbarId = enqueueSnackbar("Save column sizes for all users?", {
|
||||
action: (
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleSaveToSchema}
|
||||
>
|
||||
Save
|
||||
</LoadingButton>
|
||||
),
|
||||
anchorOrigin: { horizontal: "center", vertical: "top" },
|
||||
});
|
||||
|
||||
async function handleSaveToSchema() {
|
||||
const promises = Object.entries(debouncedColumnSizing).map(
|
||||
([key, value]) => updateColumn({ key, config: { width: value } })
|
||||
);
|
||||
await Promise.all(promises);
|
||||
closeSnackbar(snackbarId);
|
||||
}
|
||||
|
||||
return () => closeSnackbar(snackbarId);
|
||||
}, [
|
||||
debouncedColumnSizing,
|
||||
canEditColumn,
|
||||
enqueueSnackbar,
|
||||
closeSnackbar,
|
||||
updateColumn,
|
||||
]);
|
||||
useSaveColumnSizing(columnSizing, canEditColumn);
|
||||
|
||||
const { rows } = table.getRowModel();
|
||||
const leafColumns = table.getVisibleLeafColumns();
|
||||
|
||||
@@ -138,3 +138,5 @@ export function useKeyboardNavigation({
|
||||
|
||||
return { handleKeyDown, focusInsideCell } as const;
|
||||
}
|
||||
|
||||
export default useKeyboardNavigation;
|
||||
|
||||
102
src/components/Table/useSaveColumnSizing.tsx
Normal file
102
src/components/Table/useSaveColumnSizing.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useSetAtom } from "jotai";
|
||||
import { useSnackbar } from "notistack";
|
||||
import { useDebounce } from "use-debounce";
|
||||
import { isEqual, isEmpty } from "lodash-es";
|
||||
|
||||
import LoadingButton from "@mui/lab/LoadingButton";
|
||||
import CheckIcon from "@mui/icons-material/Check";
|
||||
import CircularProgressOptical from "@src/components/CircularProgressOptical";
|
||||
|
||||
import {
|
||||
tableScope,
|
||||
updateColumnAtom,
|
||||
IUpdateColumnOptions,
|
||||
} from "@src/atoms/tableScope";
|
||||
import { DEBOUNCE_DELAY } from "./Table";
|
||||
import { ColumnSizingState } from "@tanstack/react-table";
|
||||
|
||||
/** Debounces columnSizing and asks admins if they want to save for all users */
|
||||
export function useSaveColumnSizing(
|
||||
columnSizing: ColumnSizingState,
|
||||
canEditColumn: boolean
|
||||
) {
|
||||
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
|
||||
const updateColumn = useSetAtom(updateColumnAtom, tableScope);
|
||||
|
||||
// Debounce for saving to schema
|
||||
const [debouncedColumnSizing] = useDebounce(columnSizing, DEBOUNCE_DELAY, {
|
||||
equalityFn: isEqual,
|
||||
});
|
||||
// Offer to save when column sizing changes
|
||||
useEffect(() => {
|
||||
if (!canEditColumn || isEmpty(debouncedColumnSizing)) return;
|
||||
|
||||
const snackbarId = enqueueSnackbar("Save column sizes for all users?", {
|
||||
action: (
|
||||
<SaveColumnSizingButton
|
||||
debouncedColumnSizing={debouncedColumnSizing}
|
||||
updateColumn={updateColumn}
|
||||
/>
|
||||
),
|
||||
anchorOrigin: { horizontal: "center", vertical: "top" },
|
||||
});
|
||||
|
||||
return () => closeSnackbar(snackbarId);
|
||||
}, [
|
||||
debouncedColumnSizing,
|
||||
canEditColumn,
|
||||
enqueueSnackbar,
|
||||
closeSnackbar,
|
||||
updateColumn,
|
||||
]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
interface ISaveColumnSizingButtonProps {
|
||||
debouncedColumnSizing: ColumnSizingState;
|
||||
updateColumn: (update: IUpdateColumnOptions) => Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the button a component so it can have its own state,
|
||||
* so we can display the loading state without showing a new snackbar
|
||||
*/
|
||||
function SaveColumnSizingButton({
|
||||
debouncedColumnSizing,
|
||||
updateColumn,
|
||||
}: ISaveColumnSizingButtonProps) {
|
||||
const [state, setState] = useState<"" | "loading" | "success">("");
|
||||
|
||||
const handleSaveToSchema = async () => {
|
||||
setState("loading");
|
||||
// Do this one by one for now to prevent race conditions.
|
||||
// Need to support updating multiple columns in updateColumnAtom
|
||||
// in the future.
|
||||
for (const [key, value] of Object.entries(debouncedColumnSizing)) {
|
||||
await updateColumn({ key, config: { width: value } });
|
||||
}
|
||||
setState("success");
|
||||
};
|
||||
|
||||
return (
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleSaveToSchema}
|
||||
loading={Boolean(state)}
|
||||
loadingIndicator={
|
||||
state === "success" ? (
|
||||
<CheckIcon color="primary" />
|
||||
) : (
|
||||
<CircularProgressOptical size={20} color="primary" />
|
||||
)
|
||||
}
|
||||
>
|
||||
Save
|
||||
</LoadingButton>
|
||||
);
|
||||
}
|
||||
|
||||
export default useSaveColumnSizing;
|
||||
Reference in New Issue
Block a user