Skip to content

Commit a728467

Browse files
authored
feat(AnalyticalTable): introduce onFilter callback prop (#7304)
Closes #6562
1 parent 79c6ce6 commit a728467

File tree

4 files changed

+64
-5
lines changed

4 files changed

+64
-5
lines changed

packages/main/src/components/AnalyticalTable/AnalyticalTable.cy.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ describe('AnalyticalTable', () => {
468468
});
469469

470470
it('tree selection & filtering', () => {
471+
const filterSpy = cy.spy().as('filter');
471472
const TreeSelectFilterTable = (props: PropTypes) => {
472473
const [filter, setFilter] = useState('');
473474
const [relevantPayload, setRelevantPayload] = useState<Record<string, any>>({});
@@ -501,6 +502,7 @@ describe('AnalyticalTable', () => {
501502
data={dataTree}
502503
globalFilterValue={filter}
503504
selectionMode="Multiple"
505+
onFilter={filterSpy}
504506
/>
505507
<div data-testid="payloadHelper">
506508
{JSON.stringify(relevantPayload?.selectedFlatRows?.filter(Boolean).length)}
@@ -553,6 +555,12 @@ describe('AnalyticalTable', () => {
553555
// column filter + select
554556
cy.findByText('Name').click();
555557
cy.get(`[ui5-input][show-clear-icon]`).typeIntoUi5Input('Flowers Mcfarland', { force: true });
558+
cy.get('@filter').should('have.callCount', 17);
559+
cy.get('@filter').should('have.been.calledWithMatch', {
560+
value: 'Flowers Mcfarland',
561+
columnId: 'name',
562+
filters: [{ id: 'name', value: 'Flowers Mcfarland' }]
563+
});
556564
cy.findByText('Robin Moreno').should('not.exist', { timeout: 100 });
557565
cy.findByText('Judith Mathews').should('not.exist', { timeout: 100 });
558566
cy.findByText('Katy Bradshaw').should('not.exist', { timeout: 100 });
@@ -576,6 +584,8 @@ describe('AnalyticalTable', () => {
576584
}
577585
}
578586
];
587+
588+
const filterSpy = cy.spy().as('filter');
579589
const TestComp = ({ onRowSelect }: PropTypes) => {
580590
const [selectedRowIds, setSelectedRowIds] = useState({});
581591
const [selectedFlatRows, setSelectedFlatRows] = useState([]);
@@ -610,6 +620,7 @@ describe('AnalyticalTable', () => {
610620
setAllRowsSelected(e.detail.allRowsSelected);
611621
onRowSelect(e);
612622
}}
623+
onFilter={filterSpy}
613624
selectionMode={AnalyticalTableSelectionMode.Multiple}
614625
selectedRowIds={selectedRowIds}
615626
/>
@@ -696,6 +707,12 @@ describe('AnalyticalTable', () => {
696707
cy.findByText('Name-5').click();
697708
cy.findByText('Name').click();
698709
cy.get('[ui5-li-custom]').shadow().get('[ui5-input]').typeIntoUi5Input('7{enter}');
710+
cy.get('@filter').should('have.callCount', 1);
711+
cy.get('@filter').should('have.been.calledWithMatch', {
712+
value: '7',
713+
columnId: 'name',
714+
filters: [{ id: 'name', value: '7' }]
715+
});
699716
cy.findByTestId('payload').should('have.text', '["0","1","5"]');
700717
cy.findByTestId('payloadRowsById').should('have.text', '{"0":true,"1":true,"5":true}');
701718
cy.findByTestId('payloadAllRowsSelected').should('have.text', 'false');
@@ -708,10 +725,18 @@ describe('AnalyticalTable', () => {
708725

709726
cy.findByText('Name').click();
710727
cy.get('[ui5-li-custom]').shadow().get('[ui5-input]').typeIntoUi5Input('{selectall}{backspace}{enter}');
728+
cy.get('@filter').should('have.callCount', 2);
729+
cy.get('@filter').should('have.been.calledWithMatch', {
730+
value: undefined,
731+
columnId: 'name',
732+
filters: []
733+
});
734+
711735
cy.get('[data-row-index="0"][data-column-index="0"]').click();
712736
cy.findByText('Name-17').click({ force: true });
713737
cy.findByText('Name').click();
714738
cy.get('[ui5-li-custom]').shadow().get('[ui5-input]').typeIntoUi5Input('7{enter}');
739+
cy.get('@filter').should('have.callCount', 3);
715740
cy.findByTestId('payload').should(
716741
'have.text',
717742
'["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","18","19","20"]'
@@ -734,6 +759,7 @@ describe('AnalyticalTable', () => {
734759

735760
cy.findByText('Name').click();
736761
cy.get('[ui5-li-custom]').shadow().get('[ui5-input]').typeIntoUi5Input('{selectall}{backspace}{enter}');
762+
cy.get('@filter').should('have.callCount', 4);
737763

738764
cy.findByText('Name-17').click({ force: true });
739765
cy.findByTestId('input').type('7{enter}');

packages/main/src/components/AnalyticalTable/index.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ const AnalyticalTable = forwardRef<AnalyticalTableDomRef, AnalyticalTablePropTyp
160160
onSort,
161161
onTableScroll,
162162
onAutoResize,
163+
onFilter,
163164
NoDataComponent = DefaultNoDataComponent,
164165
additionalEmptyRowsCount = 0,
165166
...rest
@@ -187,6 +188,14 @@ const AnalyticalTable = forwardRef<AnalyticalTableDomRef, AnalyticalTablePropTyp
187188
const tableInstanceRef = useRef<TableInstance>(null);
188189
const scrollContainerRef = useRef<HTMLDivElement>(null);
189190

191+
const dedupedOnFilter = useMemo(() => debounce(onFilter, 0), [onFilter]);
192+
useEffect(
193+
() => () => {
194+
dedupedOnFilter.cancel();
195+
},
196+
[dedupedOnFilter]
197+
);
198+
190199
tableInstanceRef.current = useTable(
191200
{
192201
columns,
@@ -239,8 +248,9 @@ const AnalyticalTable = forwardRef<AnalyticalTableDomRef, AnalyticalTablePropTyp
239248
onGroup,
240249
onRowClick,
241250
onRowExpandChange,
242-
onRowSelect: onRowSelect,
243-
onSort
251+
onRowSelect,
252+
onSort,
253+
onFilter: dedupedOnFilter
244254
},
245255
...reactTableOptions
246256
},

packages/main/src/components/AnalyticalTable/tableReducer/stateReducer.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { actions } from 'react-table';
2+
import type { TableInstance } from '../types/index.js';
23

3-
export const stateReducer = (state, action, _prevState, instance) => {
4+
export const stateReducer = (state, action, _prevState, instance: TableInstance) => {
45
const { payload } = action;
5-
66
if (state.isRtl && action.type === actions.columnResizing) {
77
const { clientX } = action;
88
const { startX, columnWidth, headerIdWidths } = state.columnResizing;
@@ -28,6 +28,13 @@ export const stateReducer = (state, action, _prevState, instance) => {
2828
};
2929
}
3030
switch (action.type) {
31+
case 'setFilter':
32+
instance.webComponentsReactProperties.onFilter({
33+
filters: state.filters,
34+
value: action.filterValue,
35+
columnId: action.columnId
36+
});
37+
return state;
3138
case 'toggleRowExpanded':
3239
// this flag disables scrolling to the top of the table if a table is collapsed
3340
if (!state.expanded[action.id]) {

packages/main/src/components/AnalyticalTable/types/index.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ export interface WCRPropertiesType {
242242
uniqueId: string;
243243
subRowsKey: AnalyticalTablePropTypes['subRowsKey'];
244244
onColumnsReorder: AnalyticalTablePropTypes['onColumnsReorder'];
245+
onFilter: AnalyticalTablePropTypes['onFilter'];
245246
}
246247

247248
export interface RowType {
@@ -289,7 +290,7 @@ export interface AnalyticalTableState {
289290
columnOrder: string[];
290291
columnResizing: Record<string, any>;
291292
expanded: Record<string | number, any>;
292-
filters: Record<string | number, any>[];
293+
filters: Filter[];
293294
groupBy: string[];
294295
hiddenColumns: string[];
295296
selectedRowIds: Record<string | number, any>;
@@ -309,6 +310,11 @@ export interface AnalyticalTableState {
309310
triggerScroll?: TriggerScrollState;
310311
}
311312

313+
interface Filter {
314+
id: number | string;
315+
value: string;
316+
}
317+
312318
interface CellLabelParam {
313319
instance: Record<string, any>;
314320
cell: Record<string, any>;
@@ -966,6 +972,10 @@ export interface AnalyticalTablePropTypes extends Omit<CommonProps, 'title'> {
966972
* __Note:__ Auto-resize is only available on columns that have the `autoResizable` option set to `true`.
967973
*/
968974
onAutoResize?: (e?: OnAutoResizeMouseEvent) => void;
975+
/**
976+
* Fired when a filter is applied to a column.
977+
*/
978+
onFilter?: (e: OnFilterParam) => void;
969979
// default components
970980
/**
971981
* Component that will be rendered when the table is not loading and has no data.
@@ -985,6 +995,12 @@ export interface AnalyticalTablePropTypes extends Omit<CommonProps, 'title'> {
985995
tableInstance?: Ref<TableInstance>;
986996
}
987997

998+
interface OnFilterParam {
999+
filters: Filter[];
1000+
value: string | undefined;
1001+
columnId: string | number;
1002+
}
1003+
9881004
interface ConfigParam {
9891005
instance: TableInstance;
9901006
}

0 commit comments

Comments
 (0)