portainer/app/react/components/datatables/editable/EditableDatatable.tsx

86 lines
2.2 KiB
TypeScript

import { useCallback, useEffect, useRef, useState } from 'react';
import { mergeOptions } from '@@/datatables/extend-options/mergeOptions';
import { withMeta } from '@@/datatables/extend-options/withMeta';
import {
Datatable,
Props as DatatableProps,
PaginationProps,
} from '../Datatable';
import { DefaultType } from '../types';
export const NEW_ROW_ID = -1;
export const NEW_ROW_INDEX = 0;
export const UNSET_EDITABLE_ROW = -1;
interface Props<D extends DefaultType> extends Omit<DatatableProps<D>, 'meta'> {
revertRow(): void;
acceptRow(): void;
}
export function EditableDatatable<D extends DefaultType>({
dataset,
revertRow,
acceptRow,
...props
}: Props<D> & PaginationProps) {
const [autoResetPageIndex, skipAutoResetPageIndex] = useSkipper();
const [data, setData] = useState(dataset);
const [editableRow, setEditableRow] = useState(-1);
const [editableRowOriginalData, setEditableRowOriginalData] = useState<
D | undefined
>();
useEffect(() => {
setData(dataset);
}, [dataset]);
return (
<Datatable<D>
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
dataset={data}
extendTableOptions={mergeOptions(
(options) => ({
...options,
autoResetPageIndex,
}),
withMeta({
getEditableRow: () => editableRow,
getEditableRowOriginalData: () => editableRowOriginalData,
editRow: (rowIndex: number, row: D) => {
setEditableRow(rowIndex);
setEditableRowOriginalData(row);
},
updateRow: (rowIndex: number, value: D) => {
// Skip page index reset until after next rerender
skipAutoResetPageIndex();
setData((old: D[]) =>
old.map((row, index) => (index === rowIndex ? value : row))
);
},
revertRow,
acceptRow,
})
)}
/>
);
}
function useSkipper() {
const shouldSkipRef = useRef(true);
const shouldSkip = shouldSkipRef.current;
// Wrap a function with this to skip a pagination reset temporarily
const skip = useCallback(() => {
shouldSkipRef.current = false;
}, []);
useEffect(() => {
shouldSkipRef.current = true;
});
return [shouldSkip, skip] as const;
}