[controls] fix option list control making 2 requests on refresh (#219625)

Fixes https://github.com/elastic/kibana/issues/218663
This commit is contained in:
Nathan Reese 2025-04-29 16:56:52 -06:00 committed by GitHub
parent ae88fa8549
commit f13c764115
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 13 additions and 27 deletions

View file

@ -10,7 +10,7 @@
import { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query';
import { PublishesUnifiedSearch, PublishingSubject } from '@kbn/presentation-publishing';
import { apiPublishesReload } from '@kbn/presentation-publishing/interfaces/fetch/publishes_reload';
import { BehaviorSubject, debounceTime, map, merge, Observable, switchMap } from 'rxjs';
import { BehaviorSubject, debounceTime, map, merge, Observable, switchMap, tap } from 'rxjs';
import { ParentIgnoreSettings } from '../../../common';
export interface ControlGroupFetchContext {
@ -23,7 +23,8 @@ export function controlGroupFetch$(
ignoreParentSettings$: PublishingSubject<ParentIgnoreSettings | undefined>,
parentApi: Partial<PublishesUnifiedSearch> & {
unifiedSearchFilters$?: PublishingSubject<Filter[] | undefined>;
}
},
onReload?: () => void
): Observable<ControlGroupFetchContext> {
return ignoreParentSettings$.pipe(
switchMap((parentIgnoreSettings) => {
@ -40,7 +41,7 @@ export function controlGroupFetch$(
observables.push(parentApi.timeRange$);
}
if (apiPublishesReload(parentApi)) {
observables.push(parentApi.reload$);
observables.push(onReload ? parentApi.reload$.pipe(tap(onReload)) : parentApi.reload$);
}
return observables.length ? merge(...observables) : new BehaviorSubject(undefined);
}),

View file

@ -135,7 +135,7 @@ export const getControlGroupEmbeddableFactory = () => {
disabledActionIds$,
...unsavedChanges.api,
...selectionsManager.api,
controlFetch$: (controlUuid: string) =>
controlFetch$: (controlUuid: string, onReload?: () => void) =>
controlFetch$(
chaining$(
controlUuid,
@ -143,7 +143,7 @@ export const getControlGroupEmbeddableFactory = () => {
controlsManager.controlsInOrder$,
controlsManager.api.children$
),
controlGroupFetch$(ignoreParentSettings$, parentApi ? parentApi : {})
controlGroupFetch$(ignoreParentSettings$, parentApi ? parentApi : {}, onReload)
),
ignoreParentSettings$,
autoApplySelections$,

View file

@ -65,7 +65,7 @@ export type ControlGroupApi = PresentationContainer &
labelPosition: PublishingSubject<ControlLabelPosition>;
asyncResetUnsavedChanges: () => Promise<void>;
controlFetch$: (controlUuid: string) => Observable<ControlFetchContext>;
controlFetch$: (controlUuid: string, onReload?: () => void) => Observable<ControlFetchContext>;
openAddDataControlFlyout: (options?: {
controlStateTransform?: ControlStateTransform;
onSave?: () => void;

View file

@ -12,7 +12,6 @@ import {
combineLatest,
debounceTime,
Observable,
of,
startWith,
switchMap,
tap,
@ -20,7 +19,6 @@ import {
} from 'rxjs';
import { PublishingSubject } from '@kbn/presentation-publishing';
import { apiPublishesReload } from '@kbn/presentation-publishing/interfaces/fetch/publishes_reload';
import { OptionsListSuccessResponse } from '../../../../common/options_list/types';
import { isValidSearch } from '../../../../common/options_list/is_valid_search';
import { OptionsListSelection } from '../../../../common/options_list/options_list_selections';
@ -32,10 +30,10 @@ import { OptionsListComponentApi, OptionsListComponentState, OptionsListControlA
export function fetchAndValidate$({
api,
stateManager,
controlFetch$,
}: {
api: Pick<OptionsListControlApi, 'dataViews$' | 'field$' | 'setBlockingError' | 'parentApi'> &
Pick<OptionsListComponentApi, 'loadMoreSubject'> & {
controlFetch$: Observable<ControlFetchContext>;
loadingSuggestions$: BehaviorSubject<boolean>;
debouncedSearchString: Observable<string>;
};
@ -44,6 +42,7 @@ export function fetchAndValidate$({
> & {
selectedOptions: PublishingSubject<OptionsListSelection[] | undefined>;
};
controlFetch$: (onReload: () => void) => Observable<ControlFetchContext>;
}): Observable<OptionsListSuccessResponse | { error: Error }> {
const requestCache = new OptionsListFetchCache();
let abortController: AbortController | undefined;
@ -51,7 +50,7 @@ export function fetchAndValidate$({
return combineLatest([
api.dataViews$,
api.field$,
api.controlFetch$,
controlFetch$(requestCache.clearCache),
api.parentApi.allowExpensiveQueries$,
api.parentApi.ignoreParentSettings$,
api.debouncedSearchString,
@ -62,12 +61,6 @@ export function fetchAndValidate$({
startWith(null), // start with null so that `combineLatest` subscription fires
debounceTime(100) // debounce load more so "loading" state briefly shows
),
apiPublishesReload(api.parentApi)
? api.parentApi.reload$.pipe(
tap(() => requestCache.clearCache()),
startWith(undefined)
)
: of(undefined),
]).pipe(
tap(() => {
// abort any in progress requests

View file

@ -185,9 +185,9 @@ export const getOptionsListControlFactory = (): DataControlFactory<
loadingSuggestions$,
debouncedSearchString,
parentApi: controlGroupApi,
controlFetch$: controlGroupApi.controlFetch$(uuid),
},
stateManager,
controlFetch$: (onReload: () => void) => controlGroupApi.controlFetch$(uuid, onReload),
}).subscribe((result) => {
// if there was an error during fetch, set blocking error and return early
if (Object.hasOwn(result, 'error')) {

View file

@ -11,8 +11,7 @@ import type { estypes } from '@elastic/elasticsearch';
import { DataView, DataViewField } from '@kbn/data-views-plugin/public';
import { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query';
import { PublishesDataViews, PublishingSubject } from '@kbn/presentation-publishing';
import { apiPublishesReload } from '@kbn/presentation-publishing/interfaces/fetch/publishes_reload';
import { Observable, combineLatest, lastValueFrom, of, startWith, switchMap, tap } from 'rxjs';
import { Observable, combineLatest, lastValueFrom, switchMap, tap } from 'rxjs';
import { dataService } from '../../../services/kibana_services';
import { ControlFetchContext } from '../../../control_group/control_fetch';
import { ControlGroupApi } from '../../../control_group/types';
@ -31,14 +30,7 @@ export function minMax$({
setIsLoading: (isLoading: boolean) => void;
}) {
let prevRequestAbortController: AbortController | undefined;
return combineLatest([
controlFetch$,
dataViews$,
fieldName$,
apiPublishesReload(controlGroupApi)
? controlGroupApi.reload$.pipe(startWith(undefined))
: of(undefined),
]).pipe(
return combineLatest([controlFetch$, dataViews$, fieldName$]).pipe(
tap(() => {
if (prevRequestAbortController) {
prevRequestAbortController.abort();