mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Fix unhandledRejections
part 2 (#169522)
This commit is contained in:
parent
e9b6898d73
commit
dfec895836
12 changed files with 330 additions and 286 deletions
|
@ -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()
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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]> = [
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue