From c30716a073d0147fe85ddb1102429d04f6a4d6df Mon Sep 17 00:00:00 2001 From: Victor Marin <36818606+mdvictor@users.noreply.github.com> Date: Tue, 25 Oct 2022 08:32:16 +0300 Subject: [PATCH] TablePanel: Fix updating footer values on data change (#57518) * TablePanel: Fix updating footer values on data change * tests --- .../src/components/Table/Table.test.tsx | 190 ++++++++++++++++++ .../grafana-ui/src/components/Table/Table.tsx | 2 +- 2 files changed, 191 insertions(+), 1 deletion(-) diff --git a/packages/grafana-ui/src/components/Table/Table.test.tsx b/packages/grafana-ui/src/components/Table/Table.test.tsx index 7bcc94b3bd7..bd11b19bde1 100644 --- a/packages/grafana-ui/src/components/Table/Table.test.tsx +++ b/packages/grafana-ui/src/components/Table/Table.test.tsx @@ -207,5 +207,195 @@ describe('Table', () => { // 3 + header row expect(within(getTable()).getAllByRole('row')).toHaveLength(4); }); + + it('should redo footer calculations', async () => { + getTestContext({ + footerOptions: { show: true, reducer: ['sum'] }, + data: toDataFrame({ + name: 'A', + fields: [ + { + name: 'number', + type: FieldType.number, + values: [1, 1, 1, 2, 2], + config: { + custom: { + filterable: true, + }, + }, + }, + ], + }), + }); + + expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('7'); + + await userEvent.click(within(getColumnHeader(/number/)).getByRole('button', { name: '' })); + await userEvent.click(screen.getByLabelText('1')); + await userEvent.click(screen.getByText('Ok')); + + expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('3'); + }); + + it('should filter rows and recalculate footer values when multiple filter values are selected', async () => { + getTestContext({ + footerOptions: { show: true, reducer: ['sum'] }, + data: toDataFrame({ + name: 'A', + fields: [ + { + name: 'number', + type: FieldType.number, + values: [1, 1, 1, 2, 2, 3, 3], + config: { + custom: { + filterable: true, + }, + }, + }, + ], + }), + }); + + expect(within(getTable()).getAllByRole('row')).toHaveLength(8); + expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('13'); + + await userEvent.click(within(getColumnHeader(/number/)).getByRole('button', { name: '' })); + await userEvent.click(screen.getByLabelText('2')); + await userEvent.click(screen.getByLabelText('3')); + await userEvent.click(screen.getByText('Ok')); + + //4 + header row + expect(within(getTable()).getAllByRole('row')).toHaveLength(5); + expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('10'); + }); + + it('should reset when clear filters button is pressed', async () => { + getTestContext({ + footerOptions: { show: true, reducer: ['sum'] }, + data: toDataFrame({ + name: 'A', + fields: [ + { + name: 'number', + type: FieldType.number, + values: [1, 1, 1, 2, 2], + config: { + custom: { + filterable: true, + }, + }, + }, + ], + }), + }); + + await userEvent.click(within(getColumnHeader(/number/)).getByRole('button', { name: '' })); + await userEvent.click(screen.getByLabelText('1')); + await userEvent.click(screen.getByText('Ok')); + + //3 + header row + expect(within(getTable()).getAllByRole('row')).toHaveLength(4); + expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('3'); + + await userEvent.click(within(getColumnHeader(/number/)).getByRole('button', { name: '' })); + await userEvent.click(screen.getByText('Clear filter')); + + //5 + header row + expect(within(getTable()).getAllByRole('row')).toHaveLength(6); + expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('7'); + }); + }); + + describe('on data change', () => { + it('should redo footer value calculations', async () => { + const { rerender } = getTestContext({ + footerOptions: { show: true, reducer: ['sum'] }, + data: toDataFrame({ + name: 'A', + fields: [ + { + name: 'number', + type: FieldType.number, + values: [1, 1, 1, 2, 2], + config: { + custom: { + filterable: true, + }, + }, + }, + ], + }), + }); + + //5 + header row + expect(within(getTable()).getAllByRole('row')).toHaveLength(6); + expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('7'); + + const onSortByChange = jest.fn(); + const onCellFilterAdded = jest.fn(); + const onColumnResize = jest.fn(); + const props: Props = { + ariaLabel: 'aria-label', + data: getDefaultDataFrame(), + height: 600, + width: 800, + onSortByChange, + onCellFilterAdded, + onColumnResize, + }; + + const propOverrides = { + footerOptions: { show: true, reducer: ['sum'] }, + data: toDataFrame({ + name: 'A', + fields: [ + { + name: 'number', + type: FieldType.number, + values: [1, 1, 1, 2], + config: { + custom: { + filterable: true, + }, + }, + }, + ], + }), + }; + + Object.assign(props, propOverrides); + + rerender(); + + //4 + header row + expect(within(getTable()).getAllByRole('row')).toHaveLength(5); + expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('5'); + }); + }); + + describe('on table footer disabled', () => { + it('should not show footer', async () => { + getTestContext({ + footerOptions: { show: false, reducer: ['sum'] }, + data: toDataFrame({ + name: 'A', + fields: [ + { + name: 'number', + type: FieldType.number, + values: [1, 1, 1, 2, 2], + config: { + custom: { + filterable: true, + }, + }, + }, + ], + }), + }); + + expect(() => screen.getByTestId('table-footer')).toThrow('Unable to find an element'); + }); }); }); diff --git a/packages/grafana-ui/src/components/Table/Table.tsx b/packages/grafana-ui/src/components/Table/Table.tsx index 8007f0cd54a..fe69cf86ba3 100644 --- a/packages/grafana-ui/src/components/Table/Table.tsx +++ b/packages/grafana-ui/src/components/Table/Table.tsx @@ -244,7 +244,7 @@ export const Table = memo((props: Props) => { setFooterItems(undefined); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [footerOptions, theme, state.filters]); + }, [footerOptions, theme, state.filters, data]); let listHeight = height - (headerHeight + footerHeight);