Skip to content

Commit 4404894

Browse files
authored
fix: Added getKey to SelectionUtils.optimizeSelection (#1994)
fixes root issue of DH-16914 I published this as an alpha for DHE testing: [0.76.1-alpha-optimize-selection-get-key.0](https://www.npmjs.com/package/@deephaven/react-hooks/v/0.76.1-alpha-optimize-selection-get-key.0) BREAKING CHANGE: @deephaven/react-hooks: `SelectionUtils.optimizeSelection` and `useMappedSelection` require additional `getKey` arg
1 parent 1b241ca commit 4404894

6 files changed

Lines changed: 33 additions & 16 deletions

File tree

packages/jsapi-components/src/useDebouncedViewportSelectionFilter.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { renderHook } from '@testing-library/react-hooks';
22
import {
3+
createKeyedItemKey,
34
createSelectedValuesFilter,
45
FilterConditionFactory,
56
TableUtils,
@@ -82,7 +83,8 @@ it('should map selection to values', () => {
8283

8384
expect(useMappedSelection).toHaveBeenCalledWith(
8485
mockViewportData,
85-
mapItemToValue
86+
mapItemToValue,
87+
createKeyedItemKey
8688
);
8789
});
8890

packages/jsapi-components/src/useDebouncedViewportSelectionFilter.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
createKeyedItemKey,
23
createSelectedValuesFilter,
34
FilterConditionFactory,
45
} from '@deephaven/jsapi-utils';
@@ -40,7 +41,11 @@ export function useDebouncedViewportSelectionFilter<TItem, TValue>({
4041
const tableUtils = useTableUtils();
4142

4243
// Map selection to values contained in the column to filter
43-
const valuesSelection = useMappedSelection(viewportData, mapItemToValue);
44+
const valuesSelection = useMappedSelection(
45+
viewportData,
46+
mapItemToValue,
47+
createKeyedItemKey
48+
);
4449

4550
// Debounce so user can rapidly select multiple items in a row without the
4651
// cost of updating the table on each change

packages/react-hooks/src/SelectionUtils.test.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,13 @@ describe('mapSelection', () => {
122122
});
123123

124124
describe('optimizeSelection', () => {
125+
const getKey = (i: number) => 'abcdefg'.charAt(i);
126+
125127
it('should invert selection if selection is "all"', () => {
126128
const selection = 'all';
127129
const totalRecords = 10;
128130

129-
const actual = optimizeSelection(selection, totalRecords);
131+
const actual = optimizeSelection(selection, totalRecords, getKey);
130132

131133
expect(actual).toEqual({
132134
isInverted: true,
@@ -137,16 +139,16 @@ describe('optimizeSelection', () => {
137139
it.each([
138140
// Odd record count
139141
[new Set(''), 5, { isInverted: false, selection: new Set('') }],
140-
[new Set('12'), 5, { isInverted: false, selection: new Set('12') }],
141-
[new Set('123'), 5, { isInverted: true, selection: new Set('04') }],
142+
[new Set('bc'), 5, { isInverted: false, selection: new Set('bc') }],
143+
[new Set('bcd'), 5, { isInverted: true, selection: new Set('ae') }],
142144
// Even record count
143145
[new Set(''), 6, { isInverted: false, selection: new Set('') }],
144-
[new Set('123'), 6, { isInverted: false, selection: new Set('123') }],
145-
[new Set('1234'), 6, { isInverted: true, selection: new Set('05') }],
146+
[new Set('bcd'), 6, { isInverted: false, selection: new Set('bcd') }],
147+
[new Set('bcde'), 6, { isInverted: true, selection: new Set('af') }],
146148
] as const)(
147149
'should invert selection if selection size > half the total size',
148150
(selection, totalRecords, expected) => {
149-
const actual = optimizeSelection(selection, totalRecords);
151+
const actual = optimizeSelection(selection, totalRecords, getKey);
150152

151153
expect(actual).toEqual(expected);
152154
}

packages/react-hooks/src/SelectionUtils.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,12 @@ export function mapSelection<TItem, TMap>(
9494
* "no filter".
9595
* @param selection The selection to optimize
9696
* @param totalRecords The total number of records that can potentially be selected
97+
* @param getKey A function to get the key for a given index.
9798
*/
9899
export function optimizeSelection(
99100
selection: Selection,
100-
totalRecords: number
101+
totalRecords: number,
102+
getKey: (i: number) => string
101103
): { selection: Selection; isInverted: boolean } {
102104
const isInverted = selection === 'all' || selection.size > totalRecords / 2;
103105

@@ -110,8 +112,8 @@ export function optimizeSelection(
110112
: new Set<Key>(
111113
// Create a new set from any key that is not selected
112114
[...generateRange(0, totalRecords - 1)]
113-
.filter(i => !selection.has(String(i)))
114-
.map(i => String(i))
115+
.map(getKey)
116+
.filter(key => !selection.has(key))
115117
);
116118
}
117119

packages/react-hooks/src/useMappedSelection.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,16 @@ beforeEach(() => {
4040
});
4141

4242
it('should optimize selection and map it to another selection', () => {
43+
const getKey = jest.fn().mockName('getKey');
44+
4345
const { result } = renderHook(() =>
44-
useMappedSelection(viewportData, mapName)
46+
useMappedSelection(viewportData, mapName, getKey)
4547
);
4648

4749
expect(optimizeSelection).toHaveBeenCalledWith(
4850
viewportData.selectedKeys,
49-
viewportData.items.length
51+
viewportData.items.length,
52+
getKey
5053
);
5154

5255
expect(mapSelection).toHaveBeenCalledWith(

packages/react-hooks/src/useMappedSelection.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,27 @@ import type { WindowedListData } from './useWindowedListData';
88
* The keys are mapped to new values via a `mapItem` function.
99
* @param viewportData The viewport to map selections for
1010
* @param mapItem A function to map an item in the viewport to a new value
11+
* @param getKey A function to get the key for an item in the viewport.
1112
*/
1213
export function useMappedSelection<TItem, TValue>(
1314
viewportData: WindowedListData<KeyedItem<TItem>>,
14-
mapItem: (item: KeyedItem<TItem>) => TValue
15+
mapItem: (item: KeyedItem<TItem>) => TValue,
16+
getKey: (i: number) => string
1517
): SelectionMaybeInverted<TValue> {
1618
const { getItem, selectedKeys, items } = viewportData;
1719

1820
return useMemo(() => {
1921
const { selection, isInverted } = optimizeSelection(
2022
selectedKeys,
21-
items.length
23+
items.length,
24+
getKey
2225
);
2326

2427
return {
2528
selection: mapSelection(selection, getItem, mapItem),
2629
isInverted,
2730
};
28-
}, [selectedKeys, items.length, getItem, mapItem]);
31+
}, [selectedKeys, items.length, getKey, getItem, mapItem]);
2932
}
3033

3134
export default useMappedSelection;

0 commit comments

Comments
 (0)