fix: added save button to table component to improve consistency (#6663)

* Added onSave and onCancel to tableModal, in order for it to preserve state

* Changed TableNodeComponent to handle temp values and only change value when saved

* 🔧 (tableModal/index.tsx): refactor handleSetOpen and handleOnEscapeKeyDown functions to improve code readability and maintainability

* Fix test that use tableInput

---------

Co-authored-by: cristhianzl <cristhian.lousa@gmail.com>
This commit is contained in:
Lucas Oliveira 2025-02-18 17:50:27 -03:00 • committed by GitHub
commit 70bb897a85
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 62 additions and 14 deletions

View file

@ -65,10 +65,12 @@ export default function TableNodeComponent({
}; };
}, []); }, []);
const [selectedNodes, setSelectedNodes] = useState<Array<any>>([]); const [selectedNodes, setSelectedNodes] = useState<Array<any>>([]);
const [tempValue, setTempValue] = useState<any[]>(cloneDeep(value));
const [isModalOpen, setIsModalOpen] = useState(false);
const agGrid = useRef<AgGridReact>(null); const agGrid = useRef<AgGridReact>(null);
const componentColumns = columns const componentColumns = columns
? columns ? columns
: generateBackendColumnsFromValue(value ?? [], table_options); : generateBackendColumnsFromValue(tempValue ?? [], table_options);
let AgColumns = FormatColumns(componentColumns); let AgColumns = FormatColumns(componentColumns);
// add info to each column // add info to each column
AgColumns = AgColumns.map((col) => { AgColumns = AgColumns.map((col) => {
@ -93,7 +95,7 @@ export default function TableNodeComponent({
if (agGrid.current && !agGrid.current.api.isDestroyed()) { if (agGrid.current && !agGrid.current.api.isDestroyed()) {
const rows: any = []; const rows: any = [];
agGrid.current.api.forEachNode((node) => rows.push(node.data)); agGrid.current.api.forEachNode((node) => rows.push(node.data));
handleOnNewValue({ value: rows }); setTempValue(rows);
} }
} }
function deleteRow() { function deleteRow() {
@ -109,8 +111,7 @@ export default function TableNodeComponent({
if (agGrid.current && selectedNodes.length > 0) { if (agGrid.current && selectedNodes.length > 0) {
const toDuplicate = selectedNodes.map((node) => cloneDeep(node.data)); const toDuplicate = selectedNodes.map((node) => cloneDeep(node.data));
setSelectedNodes([]); setSelectedNodes([]);
const rows: any = []; setTempValue([...tempValue, ...toDuplicate]);
handleOnNewValue({ value: [...value, ...toDuplicate] });
} }
} }
function addRow() { function addRow() {
@ -118,12 +119,23 @@ export default function TableNodeComponent({
componentColumns.forEach((column) => { componentColumns.forEach((column) => {
newRow[column.name] = column.default ?? null; // Use the default value if available newRow[column.name] = column.default ?? null; // Use the default value if available
}); });
handleOnNewValue({ value: [...value, newRow] }); setTempValue([...tempValue, newRow]);
} }
function updateComponent() { function updateComponent() {
setAllRows(); setAllRows();
} }
function handleSave() {
handleOnNewValue({ value: tempValue });
setIsModalOpen(false);
}
function handleCancel() {
setTempValue(cloneDeep(value));
setIsModalOpen(false);
}
const editable = componentColumns const editable = componentColumns
.map((column) => { .map((column) => {
const isCustomEdit = const isCustomEdit =
@ -149,6 +161,8 @@ export default function TableNodeComponent({
> >
<div className="flex w-full items-center gap-3" data-testid={"div-" + id}> <div className="flex w-full items-center gap-3" data-testid={"div-" + id}>
<TableModal <TableModal
open={isModalOpen}
setOpen={setIsModalOpen}
stopEditingWhenCellsLoseFocus={true} stopEditingWhenCellsLoseFocus={true}
tableIcon={table_icon} tableIcon={table_icon}
tableOptions={table_options} tableOptions={table_options}
@ -169,8 +183,10 @@ export default function TableNodeComponent({
displayEmptyAlert={false} displayEmptyAlert={false}
className="h-full w-full" className="h-full w-full"
columnDefs={AgColumns} columnDefs={AgColumns}
rowData={value} rowData={tempValue}
context={{ field_parsers: table_options?.field_parsers }} context={{ field_parsers: table_options?.field_parsers }}
onSave={handleSave}
onCancel={handleCancel}
> >
<Button <Button
disabled={disabled} disabled={disabled}

View file

@ -15,6 +15,10 @@ interface TableModalProps extends TableComponentProps {
tableOptions?: TableOptionsTypeAPI; tableOptions?: TableOptionsTypeAPI;
hideColumns?: boolean | string[]; hideColumns?: boolean | string[];
tableIcon?: string; tableIcon?: string;
open?: boolean;
setOpen?: (open: boolean) => void;
onSave?: () => void;
onCancel?: () => void;
} }
const TableModal = forwardRef<AgGridReact, TableModalProps>( const TableModal = forwardRef<AgGridReact, TableModalProps>(
@ -25,22 +29,43 @@ const TableModal = forwardRef<AgGridReact, TableModalProps>(
children, children,
disabled, disabled,
tableIcon, tableIcon,
open,
setOpen,
onSave,
onCancel,
...props ...props
}: TableModalProps, }: TableModalProps,
ref: ForwardedRef<AgGridReact>, ref: ForwardedRef<AgGridReact>,
) => { ) => {
const handleSetOpen = (newOpen: boolean) => {
if (!newOpen && onCancel) {
onCancel();
}
if (setOpen) {
setOpen(newOpen);
}
};
const handleOnEscapeKeyDown = (e: KeyboardEvent) => {
const editingCells = (
ref as React.RefObject<AgGridReact>
)?.current?.api?.getEditingCells();
if (editingCells && editingCells.length > 0) {
e.preventDefault();
}
};
return ( return (
<BaseModal <BaseModal
onEscapeKeyDown={(e) => { onEscapeKeyDown={(e) => {
if ( handleOnEscapeKeyDown(e);
(
ref as React.RefObject<AgGridReact>
)?.current?.api.getEditingCells().length
) {
e.preventDefault();
}
}} }}
disable={disabled} disable={disabled}
open={open}
setOpen={(newOpen) => {
handleSetOpen(newOpen);
}}
> >
<BaseModal.Trigger asChild>{children}</BaseModal.Trigger> <BaseModal.Trigger asChild>{children}</BaseModal.Trigger>
<BaseModal.Header <BaseModal.Header
@ -59,6 +84,9 @@ const TableModal = forwardRef<AgGridReact, TableModalProps>(
{...props} {...props}
></TableComponent> ></TableComponent>
</BaseModal.Content> </BaseModal.Content>
<BaseModal.Footer
submit={onSave ? { label: "Save", onClick: onSave } : undefined}
></BaseModal.Footer>
</BaseModal> </BaseModal>
); );
}, },

View file

@ -25,6 +25,10 @@ test(
}, },
); );
await page.waitForSelector('[data-testid="zoom_out"]', {
timeout: 3000,
});
await page.getByTestId("sidebar-custom-component-button").click(); await page.getByTestId("sidebar-custom-component-button").click();
await page.getByTestId("zoom_out").click(); await page.getByTestId("zoom_out").click();
@ -164,7 +168,7 @@ class CustomComponent(Component):
numberOfCopiedRows = await page.getByText(thirdRandomText).count(); numberOfCopiedRows = await page.getByText(thirdRandomText).count();
expect(numberOfCopiedRows).toBe(0); expect(numberOfCopiedRows).toBe(0);
await page.getByText("Close").last().click(); await page.getByText("Save").last().click();
await page.waitForSelector("text=Open table", { await page.waitForSelector("text=Open table", {
timeout: 3000, timeout: 3000,