Skip to content

Commit 9d74ea8

Browse files
committed
Fetch more options on select/deselect all
1 parent 1181997 commit 9d74ea8

File tree

3 files changed

+88
-23
lines changed

3 files changed

+88
-23
lines changed

src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/components/options_list_popover_action_bar.tsx

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { getCompatibleSearchTechniques } from '../../../../../common/options_lis
2828
import { useOptionsListContext } from '../options_list_context_provider';
2929
import { OptionsListPopoverSortingButton } from './options_list_popover_sorting_button';
3030
import { OptionsListStrings } from '../options_list_strings';
31+
import { MAX_OPTIONS_LIST_REQUEST_SIZE } from '../constants';
3132

3233
interface OptionsListPopoverProps {
3334
showOnlySelected: boolean;
@@ -47,16 +48,14 @@ export const OptionsListPopoverActionBar = ({
4748
const [
4849
searchTechnique,
4950
searchStringValid,
50-
selectedOptions = [],
5151
invalidSelections,
5252
totalCardinality,
5353
field,
5454
allowExpensiveQueries,
55-
availableOptions,
55+
availableOptions = [],
5656
] = useBatchedPublishingSubjects(
5757
stateManager.searchTechnique,
5858
stateManager.searchStringValid,
59-
stateManager.selectedOptions,
6059
api.invalidSelections$,
6160
api.totalCardinality$,
6261
api.field$,
@@ -114,33 +113,69 @@ export const OptionsListPopoverActionBar = ({
114113
>
115114
<EuiButtonEmpty
116115
size="s"
117-
isDisabled={!availableOptions || totalCardinality < 0 || totalCardinality > 100}
116+
isDisabled={
117+
availableOptions.length < 1 || totalCardinality < 1 || totalCardinality > 100
118+
}
118119
onClick={() => {
119-
const availableOptionValues = (
120-
availableOptions?.map(({ value }) => value as string) ?? []
121-
).filter((value) => !selectedOptions.includes(value));
122-
availableOptionValues.forEach((value: string) => {
123-
api.makeSelection(value, showOnlySelected);
124-
});
120+
if (
121+
availableOptions.length > 0 &&
122+
totalCardinality > availableOptions.length
123+
) {
124+
// load more options
125+
stateManager.requestSize.next(
126+
Math.min(totalCardinality, MAX_OPTIONS_LIST_REQUEST_SIZE)
127+
);
128+
api.loadMoreSubject.next(); // trigger refetch with loadMoreSubject
129+
130+
const subscription = api.availableOptions$.subscribe((options = []) => {
131+
if (options.length === totalCardinality) {
132+
api.selectAll(options.map(({ value }) => value as string) ?? []);
133+
subscription.unsubscribe();
134+
}
135+
});
136+
} else {
137+
api.selectAll(availableOptions.map(({ value }) => value as string) ?? []);
138+
}
125139
}}
126140
>
127141
Select all
128142
</EuiButtonEmpty>
129143
</EuiToolTip>
130-
<EuiButtonEmpty
131-
size="s"
132-
isDisabled={totalCardinality > 100}
133-
onClick={() => {
134-
const availableOptionValues = (
135-
availableOptions?.map(({ value }) => value as string) ?? []
136-
).filter((value) => selectedOptions.includes(value));
137-
availableOptionValues.forEach((value: string) => {
138-
api.makeSelection(value, showOnlySelected);
139-
});
140-
}}
144+
<EuiToolTip
145+
content={
146+
totalCardinality > 100
147+
? 'Bulk selection is only available for less than 100 options'
148+
: undefined
149+
}
141150
>
142-
Deselect all
143-
</EuiButtonEmpty>
151+
<EuiButtonEmpty
152+
size="s"
153+
isDisabled={!availableOptions || totalCardinality < 1 || totalCardinality > 100}
154+
onClick={() => {
155+
if (
156+
availableOptions.length > 0 &&
157+
totalCardinality > availableOptions.length
158+
) {
159+
// load more options
160+
stateManager.requestSize.next(
161+
Math.min(totalCardinality, MAX_OPTIONS_LIST_REQUEST_SIZE)
162+
);
163+
api.loadMoreSubject.next(); // trigger refetch with loadMoreSubject
164+
165+
const subscription = api.availableOptions$.subscribe((options = []) => {
166+
if (options.length === totalCardinality) {
167+
api.deselectAll(options.map(({ value }) => value as string) ?? []);
168+
subscription.unsubscribe();
169+
}
170+
});
171+
} else {
172+
api.deselectAll(availableOptions.map(({ value }) => value as string) ?? []);
173+
}
174+
}}
175+
>
176+
Deselect all
177+
</EuiButtonEmpty>
178+
</EuiToolTip>
144179
</EuiText>
145180
</EuiFlexItem>
146181
)}

src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,34 @@ export const getOptionsListControlFactory = (): DataControlFactory<
422422
);
423423
}
424424
},
425+
selectAll: (keys: string[]) => {
426+
const field = api.field$.getValue();
427+
if (keys.length < 1 || !field) {
428+
api.setBlockingError(
429+
new Error(OptionsListStrings.control.getInvalidSelectionMessage())
430+
);
431+
return;
432+
}
433+
434+
const selectedOptions = stateManager.selectedOptions.getValue() ?? [];
435+
const newSelections = keys.filter((value) => !selectedOptions.includes(value as string));
436+
selections.internalApi.setSelectedOptions([...selectedOptions, ...newSelections]);
437+
},
438+
deselectAll: (keys: string[]) => {
439+
const field = api.field$.getValue();
440+
if (keys.length < 1 || !field) {
441+
api.setBlockingError(
442+
new Error(OptionsListStrings.control.getInvalidSelectionMessage())
443+
);
444+
return;
445+
}
446+
447+
const selectedOptions = stateManager.selectedOptions.getValue() ?? [];
448+
const remainingSelections = selectedOptions.filter(
449+
(option) => !keys.includes(option as string)
450+
);
451+
selections.internalApi.setSelectedOptions(remainingSelections);
452+
},
425453
};
426454

427455
if (selections.internalApi.hasInitialSelections) {

src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export type OptionsListComponentApi = OptionsListControlApi &
3939
PublishesOptions & {
4040
deselectOption: (key: string | undefined) => void;
4141
makeSelection: (key: string | undefined, showOnlySelected: boolean) => void;
42+
selectAll: (keys: string[]) => void;
43+
deselectAll: (keys: string[]) => void;
4244
loadMoreSubject: Subject<void>;
4345
setExclude: (next: boolean | undefined) => void;
4446
};

0 commit comments

Comments
 (0)