Skip to content

Commit f7b37d2

Browse files
authored
[EuiBasicTable][EuiInMemoryTable] Support controlled selection API (#7321)
1 parent b1d7031 commit f7b37d2

File tree

10 files changed

+805
-201
lines changed

10 files changed

+805
-201
lines changed

src-docs/src/views/tables/in_memory/in_memory_selection.tsx renamed to src-docs/src/views/tables/in_memory/in_memory_selection_controlled.tsx

Lines changed: 26 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,22 @@
1-
import React, { useState, useRef, ReactNode } from 'react';
1+
import React, { useState, ReactNode } from 'react';
22
import { faker } from '@faker-js/faker';
3-
import { formatDate, Random } from '../../../../../src/services';
3+
import { Random } from '../../../../../src/services';
44

55
import {
66
EuiInMemoryTable,
77
EuiBasicTableColumn,
88
EuiTableSelectionType,
99
EuiSearchBarProps,
10-
EuiLink,
1110
EuiHealth,
1211
EuiButton,
1312
EuiEmptyPrompt,
14-
EuiFlexGroup,
15-
EuiFlexItem,
1613
EuiSpacer,
1714
} from '../../../../../src/components';
1815

1916
type User = {
2017
id: number;
2118
firstName: string | null | undefined;
2219
lastName: string;
23-
github: string;
24-
dateOfBirth: Date;
2520
online: boolean;
2621
location: {
2722
city: string;
@@ -36,8 +31,6 @@ for (let i = 0; i < 20; i++) {
3631
id: i + 1,
3732
firstName: faker.person.firstName(),
3833
lastName: faker.person.lastName(),
39-
github: faker.internet.userName(),
40-
dateOfBirth: faker.date.past(),
4134
online: faker.datatype.boolean(),
4235
location: {
4336
city: faker.location.city(),
@@ -46,17 +39,6 @@ for (let i = 0; i < 20; i++) {
4639
});
4740
}
4841

49-
const onlineUsers = userData.filter((user) => user.online);
50-
51-
const deleteUsersByIds = (...ids: number[]) => {
52-
ids.forEach((id) => {
53-
const index = userData.findIndex((user) => user.id === id);
54-
if (index >= 0) {
55-
userData.splice(index, 1);
56-
}
57-
});
58-
};
59-
6042
const columns: Array<EuiBasicTableColumn<User>> = [
6143
{
6244
field: 'firstName',
@@ -83,23 +65,6 @@ const columns: Array<EuiBasicTableColumn<User>> = [
8365
show: false,
8466
},
8567
},
86-
{
87-
field: 'github',
88-
name: 'Github',
89-
render: (username: User['github']) => (
90-
<EuiLink href="#" target="_blank">
91-
{username}
92-
</EuiLink>
93-
),
94-
},
95-
{
96-
field: 'dateOfBirth',
97-
name: 'Date of Birth',
98-
dataType: 'date',
99-
render: (dateOfBirth: User['dateOfBirth']) =>
100-
formatDate(dateOfBirth, 'dobLong'),
101-
sortable: true,
102-
},
10368
{
10469
field: 'location',
10570
name: 'Location',
@@ -153,7 +118,6 @@ export default () => {
153118

154119
const [selection, setSelection] = useState<User[]>([]);
155120
const [error, setError] = useState<string | undefined>();
156-
const tableRef = useRef<EuiInMemoryTable<User> | null>(null);
157121

158122
const loadUsers = () => {
159123
setMessage('Loading users...');
@@ -168,6 +132,8 @@ export default () => {
168132
}, random.number({ min: 0, max: 3000 }));
169133
};
170134

135+
const onlineUsers = users.filter((user) => user.online);
136+
171137
const loadUsersWithError = () => {
172138
setMessage('Loading users...');
173139
setLoading(true);
@@ -187,7 +153,23 @@ export default () => {
187153
}
188154

189155
const onClick = () => {
190-
deleteUsersByIds(...selection.map((user) => user.id));
156+
const deleteUsersByIds = (users: User[], ids: number[]) => {
157+
const updatedUsers = [...users];
158+
ids.forEach((id) => {
159+
const index = updatedUsers.findIndex((user) => user.id === id);
160+
if (index >= 0) {
161+
updatedUsers.splice(index, 1);
162+
}
163+
});
164+
return updatedUsers;
165+
};
166+
167+
setUsers((users) =>
168+
deleteUsersByIds(
169+
users,
170+
selection.map((user) => user.id)
171+
)
172+
);
191173
setSelection([]);
192174
};
193175

@@ -256,27 +238,19 @@ export default () => {
256238
selectableMessage: (selectable) =>
257239
!selectable ? 'User is currently offline' : '',
258240
onSelectionChange: (selection) => setSelection(selection),
259-
initialSelected: onlineUsers,
260-
};
261-
262-
const onSelection = () => {
263-
tableRef.current?.setSelection(onlineUsers);
241+
selected: selection,
264242
};
265243

266244
return (
267245
<>
268-
<EuiFlexGroup alignItems="center">
269-
<EuiFlexItem grow={false}>
270-
<EuiButton onClick={onSelection}>Select online users</EuiButton>
271-
</EuiFlexItem>
272-
<EuiFlexItem />
273-
</EuiFlexGroup>
246+
<EuiButton onClick={() => setSelection(onlineUsers)}>
247+
Select online users
248+
</EuiButton>
274249

275250
<EuiSpacer size="l" />
276251

277252
<EuiInMemoryTable
278-
tableCaption="Demo of EuiInMemoryTable with selection"
279-
ref={tableRef}
253+
tableCaption="Demo of EuiInMemoryTable with controlled selection"
280254
items={users}
281255
itemId="id"
282256
error={error}
Lines changed: 41 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,50 @@
11
import React from 'react';
2-
import { EuiCode } from '../../../../../src/components';
3-
import { GuideSectionTypes } from '../../../components';
2+
import { EuiCode, EuiSpacer } from '../../../../../src/components';
43

5-
import Table from './in_memory_selection';
6-
import { EuiInMemoryTable } from '../../../../../src/components/basic_table/in_memory_table';
7-
import {
8-
Criteria,
9-
CriteriaWithPagination,
10-
} from '!!prop-loader!../../../../../src/components/basic_table/basic_table';
11-
import { Pagination } from '../paginated/_props';
12-
import {
13-
EuiTableFieldDataColumnType,
14-
EuiTableComputedColumnType,
15-
EuiTableActionsColumnType,
16-
EuiTableSelectionType,
17-
EuiTableSortingType,
18-
} from '!!prop-loader!../../../../../src/components/basic_table/table_types';
19-
import { CustomItemAction } from '!!prop-loader!../../../../../src/components/basic_table/action_types';
20-
import {
21-
DefaultItemActionProps as DefaultItemAction,
22-
SearchProps as Search,
23-
SearchFilterConfigProps as SearchFilterConfig,
24-
} from '../props/props';
25-
import { FieldValueOptionType } from '!!prop-loader!../../../../../src/components/search_bar/filters/field_value_selection_filter';
26-
import { FieldValueToggleGroupFilterItemType } from '!prop-loader!../../../../../src/components/search_bar/filters/field_value_toggle_group_filter.tsx';
4+
import { ConditionallyControlledDemo } from '../../tables/selection/selection_section';
275

28-
const source = require('!!raw-loader!./in_memory_selection');
6+
import Controlled from './in_memory_selection_controlled';
7+
const controlledSource = require('!!raw-loader!./in_memory_selection_controlled');
8+
9+
import Uncontrolled from './in_memory_selection_uncontrolled';
10+
const uncontrolledSource = require('!!raw-loader!./in_memory_selection_uncontrolled');
2911

3012
export const selectionSection = {
3113
title: 'In-memory table selection',
32-
source: [
33-
{
34-
type: GuideSectionTypes.TSX,
35-
code: source,
36-
},
37-
],
3814
text: (
39-
<p>
40-
The following example shows how to use <strong>EuiInMemoryTable</strong>{' '}
41-
along with item selection. It also shows how you can display messages,
42-
errors and show loading indication. You can set items to be selected
43-
initially by passing an array of items as the{' '}
44-
<EuiCode>initialSelected</EuiCode> value inside{' '}
45-
<EuiCode>selection</EuiCode> property and passing{' '}
46-
<EuiCode>itemId</EuiCode> property to enable selection. You can also use
47-
the <EuiCode>setSelection</EuiCode> method to take complete control over
48-
table selection. This can be useful if you want to handle selection in
49-
table based on user interaction with another part of the UI.
50-
</p>
15+
<>
16+
<p>
17+
To enable selection, both the <EuiCode>itemId</EuiCode> and{' '}
18+
<EuiCode>selection</EuiCode> props must be passed. The following example
19+
shows how to use <strong>EuiInMemoryTable</strong> with both controlled
20+
and uncontrolled item selection. It also shows how you can display
21+
messages, errors and show loading indication.
22+
</p>
23+
<p>
24+
For uncontrolled usage, where selection changes are determined entirely
25+
to be selected initially by passing an array of items to{' '}
26+
<EuiCode>selection.initialSelected</EuiCode>. You can also use{' '}
27+
<EuiCode>selected.onSelectionChange</EuiCode> to track or respond to the
28+
items that users select.
29+
</p>
30+
<p>
31+
To completely control table selection, use{' '}
32+
<EuiCode>selection.selected</EuiCode> instead (which requires passing{' '}
33+
<EuiCode>selected.onSelectionChange</EuiCode>). This can be useful if
34+
you want to handle table selections based on user interaction with
35+
another part of the UI.
36+
</p>
37+
</>
38+
),
39+
children: (
40+
<>
41+
<EuiSpacer />
42+
<ConditionallyControlledDemo
43+
controlledDemo={<Controlled />}
44+
uncontrolledDemo={<Uncontrolled />}
45+
controlledSource={controlledSource}
46+
uncontrolledSource={uncontrolledSource}
47+
/>
48+
</>
5149
),
52-
props: {
53-
EuiInMemoryTable,
54-
Criteria,
55-
CriteriaWithPagination,
56-
Pagination,
57-
EuiTableSortingType,
58-
EuiTableSelectionType,
59-
EuiTableFieldDataColumnType,
60-
EuiTableComputedColumnType,
61-
EuiTableActionsColumnType,
62-
DefaultItemAction,
63-
CustomItemAction,
64-
Search,
65-
SearchFilterConfig,
66-
FieldValueOptionType,
67-
FieldValueToggleGroupFilterItemType,
68-
},
69-
demo: <Table />,
7050
};

0 commit comments

Comments
 (0)