Fix unhandledRejections part 2 (#169522)

This commit is contained in:
Alejandro Fernández Haro 2023-11-05 00:31:44 +01:00 committed by GitHub
parent e9b6898d73
commit dfec895836
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 330 additions and 286 deletions

View file

@ -10,7 +10,7 @@ import ReactDOM from 'react-dom';
import { batch } from 'react-redux';
import deepEqual from 'fast-deep-equal';
import { isEmpty, isEqual } from 'lodash';
import { merge, Subject, Subscription } from 'rxjs';
import { merge, Subject, Subscription, switchMap, tap } from 'rxjs';
import React, { createContext, useContext } from 'react';
import { debounceTime, map, distinctUntilChanged, skip } from 'rxjs/operators';
@ -207,30 +207,33 @@ export class OptionsListEmbeddable
a.exclude === b.exclude &&
a.existsSelected === b.existsSelected &&
isEqual(a.selectedOptions, b.selectedOptions)
)
)
.subscribe(async ({ selectedOptions: newSelectedOptions }) => {
if (!newSelectedOptions || isEmpty(newSelectedOptions)) {
this.dispatch.clearValidAndInvalidSelections({});
} else {
const { invalidSelections } = this.getState().componentState ?? {};
const newValidSelections: string[] = [];
const newInvalidSelections: string[] = [];
for (const selectedOption of newSelectedOptions) {
if (invalidSelections?.includes(selectedOption)) {
newInvalidSelections.push(selectedOption);
continue;
),
tap(({ selectedOptions: newSelectedOptions }) => {
if (!newSelectedOptions || isEmpty(newSelectedOptions)) {
this.dispatch.clearValidAndInvalidSelections({});
} else {
const { invalidSelections } = this.getState().componentState ?? {};
const newValidSelections: string[] = [];
const newInvalidSelections: string[] = [];
for (const selectedOption of newSelectedOptions) {
if (invalidSelections?.includes(selectedOption)) {
newInvalidSelections.push(selectedOption);
continue;
}
newValidSelections.push(selectedOption);
}
newValidSelections.push(selectedOption);
this.dispatch.setValidAndInvalidSelections({
validSelections: newValidSelections,
invalidSelections: newInvalidSelections,
});
}
this.dispatch.setValidAndInvalidSelections({
validSelections: newValidSelections,
invalidSelections: newInvalidSelections,
});
}
const newFilters = await this.buildFilter();
this.dispatch.publishFilters(newFilters);
})
}),
switchMap(async () => {
const newFilters = await this.buildFilter();
this.dispatch.publishFilters(newFilters);
})
)
.subscribe()
);
};

View file

@ -12,7 +12,7 @@ import { isEmpty } from 'lodash';
import { batch } from 'react-redux';
import { get, isEqual } from 'lodash';
import deepEqual from 'fast-deep-equal';
import { Subscription, lastValueFrom } from 'rxjs';
import { Subscription, lastValueFrom, switchMap } from 'rxjs';
import { distinctUntilChanged, skip, map } from 'rxjs/operators';
import {
@ -168,14 +168,18 @@ export class RangeSliderEmbeddable
// fetch available min/max when input changes
this.subscriptions.add(
dataFetchPipe.subscribe(async (changes) => {
try {
await this.runRangeSliderQuery();
await this.buildFilter();
} catch (e) {
this.onLoadingError(e.message);
}
})
dataFetchPipe
.pipe(
switchMap(async (changes) => {
try {
await this.runRangeSliderQuery();
await this.buildFilter();
} catch (e) {
this.onLoadingError(e.message);
}
})
)
.subscribe()
);
// build filters when value changes
@ -183,9 +187,10 @@ export class RangeSliderEmbeddable
this.getInput$()
.pipe(
distinctUntilChanged((a, b) => isEqual(a.value ?? ['', ''], b.value ?? ['', ''])),
skip(1) // skip the first input update because initial filters will be built by initialize.
skip(1), // skip the first input update because initial filters will be built by initialize.
switchMap(this.buildFilter)
)
.subscribe(this.buildFilter)
.subscribe()
);
};

View file

@ -10,6 +10,7 @@ import { isOfAggregateQueryType, getAggregateQueryMode } from '@kbn/es-query';
import { useCallback, useEffect, useRef } from 'react';
import type { DataViewsContract } from '@kbn/data-views-plugin/public';
import { VIEW_MODE } from '@kbn/saved-search-plugin/public';
import { switchMap } from 'rxjs';
import { useSavedSearchInitial } from '../services/discover_state_provider';
import type { DiscoverStateContainer } from '../services/discover_state';
import { getValidViewMode } from '../utils/get_valid_view_mode';
@ -51,86 +52,90 @@ export function useTextBasedQueryLanguage({
}, []);
useEffect(() => {
const subscription = stateContainer.dataState.data$.documents$.subscribe(async (next) => {
const { query, recordRawType } = next;
if (!query || next.fetchStatus === FetchStatus.ERROR) {
return;
}
const sendComplete = () => {
stateContainer.dataState.data$.documents$.next({
...next,
fetchStatus: FetchStatus.COMPLETE,
});
};
const { index, viewMode } = stateContainer.appState.getState();
let nextColumns: string[] = [];
const isTextBasedQueryLang =
recordRawType === 'plain' &&
isOfAggregateQueryType(query) &&
('sql' in query || 'esql' in query);
const hasResults = Boolean(next.result?.length);
let queryHasTransformationalCommands = 'sql' in query;
if ('esql' in query) {
TRANSFORMATIONAL_COMMANDS.forEach((command: string) => {
if (query.esql.toLowerCase().includes(command)) {
queryHasTransformationalCommands = true;
const subscription = stateContainer.dataState.data$.documents$
.pipe(
switchMap(async (next) => {
const { query, recordRawType } = next;
if (!query || next.fetchStatus === FetchStatus.ERROR) {
return;
}
});
}
if (isTextBasedQueryLang) {
const language = getAggregateQueryMode(query);
if (next.fetchStatus !== FetchStatus.PARTIAL) {
return;
}
const dataViewObj = stateContainer.internalState.getState().dataView!;
if (hasResults) {
// check if state needs to contain column transformation due to a different columns in the resultset
const firstRow = next.result![0];
const firstRowColumns = Object.keys(firstRow.raw).slice(0, MAX_NUM_OF_COLUMNS);
if (!queryHasTransformationalCommands) {
nextColumns = [];
initialFetch.current = false;
} else {
nextColumns = firstRowColumns;
if (
initialFetch.current &&
!prev.current.columns.length &&
Boolean(dataViewObj?.id === index)
) {
prev.current.columns = firstRowColumns;
}
const sendComplete = () => {
stateContainer.dataState.data$.documents$.next({
...next,
fetchStatus: FetchStatus.COMPLETE,
});
};
const { index, viewMode } = stateContainer.appState.getState();
let nextColumns: string[] = [];
const isTextBasedQueryLang =
recordRawType === 'plain' &&
isOfAggregateQueryType(query) &&
('sql' in query || 'esql' in query);
const hasResults = Boolean(next.result?.length);
let queryHasTransformationalCommands = 'sql' in query;
if ('esql' in query) {
TRANSFORMATIONAL_COMMANDS.forEach((command: string) => {
if (query.esql.toLowerCase().includes(command)) {
queryHasTransformationalCommands = true;
return;
}
});
}
}
const addColumnsToState = !isEqual(nextColumns, prev.current.columns);
const queryChanged = query[language] !== prev.current.query;
// no need to reset index to state if it hasn't changed
const addDataViewToState = Boolean(dataViewObj?.id !== index);
if (!queryChanged || (!addDataViewToState && !addColumnsToState)) {
sendComplete();
return;
}
if (queryChanged) {
prev.current.query = query[language];
prev.current.columns = nextColumns;
}
const nextState = {
...(addDataViewToState && { index: dataViewObj.id }),
...((addColumnsToState || queryChanged) && { columns: nextColumns }),
...(viewMode === VIEW_MODE.AGGREGATED_LEVEL && {
viewMode: getValidViewMode({ viewMode, isTextBasedQueryMode: true }),
}),
};
await stateContainer.appState.replaceUrlState(nextState);
sendComplete();
} else {
// cleanup for a "regular" query
cleanup();
}
});
if (isTextBasedQueryLang) {
const language = getAggregateQueryMode(query);
if (next.fetchStatus !== FetchStatus.PARTIAL) {
return;
}
const dataViewObj = stateContainer.internalState.getState().dataView!;
if (hasResults) {
// check if state needs to contain column transformation due to a different columns in the resultset
const firstRow = next.result![0];
const firstRowColumns = Object.keys(firstRow.raw).slice(0, MAX_NUM_OF_COLUMNS);
if (!queryHasTransformationalCommands) {
nextColumns = [];
initialFetch.current = false;
} else {
nextColumns = firstRowColumns;
if (
initialFetch.current &&
!prev.current.columns.length &&
Boolean(dataViewObj?.id === index)
) {
prev.current.columns = firstRowColumns;
}
}
}
const addColumnsToState = !isEqual(nextColumns, prev.current.columns);
const queryChanged = query[language] !== prev.current.query;
// no need to reset index to state if it hasn't changed
const addDataViewToState = Boolean(dataViewObj?.id !== index);
if (!queryChanged || (!addDataViewToState && !addColumnsToState)) {
sendComplete();
return;
}
if (queryChanged) {
prev.current.query = query[language];
prev.current.columns = nextColumns;
}
const nextState = {
...(addDataViewToState && { index: dataViewObj.id }),
...((addColumnsToState || queryChanged) && { columns: nextColumns }),
...(viewMode === VIEW_MODE.AGGREGATED_LEVEL && {
viewMode: getValidViewMode({ viewMode, isTextBasedQueryMode: true }),
}),
};
await stateContainer.appState.replaceUrlState(nextState);
sendComplete();
} else {
// cleanup for a "regular" query
cleanup();
}
})
)
.subscribe();
return () => {
// cleanup for e.g. when savedSearch is switched
cleanup();

View file

@ -5,7 +5,7 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { BehaviorSubject, filter, map, Observable, share, Subject, tap } from 'rxjs';
import { BehaviorSubject, filter, map, mergeMap, Observable, share, Subject, tap } from 'rxjs';
import type { AutoRefreshDoneFn } from '@kbn/data-plugin/public';
import type { DatatableColumn } from '@kbn/expressions-plugin/common';
import { RequestAdapter } from '@kbn/inspector-plugin/common';
@ -219,60 +219,64 @@ export function getDataStateContainer({
let abortControllerFetchMore: AbortController;
function subscribe() {
const subscription = fetch$.subscribe(async ({ options, searchSessionId }) => {
const commonFetchDeps = {
initialFetchStatus: getInitialFetchStatus(),
inspectorAdapters,
searchSessionId,
services,
getAppState,
getInternalState,
savedSearch: getSavedSearch(),
useNewFieldsApi: !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE),
};
const subscription = fetch$
.pipe(
mergeMap(async ({ options, searchSessionId }) => {
const commonFetchDeps = {
initialFetchStatus: getInitialFetchStatus(),
inspectorAdapters,
searchSessionId,
services,
getAppState,
getInternalState,
savedSearch: getSavedSearch(),
useNewFieldsApi: !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE),
};
abortController?.abort();
abortControllerFetchMore?.abort();
abortController?.abort();
abortControllerFetchMore?.abort();
if (options.fetchMore) {
abortControllerFetchMore = new AbortController();
if (options.fetchMore) {
abortControllerFetchMore = new AbortController();
const fetchMoreStartTime = window.performance.now();
await fetchMoreDocuments(dataSubjects, {
abortController: abortControllerFetchMore,
...commonFetchDeps,
});
const fetchMoreDuration = window.performance.now() - fetchMoreStartTime;
reportPerformanceMetricEvent(services.analytics, {
eventName: 'discoverFetchMore',
duration: fetchMoreDuration,
});
return;
}
const fetchMoreStartTime = window.performance.now();
await fetchMoreDocuments(dataSubjects, {
abortController: abortControllerFetchMore,
...commonFetchDeps,
});
const fetchMoreDuration = window.performance.now() - fetchMoreStartTime;
reportPerformanceMetricEvent(services.analytics, {
eventName: 'discoverFetchMore',
duration: fetchMoreDuration,
});
return;
}
abortController = new AbortController();
const prevAutoRefreshDone = autoRefreshDone;
abortController = new AbortController();
const prevAutoRefreshDone = autoRefreshDone;
const fetchAllStartTime = window.performance.now();
await fetchAll(dataSubjects, options.reset, {
abortController,
...commonFetchDeps,
});
const fetchAllDuration = window.performance.now() - fetchAllStartTime;
reportPerformanceMetricEvent(services.analytics, {
eventName: 'discoverFetchAll',
duration: fetchAllDuration,
});
const fetchAllStartTime = window.performance.now();
await fetchAll(dataSubjects, options.reset, {
abortController,
...commonFetchDeps,
});
const fetchAllDuration = window.performance.now() - fetchAllStartTime;
reportPerformanceMetricEvent(services.analytics, {
eventName: 'discoverFetchAll',
duration: fetchAllDuration,
});
// If the autoRefreshCallback is still the same as when we started i.e. there was no newer call
// replacing this current one, call it to make sure we tell that the auto refresh is done
// and a new one can be scheduled.
if (autoRefreshDone === prevAutoRefreshDone) {
// if this function was set and is executed, another refresh fetch can be triggered
autoRefreshDone?.();
autoRefreshDone = undefined;
}
});
// If the autoRefreshCallback is still the same as when we started i.e. there was no newer call
// replacing this current one, call it to make sure we tell that the auto refresh is done
// and a new one can be scheduled.
if (autoRefreshDone === prevAutoRefreshDone) {
// if this function was set and is executed, another refresh fetch can be triggered
autoRefreshDone?.();
autoRefreshDone = undefined;
}
})
)
.subscribe();
return () => {
abortController?.abort();

View file

@ -7,7 +7,7 @@
*/
import _, { get } from 'lodash';
import { Subscription, ReplaySubject } from 'rxjs';
import { Subscription, ReplaySubject, mergeMap } from 'rxjs';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { render } from 'react-dom';
@ -474,27 +474,34 @@ export class VisualizeEmbeddable
});
this.subscriptions.push(
this.handler.events$.subscribe(async (event) => {
if (!this.input.disableTriggers) {
const triggerId = get(VIS_EVENT_TO_TRIGGER, event.name, VIS_EVENT_TO_TRIGGER.filter);
let context;
this.handler.events$
.pipe(
mergeMap(async (event) => {
if (!this.input.disableTriggers) {
const triggerId = get(VIS_EVENT_TO_TRIGGER, event.name, VIS_EVENT_TO_TRIGGER.filter);
let context;
if (triggerId === VIS_EVENT_TO_TRIGGER.applyFilter) {
context = {
embeddable: this,
timeFieldName: this.vis.data.indexPattern?.timeFieldName!,
...event.data,
};
} else {
context = {
embeddable: this,
data: { timeFieldName: this.vis.data.indexPattern?.timeFieldName!, ...event.data },
};
}
if (triggerId === VIS_EVENT_TO_TRIGGER.applyFilter) {
context = {
embeddable: this,
timeFieldName: this.vis.data.indexPattern?.timeFieldName!,
...event.data,
};
} else {
context = {
embeddable: this,
data: {
timeFieldName: this.vis.data.indexPattern?.timeFieldName!,
...event.data,
},
};
}
getUiActions().getTrigger(triggerId).exec(context);
}
})
await getUiActions().getTrigger(triggerId).exec(context);
}
})
)
.subscribe()
);
if (this.vis.description) {

View file

@ -13,6 +13,7 @@ import { i18n } from '@kbn/i18n';
import useLocalStorage from 'react-use/lib/useLocalStorage';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import type { DataView } from '@kbn/data-views-plugin/public';
import { switchMap } from 'rxjs';
import type {
VisualizeServices,
VisualizeAppState,
@ -234,19 +235,23 @@ const TopNav = ({
/** Synchronizing dataView with state **/
useEffect(() => {
const stateContainerSubscription = stateContainer.state$.subscribe(async ({ dataView }) => {
if (
dataView &&
visInstance.vis.data.indexPattern &&
dataView !== visInstance.vis.data.indexPattern.id
) {
const dataViewFromState = await services.dataViews.get(dataView);
const stateContainerSubscription = stateContainer.state$
.pipe(
switchMap(async ({ dataView }) => {
if (
dataView &&
visInstance.vis.data.indexPattern &&
dataView !== visInstance.vis.data.indexPattern.id
) {
const dataViewFromState = await services.dataViews.get(dataView);
if (dataViewFromState) {
setIndexPatterns([dataViewFromState]);
}
}
});
if (dataViewFromState) {
setIndexPatterns([dataViewFromState]);
}
}
})
)
.subscribe();
return () => {
stateContainerSubscription.unsubscribe();
};
@ -255,13 +260,16 @@ const TopNav = ({
useEffect(() => {
const autoRefreshFetchSub = services.data.query.timefilter.timefilter
.getAutoRefreshFetch$()
.subscribe(async (done) => {
try {
await doReload();
} finally {
done();
}
});
.pipe(
switchMap(async (done) => {
try {
await doReload();
} finally {
done();
}
})
)
.subscribe();
return () => {
autoRefreshFetchSub.unsubscribe();
};

View file

@ -66,7 +66,7 @@ export const LicensingLogic = kea<MakeLogicType<LicensingValues, LicensingAction
},
events: ({ props, actions, values }) => ({
afterMount: () => {
const licenseSubscription = props.license$.subscribe(async (license: ILicense) => {
const licenseSubscription = props.license$.subscribe((license: ILicense) => {
actions.setLicense(license);
});
actions.setLicenseSubscription(licenseSubscription);

View file

@ -32,7 +32,7 @@ import {
} from '@kbn/data-plugin/public';
import type { Start as InspectorStart } from '@kbn/inspector-plugin/public';
import { merge, Subscription } from 'rxjs';
import { merge, Subscription, switchMap } from 'rxjs';
import { toExpression } from '@kbn/interpreter';
import { DefaultInspectorAdapters, ErrorLike, RenderMode } from '@kbn/expressions-plugin/common';
import { map, distinctUntilChanged, skip, debounceTime } from 'rxjs/operators';
@ -545,18 +545,21 @@ export class Embeddable
// Merge and debounce the observables to avoid multiple reloads
this.inputReloadSubscriptions.push(
merge(searchContext$, attributesOrSavedObjectId$)
.pipe(debounceTime(0))
.subscribe(async ({ trigger, input }) => {
if (trigger === 'attributesOrSavedObjectId') {
await this.initializeSavedVis(input);
}
.pipe(
debounceTime(0),
switchMap(async ({ trigger, input }) => {
if (trigger === 'attributesOrSavedObjectId') {
await this.initializeSavedVis(input);
}
// reset removable messages
// Dashboard search/context changes are detected here
this.additionalUserMessages = {};
// reset removable messages
// Dashboard search/context changes are detected here
this.additionalUserMessages = {};
this.reload();
})
this.reload();
})
)
.subscribe()
);
}

View file

@ -13,7 +13,7 @@ import type {
Plugin,
PluginInitializerContext,
} from '@kbn/core/public';
import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject, mergeMap } from 'rxjs';
import { take } from 'rxjs/operators';
import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
@ -204,65 +204,69 @@ export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> {
}
const licensing = pluginsSetup.licensing.license$.pipe(take(1));
licensing.subscribe(async (license) => {
const mlEnabled = isMlEnabled(license);
const fullLicense = isFullLicense(license);
const [coreStart, pluginStart] = await core.getStartServices();
const { capabilities } = coreStart.application;
const mlCapabilities = capabilities.ml as MlCapabilities;
licensing
.pipe(
mergeMap(async (license) => {
const mlEnabled = isMlEnabled(license);
const fullLicense = isFullLicense(license);
const [coreStart, pluginStart] = await core.getStartServices();
const { capabilities } = coreStart.application;
const mlCapabilities = capabilities.ml as MlCapabilities;
// register various ML plugin features which require a full license
// note including registerHomeFeature in register_helper would cause the page bundle size to increase significantly
if (mlEnabled) {
// add ML to home page
if (pluginsSetup.home) {
registerHomeFeature(pluginsSetup.home);
}
const {
registerEmbeddables,
registerMlUiActions,
registerSearchLinks,
registerMlAlerts,
registerMapExtension,
registerCasesAttachments,
} = await import('./register_helper');
registerSearchLinks(this.appUpdater$, fullLicense, mlCapabilities, !this.isServerless);
if (fullLicense) {
registerMlUiActions(pluginsSetup.uiActions, core);
if (this.enabledFeatures.ad) {
registerEmbeddables(pluginsSetup.embeddable, core);
if (pluginsSetup.cases) {
registerCasesAttachments(pluginsSetup.cases, coreStart, pluginStart);
// register various ML plugin features which require a full license
// note including registerHomeFeature in register_helper would cause the page bundle size to increase significantly
if (mlEnabled) {
// add ML to home page
if (pluginsSetup.home) {
registerHomeFeature(pluginsSetup.home);
}
if (
pluginsSetup.triggersActionsUi &&
mlCapabilities.canUseMlAlerts &&
mlCapabilities.canGetJobs
) {
registerMlAlerts(pluginsSetup.triggersActionsUi, pluginsSetup.alerting);
}
const {
registerEmbeddables,
registerMlUiActions,
registerSearchLinks,
registerMlAlerts,
registerMapExtension,
registerCasesAttachments,
} = await import('./register_helper');
registerSearchLinks(this.appUpdater$, fullLicense, mlCapabilities, !this.isServerless);
if (pluginsSetup.maps) {
// Pass canGetJobs as minimum permission to show anomalies card in maps layers
await registerMapExtension(pluginsSetup.maps, core, {
canGetJobs: mlCapabilities.canGetJobs,
canCreateJobs: mlCapabilities.canCreateJob,
});
if (fullLicense) {
registerMlUiActions(pluginsSetup.uiActions, core);
if (this.enabledFeatures.ad) {
registerEmbeddables(pluginsSetup.embeddable, core);
if (pluginsSetup.cases) {
registerCasesAttachments(pluginsSetup.cases, coreStart, pluginStart);
}
if (
pluginsSetup.triggersActionsUi &&
mlCapabilities.canUseMlAlerts &&
mlCapabilities.canGetJobs
) {
registerMlAlerts(pluginsSetup.triggersActionsUi, pluginsSetup.alerting);
}
if (pluginsSetup.maps) {
// Pass canGetJobs as minimum permission to show anomalies card in maps layers
await registerMapExtension(pluginsSetup.maps, core, {
canGetJobs: mlCapabilities.canGetJobs,
canCreateJobs: mlCapabilities.canCreateJob,
});
}
}
}
} else {
// if ml is disabled in elasticsearch, disable ML in kibana
this.appUpdater$.next(() => ({
status: AppStatus.inaccessible,
}));
}
}
} else {
// if ml is disabled in elasticsearch, disable ML in kibana
this.appUpdater$.next(() => ({
status: AppStatus.inaccessible,
}));
}
});
})
)
.subscribe();
return {
locator: this.locator,

View file

@ -6,7 +6,7 @@
*/
import type { Subscription } from 'rxjs';
import { filter } from 'rxjs';
import { filter, switchMap } from 'rxjs';
import { throttleTime } from 'rxjs/operators';
import type {
@ -58,15 +58,16 @@ export class AnalyticsService {
this.securityFeaturesSubscription = this.securityLicense.features$
.pipe(
filter(({ allowLogin }) => allowLogin),
throttleTime(5000)
throttleTime(5000),
switchMap(async () => {
try {
await AnalyticsService.recordAuthTypeAnalytics(http);
} catch {
// do nothing
}
})
)
.subscribe(async () => {
try {
await AnalyticsService.recordAuthTypeAnalytics(http);
} catch {
// do nothing
}
});
.subscribe();
}
public stop() {

View file

@ -66,7 +66,7 @@ export class ManagementService {
}
start({ capabilities, uiConfig }: StartParams) {
this.licenseFeaturesSubscription = this.license.features$.subscribe(async (features) => {
this.licenseFeaturesSubscription = this.license.features$.subscribe((features) => {
const securitySection = this.securitySection!;
const securityManagementAppsStatuses: Array<[ManagementApp, boolean]> = [

View file

@ -6,7 +6,7 @@
*/
import { i18n } from '@kbn/i18n';
import { Subject } from 'rxjs';
import { Subject, mergeMap } from 'rxjs';
import type * as H from 'history';
import type {
AppMountParameters,
@ -532,18 +532,22 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
capabilities: core.application.capabilities,
};
license$.subscribe(async (license) => {
const linksPermissions: LinksPermissions = {
...baseLinksPermissions,
...(license.type != null && { license }),
};
license$
.pipe(
mergeMap(async (license) => {
const linksPermissions: LinksPermissions = {
...baseLinksPermissions,
...(license.type != null && { license }),
};
// set initial links to not block rendering
updateAppLinks(appLinksSwitcher(links), linksPermissions);
// set initial links to not block rendering
updateAppLinks(appLinksSwitcher(links), linksPermissions);
// set filtered links asynchronously
const filteredLinks = await getFilteredLinks(core, plugins);
updateAppLinks(appLinksSwitcher(filteredLinks), linksPermissions);
});
// set filtered links asynchronously
const filteredLinks = await getFilteredLinks(core, plugins);
updateAppLinks(appLinksSwitcher(filteredLinks), linksPermissions);
})
)
.subscribe();
}
}