diff --git a/client/src/webpages/dashboard/components/table/Table.test.tsx b/client/src/webpages/dashboard/components/table/Table.test.tsx index 74ce24e4..5f7c6c85 100644 --- a/client/src/webpages/dashboard/components/table/Table.test.tsx +++ b/client/src/webpages/dashboard/components/table/Table.test.tsx @@ -349,6 +349,54 @@ describe('Table behavior', () => { expectAllRowsVisible(); }); + it('prunes staged filters when their columns are removed', () => { + const nameColumn = { + ...columns[0], + meta: { filter: filterFor('name', 'Filter names') }, + filterFn: 'text', + } satisfies TableColumnDef; + const statusColumn = { + ...columns[1], + meta: { filter: filterFor('status', 'Filter statuses') }, + filterFn: 'text', + } satisfies TableColumnDef; + const { rerender } = renderTable([nameColumn, statusColumn]); + + fireEvent.click(screen.getByRole('button', { name: /filter/i })); + const filterMenu = screen + .getByRole('button', { name: 'Save' }) + .closest('.absolute'); + expect(filterMenu).not.toBeNull(); + fireEvent.click(within(filterMenu!).getByText('Name')); + fireEvent.change(screen.getByPlaceholderText('Filter names'), { + target: { value: 'alp' }, + }); + + rerender( + + + , + ); + fireEvent.click(screen.getByRole('button', { name: 'Save' })); + + rerender( + +
+ , + ); + fireEvent.click(screen.getByRole('button', { name: /filter/i })); + const restoredFilterMenu = screen + .getByRole('button', { name: 'Save' }) + .closest('.absolute'); + expect(restoredFilterMenu).not.toBeNull(); + if (!screen.queryByPlaceholderText('Filter names')) { + fireEvent.click(within(restoredFilterMenu!).getByText('Name')); + } + expect( + screen.getByPlaceholderText('Filter names').value, + ).toBe(''); + }); + it('renders links and selects a clicked row using its raw data', () => { const onSelectRow = vi.fn(); renderTable(columns, { diff --git a/client/src/webpages/dashboard/components/table/TableFilter.tsx b/client/src/webpages/dashboard/components/table/TableFilter.tsx index 9598e62c..0be78b41 100644 --- a/client/src/webpages/dashboard/components/table/TableFilter.tsx +++ b/client/src/webpages/dashboard/components/table/TableFilter.tsx @@ -72,10 +72,17 @@ export default function TableFilter(props: { }; const onSave = () => { + const missingColumnIds: string[] = []; for (const [columnId, value] of Object.entries(unsavedFilterValues)) { - filterColumns - .find((column) => column.id === columnId)! - .setFilterValue(value); + const column = filterColumns.find((column) => column.id === columnId); + if (!column) { + missingColumnIds.push(columnId); + continue; + } + column.setFilterValue(value); + } + if (missingColumnIds.length > 0) { + setUnsavedFilterValues(omit(unsavedFilterValues, missingColumnIds)); } setMenuVisible(false); }; @@ -92,9 +99,10 @@ export default function TableFilter(props: { const removeFilter = (columnId: string) => { setUnsavedFilterValues(omit(unsavedFilterValues, columnId)); - filterColumns - .find((column) => column.id === columnId)! - .setFilterValue(undefined); + const column = filterColumns.find((column) => column.id === columnId); + if (column) { + column.setFilterValue(undefined); + } }; const activeFilters = filterColumns.filter((column) =>