[Controls] Bulk select for options list control #221010
[Controls] Bulk select for options list control #221010cqliu1 merged 36 commits intoelastic:mainfrom
Conversation
d036377 to
812c7ee
Compare
|
Cloud deployments require a Github label, please add |
d0646ff to
263c283
Compare
|
Pinging @elastic/kibana-presentation (Team:Presentation) |
Fix select and deselect logic Fix types Fetch more options on select/deselect all Add loadMoreOptions callback Add const for bulk selection limit Add i18n Remove unused import Handle showOnlySelected with bulk selection Add options list action bar tests Remove console log Clean up code Added test
bd338d9 to
080d7d7
Compare
| <EuiToolTip | ||
| content={ | ||
| hasTooManyOptions | ||
| ? OptionsListStrings.popover.getMaximumBulkSelectionTooltip() | ||
| : undefined | ||
| } | ||
| > | ||
| <EuiButtonEmpty | ||
| size="xs" | ||
| disabled={isBulkSelectDisabled} | ||
| data-test-subj="optionsList-control-selectAll" | ||
| onClick={() => handleBulkAction(componentApi.selectAll)} | ||
| > | ||
| {OptionsListStrings.popover.getSelectAllButtonLabel()} | ||
| </EuiButtonEmpty> | ||
| </EuiToolTip> | ||
| <EuiToolTip | ||
| content={ | ||
| hasTooManyOptions | ||
| ? OptionsListStrings.popover.getMaximumBulkSelectionTooltip() | ||
| : undefined | ||
| } | ||
| > | ||
| <EuiButtonEmpty | ||
| size="xs" | ||
| disabled={isBulkSelectDisabled} | ||
| data-test-subj="optionsList-control-deselectAll" | ||
| onClick={() => handleBulkAction(componentApi.deselectAll)} | ||
| > | ||
| {OptionsListStrings.popover.getDeselectAllButtonLabel()} | ||
| </EuiButtonEmpty> | ||
| </EuiToolTip> |
There was a problem hiding this comment.
Maybe we wait on @elastic/kibana-design for this one 😆 The double | feels a bit busy to me and I would prefer just adding some padding between "select all" and "deselect all" (about the same size as the gap with the |, but without actually rendering the | if that makes sense)... But I'm not sure
| <EuiToolTip | ||
| content={ | ||
| hasTooManyOptions | ||
| ? OptionsListStrings.popover.getMaximumBulkSelectionTooltip() | ||
| : undefined | ||
| } | ||
| > | ||
| <EuiButtonEmpty | ||
| size="xs" | ||
| disabled={isBulkSelectDisabled} | ||
| data-test-subj="optionsList-control-selectAll" | ||
| onClick={() => handleBulkAction(componentApi.selectAll)} | ||
| > | ||
| {OptionsListStrings.popover.getSelectAllButtonLabel()} | ||
| </EuiButtonEmpty> | ||
| </EuiToolTip> | ||
| <EuiToolTip | ||
| content={ | ||
| hasTooManyOptions | ||
| ? OptionsListStrings.popover.getMaximumBulkSelectionTooltip() | ||
| : undefined | ||
| } | ||
| > | ||
| <EuiButtonEmpty | ||
| size="xs" | ||
| disabled={isBulkSelectDisabled} | ||
| data-test-subj="optionsList-control-deselectAll" | ||
| onClick={() => handleBulkAction(componentApi.deselectAll)} | ||
| > | ||
| {OptionsListStrings.popover.getDeselectAllButtonLabel()} | ||
| </EuiButtonEmpty> | ||
| </EuiToolTip> |
There was a problem hiding this comment.
I wonder if we could make this work a little better for the min popover size (300px)? Ideally, I would want it constrained to a single line for this size, at least in English... But if we can't (since I know this will change depending on the length of the cardinality string), I would hope that we could at least make the two line layout look a bit more... intentional 😆 i.e. keeping "select all" + "deselect all" grouped, or using icons, or... something.
| Min size | Larger |
|---|---|
![]() |
![]() |
...c/controls/data_controls/options_list_control/components/options_list_popover_action_bar.tsx
Outdated
Show resolved
Hide resolved
|
|
||
| if (totalCardinality > availableOptions.length) { | ||
| const newAvailableOptions = (await loadMoreOptions()) ?? []; | ||
| bulkAction(newAvailableOptions.map(({ value }) => value as string)); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Would it be sufficient to just disable select/deselect buttons while the control is loading? I don't think we need any additional loading indicators since we have the spinner in the base control and the loading bar at the bottom of the popover.
There was a problem hiding this comment.
I wonder if it would be possible to add the following "loading icon" indicator beside each option (i.e. where the "checked" status usually is) as soon as "select all" is clicked in? This gives a better indication for "we are waiting to make the selections" to me...
If not then yeah, maybe just disabling the "select all / deselect all" buttons would be sufficient
There was a problem hiding this comment.
I'm pretty sure that loading indicator is just the Eui icon being async imported - but maybe we could checkmark the visible ones right away - though that might make the code uglier.
There was a problem hiding this comment.
m pretty sure that loading indicator is just the Eui icon being async imported
I know! I just don't love how we have two consecutive loading states happening, so if we could simulate the same "loading" state, I think this would help with the feeling of "I clicked this button but nothing is happening!"
...c/controls/data_controls/options_list_control/components/options_list_popover_action_bar.tsx
Outdated
Show resolved
Hide resolved
...c/controls/data_controls/options_list_control/components/options_list_popover_action_bar.tsx
Outdated
Show resolved
Hide resolved
...rols/public/controls/data_controls/options_list_control/get_options_list_control_factory.tsx
Show resolved
Hide resolved
…s/options-list/select-deselect-all
…ithub.com/cqliu1/kibana into controls/options-list/select-deselect-all
…s/options-list/select-deselect-all
| )} | ||
| options={selectableOptions} | ||
| listProps={{ onFocusBadge: false, isVirtualized: false }} | ||
| listProps={{ onFocusBadge: false }} |
There was a problem hiding this comment.
By enable virtualization in the EuiSelectable component in the invalid selections component, we get a list with a fixed height with scrolling enabled similar to the list of available options above it. This fixes the issue described in #222121.
Jun-20-2025.16-34-52.mp4
…s/options-list/select-deselect-all
andreadelrio
left a comment
There was a problem hiding this comment.
Design changes LGTM, nice job!
| { value: 'toot', docCount: 11 }, | ||
| ]; | ||
|
|
||
| const renderComponent = ({ |
There was a problem hiding this comment.
I added some edits to these tests to make it more user-focused, like using selectors like getByRole, not getByTestId. or using get selectors and not query selectors (query should only be used when checking for non-existance, since they have worse messaging)
💚 Build Succeeded
Metrics [docs]Async chunks
History
|
|
Starting backport for target branches: 8.19 |







Summary
Closes #181694.
Closes #222121.
This adds
Select allandDeselect allbuttons to the options list popover to allow users to make bulk selections. Bulk selections will only be available when there are 100 or fewer available options.Disabled bulk select
Bulk selection is disabled when there are no available options.

Bulk selection is also disabled when total cardinality is over 100.
When
showOnlySelectedis enabledEven if the total cardinality is greater than the bulk selection limit, bulk selection is enabled whenPer feedback, we opted to disabled bulk selection when this is enabled.showOnlySelectedis enabled, and the number of selection options is fewer than the bulk selection limit (e.g. fewer than 100 selections).Checklist
Check the PR satisfies following conditions.
Reviewers should verify this PR satisfies this list as well.
release_note:breakinglabel should be applied in these situations.release_note:*label is applied per the guidelinesIdentify risks
Does this PR introduce any risks? For example, consider risks like hard to test bugs, performance regression, potential of data loss.
Describe the risk, its severity, and mitigation for each identified risk. Invite stakeholders and evaluate how to proceed before merging.