mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[Discover] Optimize Discover plugin page load bundle (#208298)](https://github.com/elastic/kibana/pull/208298) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Davis McPhee","email":"davis.mcphee@elastic.co"},"sourceCommit":{"committedDate":"2025-03-11T20:30:25Z","message":"[Discover] Optimize Discover plugin page load bundle (#208298)\n\n## Summary\n\nThis PR optimizes the Discover page load bundle by reducing it to only\ncode which is actually required on startup, and dynamically loading\nother code when it's needed, resulting in a 55% decrease in the bundle\nsize.\n\nBefore (44.15 KB):\n\n\n\nAfter (20.12 KB):\n\n\n\n### Checklist\n\n- [ ] Any text added follows [EUI's writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\nsentence case text and includes [i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n- [ ]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas added for features that require explanation or tutorials\n- [ ] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [ ] If a plugin configuration key changed, check if it needs to be\nallowlisted in the cloud and added to the [docker\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\n- [ ] This was checked for breaking HTTP API changes, and any breaking\nchanges have been approved by the breaking-change committee. The\n`release_note:breaking` label should be applied in these situations.\n- [ ] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n- [x] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n---------\n\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"e1bffa6a9b6a82e347b1c1f4dbfaa7571fff546b","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Feature:Discover","release_note:skip","backport missing","Team:DataDiscovery","backport:version","v9.1.0","v8.19.0"],"title":"[Discover] Optimize Discover plugin page load bundle","number":208298,"url":"https://github.com/elastic/kibana/pull/208298","mergeCommit":{"message":"[Discover] Optimize Discover plugin page load bundle (#208298)\n\n## Summary\n\nThis PR optimizes the Discover page load bundle by reducing it to only\ncode which is actually required on startup, and dynamically loading\nother code when it's needed, resulting in a 55% decrease in the bundle\nsize.\n\nBefore (44.15 KB):\n\n\n\nAfter (20.12 KB):\n\n\n\n### Checklist\n\n- [ ] Any text added follows [EUI's writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\nsentence case text and includes [i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n- [ ]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas added for features that require explanation or tutorials\n- [ ] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [ ] If a plugin configuration key changed, check if it needs to be\nallowlisted in the cloud and added to the [docker\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\n- [ ] This was checked for breaking HTTP API changes, and any breaking\nchanges have been approved by the breaking-change committee. The\n`release_note:breaking` label should be applied in these situations.\n- [ ] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n- [x] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n---------\n\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"e1bffa6a9b6a82e347b1c1f4dbfaa7571fff546b"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/208298","number":208298,"mergeCommit":{"message":"[Discover] Optimize Discover plugin page load bundle (#208298)\n\n## Summary\n\nThis PR optimizes the Discover page load bundle by reducing it to only\ncode which is actually required on startup, and dynamically loading\nother code when it's needed, resulting in a 55% decrease in the bundle\nsize.\n\nBefore (44.15 KB):\n\n\n\nAfter (20.12 KB):\n\n\n\n### Checklist\n\n- [ ] Any text added follows [EUI's writing\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\nsentence case text and includes [i18n\nsupport](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)\n- [ ]\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\nwas added for features that require explanation or tutorials\n- [ ] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n- [ ] If a plugin configuration key changed, check if it needs to be\nallowlisted in the cloud and added to the [docker\nlist](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)\n- [ ] This was checked for breaking HTTP API changes, and any breaking\nchanges have been approved by the breaking-change committee. The\n`release_note:breaking` label should be applied in these situations.\n- [ ] [Flaky Test\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\nused on any tests changed\n- [x] The PR description includes the appropriate Release Notes section,\nand the correct `release_note:*` label is applied per the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n---------\n\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"e1bffa6a9b6a82e347b1c1f4dbfaa7571fff546b"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT-->
This commit is contained in:
parent
ccc2c36864
commit
6d2411ffdc
47 changed files with 991 additions and 739 deletions
|
@ -35,7 +35,7 @@ pageLoadAssetSize:
|
|||
dataViews: 65000
|
||||
dataVisualizer: 30000
|
||||
devTools: 38637
|
||||
discover: 99999
|
||||
discover: 25000
|
||||
discoverEnhanced: 42730
|
||||
discoverShared: 17111
|
||||
embeddable: 24000
|
||||
|
|
|
@ -14,9 +14,11 @@ import {
|
|||
} from '@kbn/kibana-utils-plugin/public';
|
||||
import { mockStorage } from '@kbn/kibana-utils-plugin/public/storage/hashed_item_store/mock';
|
||||
import { FilterStateStore } from '@kbn/es-query';
|
||||
import { DiscoverAppLocatorDefinition } from './app_locator';
|
||||
import type { DiscoverAppLocatorParams } from './app_locator';
|
||||
import { DISCOVER_APP_LOCATOR } from './app_locator';
|
||||
import type { SerializableRecord } from '@kbn/utility-types';
|
||||
import { createDataViewDataSource, createEsqlDataSource } from './data_sources';
|
||||
import { appLocatorGetLocationCommon } from './app_locator_get_location';
|
||||
|
||||
const dataViewId: string = 'c367b774-a4c2-11ea-bb37-0242ac130002';
|
||||
const savedSearchId: string = '571aaf70-4c88-11e8-b3d7-01146121b73d';
|
||||
|
@ -26,11 +28,14 @@ interface SetupParams {
|
|||
}
|
||||
|
||||
const setup = async ({ useHash = false }: SetupParams = {}) => {
|
||||
const locator = new DiscoverAppLocatorDefinition({ useHash, setStateToKbnUrl });
|
||||
|
||||
return {
|
||||
locator,
|
||||
const locator = {
|
||||
id: DISCOVER_APP_LOCATOR,
|
||||
getLocation: (params: DiscoverAppLocatorParams) => {
|
||||
return appLocatorGetLocationCommon({ useHash, setStateToKbnUrl }, params);
|
||||
},
|
||||
};
|
||||
|
||||
return { locator };
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -267,7 +272,7 @@ describe('Discover url generator', () => {
|
|||
const { locator } = await setup();
|
||||
const { state } = await locator.getLocation({ dataViewSpec: dataViewSpecMock });
|
||||
|
||||
expect(state.dataViewSpec).toEqual(dataViewSpecMock);
|
||||
expect((state as Record<string, unknown>).dataViewSpec).toEqual(dataViewSpecMock);
|
||||
});
|
||||
|
||||
describe('useHash property', () => {
|
||||
|
|
|
@ -9,15 +9,11 @@
|
|||
|
||||
import type { SerializableRecord } from '@kbn/utility-types';
|
||||
import type { Filter, TimeRange, Query, AggregateQuery } from '@kbn/es-query';
|
||||
import { isOfAggregateQueryType } from '@kbn/es-query';
|
||||
import type { GlobalQueryStateFromUrl, RefreshInterval } from '@kbn/data-plugin/public';
|
||||
import type { RefreshInterval } from '@kbn/data-plugin/public';
|
||||
import type { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public';
|
||||
import type { DiscoverGridSettings } from '@kbn/saved-search-plugin/common';
|
||||
import type { DataViewSpec } from '@kbn/data-views-plugin/common';
|
||||
import type { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/common';
|
||||
import type { VIEW_MODE } from './constants';
|
||||
import type { DiscoverAppState } from '../public';
|
||||
import { createDataViewDataSource, createEsqlDataSource } from './data_sources';
|
||||
|
||||
export const DISCOVER_APP_LOCATOR = 'DISCOVER_APP_LOCATOR';
|
||||
|
||||
|
@ -113,11 +109,6 @@ export interface DiscoverAppLocatorParams extends SerializableRecord {
|
|||
|
||||
export type DiscoverAppLocator = LocatorPublic<DiscoverAppLocatorParams>;
|
||||
|
||||
export interface DiscoverAppLocatorDependencies {
|
||||
useHash: boolean;
|
||||
setStateToKbnUrl: typeof setStateToKbnUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Location state of scoped history (history instance of Kibana Platform application service)
|
||||
*/
|
||||
|
@ -126,83 +117,5 @@ export interface MainHistoryLocationState {
|
|||
isAlertResults?: boolean;
|
||||
}
|
||||
|
||||
export class DiscoverAppLocatorDefinition implements LocatorDefinition<DiscoverAppLocatorParams> {
|
||||
public readonly id = DISCOVER_APP_LOCATOR;
|
||||
|
||||
constructor(protected readonly deps: DiscoverAppLocatorDependencies) {}
|
||||
|
||||
public readonly getLocation = async (params: DiscoverAppLocatorParams) => {
|
||||
const {
|
||||
useHash = this.deps.useHash,
|
||||
filters,
|
||||
dataViewId,
|
||||
indexPatternId,
|
||||
dataViewSpec,
|
||||
query,
|
||||
refreshInterval,
|
||||
savedSearchId,
|
||||
timeRange,
|
||||
searchSessionId,
|
||||
columns,
|
||||
grid,
|
||||
savedQuery,
|
||||
sort,
|
||||
interval,
|
||||
viewMode,
|
||||
hideAggregatedPreview,
|
||||
breakdownField,
|
||||
isAlertResults,
|
||||
} = params;
|
||||
const savedSearchPath = savedSearchId ? `view/${encodeURIComponent(savedSearchId)}` : '';
|
||||
const appState: Partial<DiscoverAppState> = {};
|
||||
const queryState: GlobalQueryStateFromUrl = {};
|
||||
const { isFilterPinned } = await import('@kbn/es-query');
|
||||
|
||||
if (query) appState.query = query;
|
||||
if (filters && filters.length) appState.filters = filters?.filter((f) => !isFilterPinned(f));
|
||||
if (indexPatternId)
|
||||
appState.dataSource = createDataViewDataSource({ dataViewId: indexPatternId });
|
||||
if (dataViewId) appState.dataSource = createDataViewDataSource({ dataViewId });
|
||||
if (isOfAggregateQueryType(query)) appState.dataSource = createEsqlDataSource();
|
||||
if (columns) appState.columns = columns;
|
||||
if (grid) appState.grid = grid;
|
||||
if (savedQuery) appState.savedQuery = savedQuery;
|
||||
if (sort) appState.sort = sort;
|
||||
if (interval) appState.interval = interval;
|
||||
if (timeRange) queryState.time = timeRange;
|
||||
if (filters && filters.length) queryState.filters = filters?.filter((f) => isFilterPinned(f));
|
||||
if (refreshInterval) queryState.refreshInterval = refreshInterval;
|
||||
if (viewMode) appState.viewMode = viewMode;
|
||||
if (hideAggregatedPreview) appState.hideAggregatedPreview = hideAggregatedPreview;
|
||||
if (breakdownField) appState.breakdownField = breakdownField;
|
||||
|
||||
const state: MainHistoryLocationState = {};
|
||||
if (dataViewSpec) state.dataViewSpec = dataViewSpec;
|
||||
if (isAlertResults) state.isAlertResults = isAlertResults;
|
||||
|
||||
let path = `#/${savedSearchPath}`;
|
||||
|
||||
if (searchSessionId) {
|
||||
path = `${path}?searchSessionId=${searchSessionId}`;
|
||||
}
|
||||
|
||||
if (Object.keys(queryState).length) {
|
||||
path = this.deps.setStateToKbnUrl<GlobalQueryStateFromUrl>(
|
||||
'_g',
|
||||
queryState,
|
||||
{ useHash },
|
||||
path
|
||||
);
|
||||
}
|
||||
|
||||
if (Object.keys(appState).length) {
|
||||
path = this.deps.setStateToKbnUrl('_a', appState, { useHash }, path);
|
||||
}
|
||||
|
||||
return {
|
||||
app: 'discover',
|
||||
path,
|
||||
state,
|
||||
};
|
||||
};
|
||||
}
|
||||
export type DiscoverAppLocatorGetLocation =
|
||||
LocatorDefinition<DiscoverAppLocatorParams>['getLocation'];
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { GlobalQueryStateFromUrl } from '@kbn/data-plugin/public';
|
||||
import { isFilterPinned, isOfAggregateQueryType } from '@kbn/es-query';
|
||||
import type { setStateToKbnUrl as setStateToKbnUrlCommon } from '@kbn/kibana-utils-plugin/common';
|
||||
import type { DiscoverAppLocatorGetLocation, MainHistoryLocationState } from './app_locator';
|
||||
import type { DiscoverAppState } from '../public';
|
||||
import { createDataViewDataSource, createEsqlDataSource } from './data_sources';
|
||||
|
||||
export const appLocatorGetLocationCommon = async (
|
||||
{
|
||||
useHash: useHashOriginal,
|
||||
setStateToKbnUrl,
|
||||
}: {
|
||||
useHash: boolean;
|
||||
setStateToKbnUrl: typeof setStateToKbnUrlCommon;
|
||||
},
|
||||
...[params]: Parameters<DiscoverAppLocatorGetLocation>
|
||||
): ReturnType<DiscoverAppLocatorGetLocation> => {
|
||||
const {
|
||||
useHash = useHashOriginal,
|
||||
filters,
|
||||
dataViewId,
|
||||
indexPatternId,
|
||||
dataViewSpec,
|
||||
query,
|
||||
refreshInterval,
|
||||
savedSearchId,
|
||||
timeRange,
|
||||
searchSessionId,
|
||||
columns,
|
||||
grid,
|
||||
savedQuery,
|
||||
sort,
|
||||
interval,
|
||||
viewMode,
|
||||
hideAggregatedPreview,
|
||||
breakdownField,
|
||||
isAlertResults,
|
||||
} = params;
|
||||
const savedSearchPath = savedSearchId ? `view/${encodeURIComponent(savedSearchId)}` : '';
|
||||
const appState: Partial<DiscoverAppState> = {};
|
||||
const queryState: GlobalQueryStateFromUrl = {};
|
||||
|
||||
if (query) appState.query = query;
|
||||
if (filters && filters.length) appState.filters = filters?.filter((f) => !isFilterPinned(f));
|
||||
if (indexPatternId)
|
||||
appState.dataSource = createDataViewDataSource({ dataViewId: indexPatternId });
|
||||
if (dataViewId) appState.dataSource = createDataViewDataSource({ dataViewId });
|
||||
if (isOfAggregateQueryType(query)) appState.dataSource = createEsqlDataSource();
|
||||
if (columns) appState.columns = columns;
|
||||
if (grid) appState.grid = grid;
|
||||
if (savedQuery) appState.savedQuery = savedQuery;
|
||||
if (sort) appState.sort = sort;
|
||||
if (interval) appState.interval = interval;
|
||||
if (timeRange) queryState.time = timeRange;
|
||||
if (filters && filters.length) queryState.filters = filters?.filter((f) => isFilterPinned(f));
|
||||
if (refreshInterval) queryState.refreshInterval = refreshInterval;
|
||||
if (viewMode) appState.viewMode = viewMode;
|
||||
if (hideAggregatedPreview) appState.hideAggregatedPreview = hideAggregatedPreview;
|
||||
if (breakdownField) appState.breakdownField = breakdownField;
|
||||
|
||||
const state: MainHistoryLocationState = {};
|
||||
if (dataViewSpec) state.dataViewSpec = dataViewSpec;
|
||||
if (isAlertResults) state.isAlertResults = isAlertResults;
|
||||
|
||||
let path = `#/${savedSearchPath}`;
|
||||
|
||||
if (searchSessionId) {
|
||||
path = `${path}?searchSessionId=${searchSessionId}`;
|
||||
}
|
||||
|
||||
if (Object.keys(queryState).length) {
|
||||
path = setStateToKbnUrl<GlobalQueryStateFromUrl>('_g', queryState, { useHash }, path);
|
||||
}
|
||||
|
||||
if (Object.keys(appState).length) {
|
||||
path = setStateToKbnUrl('_a', appState, { useHash }, path);
|
||||
}
|
||||
|
||||
return {
|
||||
app: 'discover',
|
||||
path,
|
||||
state,
|
||||
};
|
||||
};
|
|
@ -7,36 +7,12 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { DISCOVER_ESQL_LOCATOR } from '@kbn/deeplinks-analytics';
|
||||
import type { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import type { SerializableRecord } from '@kbn/utility-types';
|
||||
import { getIndexForESQLQuery, getInitialESQLQuery, getESQLAdHocDataview } from '@kbn/esql-utils';
|
||||
import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
|
||||
export type DiscoverESQLLocatorParams = SerializableRecord;
|
||||
|
||||
export interface DiscoverESQLLocatorDependencies {
|
||||
discoverAppLocator: LocatorPublic<SerializableRecord>;
|
||||
dataViews: DataViewsPublicPluginStart;
|
||||
}
|
||||
|
||||
export type DiscoverESQLLocator = LocatorPublic<DiscoverESQLLocatorParams>;
|
||||
|
||||
export class DiscoverESQLLocatorDefinition implements LocatorDefinition<DiscoverESQLLocatorParams> {
|
||||
public readonly id = DISCOVER_ESQL_LOCATOR;
|
||||
|
||||
constructor(protected readonly deps: DiscoverESQLLocatorDependencies) {}
|
||||
|
||||
public readonly getLocation = async () => {
|
||||
const { discoverAppLocator, dataViews } = this.deps;
|
||||
const indexName = (await getIndexForESQLQuery({ dataViews })) ?? '*';
|
||||
const dataView = await getESQLAdHocDataview(`from ${indexName}`, dataViews);
|
||||
const esql = getInitialESQLQuery(dataView);
|
||||
|
||||
const params = {
|
||||
query: { esql },
|
||||
};
|
||||
|
||||
return await discoverAppLocator.getLocation(params);
|
||||
};
|
||||
}
|
||||
export type DiscoverESQLLocatorGetLocation =
|
||||
LocatorDefinition<DiscoverESQLLocatorParams>['getLocation'];
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import type { SerializableRecord } from '@kbn/utility-types';
|
||||
import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import { getESQLAdHocDataview, getIndexForESQLQuery, getInitialESQLQuery } from '@kbn/esql-utils';
|
||||
import type { DiscoverESQLLocatorGetLocation } from './esql_locator';
|
||||
|
||||
export const esqlLocatorGetLocation = async ({
|
||||
discoverAppLocator,
|
||||
dataViews,
|
||||
}: {
|
||||
discoverAppLocator: LocatorPublic<SerializableRecord>;
|
||||
dataViews: DataViewsPublicPluginStart;
|
||||
}): ReturnType<DiscoverESQLLocatorGetLocation> => {
|
||||
const indexName = (await getIndexForESQLQuery({ dataViews })) ?? '*';
|
||||
const dataView = await getESQLAdHocDataview(`from ${indexName}`, dataViews);
|
||||
const esql = getInitialESQLQuery(dataView);
|
||||
|
||||
const params = {
|
||||
query: { esql },
|
||||
};
|
||||
|
||||
return await discoverAppLocator.getLocation(params);
|
||||
};
|
|
@ -10,12 +10,11 @@
|
|||
export const PLUGIN_ID = 'discover';
|
||||
export const APP_ICON = 'discoverApp';
|
||||
|
||||
export { DISCOVER_APP_LOCATOR, DiscoverAppLocatorDefinition } from './app_locator';
|
||||
export { DISCOVER_APP_LOCATOR } from './app_locator';
|
||||
export type {
|
||||
DiscoverAppLocator,
|
||||
DiscoverAppLocatorParams,
|
||||
MainHistoryLocationState,
|
||||
} from './app_locator';
|
||||
|
||||
export { DiscoverESQLLocatorDefinition } from './esql_locator';
|
||||
export type { DiscoverESQLLocator, DiscoverESQLLocatorParams } from './esql_locator';
|
||||
|
|
|
@ -46,7 +46,7 @@ import type { SearchSourceDependencies } from '@kbn/data-plugin/common';
|
|||
import type { SearchResponse } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { createElement } from 'react';
|
||||
import { createContextAwarenessMocks } from '../context_awareness/__mocks__';
|
||||
import { DiscoverEBTManager } from '../services/discover_ebt_manager';
|
||||
import { DiscoverEBTManager } from '../plugin_imports/discover_ebt_manager';
|
||||
import { createUrlTrackerMock } from './url_tracker.mock';
|
||||
|
||||
export function createDiscoverServicesMock(): DiscoverServices {
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
*/
|
||||
|
||||
import { getStatesFromKbnUrl } from '@kbn/kibana-utils-plugin/public';
|
||||
import { DiscoverContextAppLocatorDefinition } from './locator';
|
||||
import type { DiscoverContextAppLocatorParams } from './locator';
|
||||
import { DISCOVER_CONTEXT_APP_LOCATOR } from './locator';
|
||||
import { contextAppLocatorGetLocation } from './locator_get_location';
|
||||
|
||||
const dataViewId: string = 'c367b774-a4c2-11ea-bb37-0242ac130002';
|
||||
|
||||
|
@ -17,7 +19,13 @@ interface SetupParams {
|
|||
}
|
||||
|
||||
const setup = async ({ useHash = false }: SetupParams = {}) => {
|
||||
const locator = new DiscoverContextAppLocatorDefinition({ useHash });
|
||||
const locator = {
|
||||
id: DISCOVER_CONTEXT_APP_LOCATOR,
|
||||
getLocation: async (params: DiscoverContextAppLocatorParams) => {
|
||||
return contextAppLocatorGetLocation({ useHash }, params);
|
||||
},
|
||||
};
|
||||
|
||||
return { locator };
|
||||
};
|
||||
|
||||
|
|
|
@ -9,9 +9,7 @@
|
|||
|
||||
import type { SerializableRecord } from '@kbn/utility-types';
|
||||
import type { Filter } from '@kbn/es-query';
|
||||
import type { GlobalQueryStateFromUrl } from '@kbn/data-plugin/public';
|
||||
import type { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public';
|
||||
import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public';
|
||||
import type { DataViewSpec } from '@kbn/data-views-plugin/public';
|
||||
|
||||
export const DISCOVER_CONTEXT_APP_LOCATOR = 'DISCOVER_CONTEXT_APP_LOCATOR';
|
||||
|
@ -26,58 +24,10 @@ export interface DiscoverContextAppLocatorParams extends SerializableRecord {
|
|||
|
||||
export type DiscoverContextAppLocator = LocatorPublic<DiscoverContextAppLocatorParams>;
|
||||
|
||||
export interface DiscoverContextAppLocatorDependencies {
|
||||
useHash: boolean;
|
||||
}
|
||||
|
||||
export interface ContextHistoryLocationState {
|
||||
referrer: string;
|
||||
dataViewSpec?: DataViewSpec;
|
||||
}
|
||||
|
||||
export class DiscoverContextAppLocatorDefinition
|
||||
implements LocatorDefinition<DiscoverContextAppLocatorParams>
|
||||
{
|
||||
public readonly id = DISCOVER_CONTEXT_APP_LOCATOR;
|
||||
|
||||
constructor(protected readonly deps: DiscoverContextAppLocatorDependencies) {}
|
||||
|
||||
public readonly getLocation = async (params: DiscoverContextAppLocatorParams) => {
|
||||
const useHash = this.deps.useHash;
|
||||
const { index, rowId, columns, filters, referrer } = params;
|
||||
|
||||
const appState: { filters?: Filter[]; columns?: string[] } = {};
|
||||
const queryState: GlobalQueryStateFromUrl = {};
|
||||
|
||||
const { isFilterPinned } = await import('@kbn/es-query');
|
||||
if (filters && filters.length) appState.filters = filters?.filter((f) => !isFilterPinned(f));
|
||||
if (columns) appState.columns = columns;
|
||||
|
||||
if (filters && filters.length) queryState.filters = filters?.filter((f) => isFilterPinned(f));
|
||||
|
||||
let dataViewId;
|
||||
const state: ContextHistoryLocationState = { referrer };
|
||||
if (typeof index === 'object') {
|
||||
state.dataViewSpec = index;
|
||||
dataViewId = index.id!;
|
||||
} else {
|
||||
dataViewId = index;
|
||||
}
|
||||
|
||||
let path = `#/context/${dataViewId}/${encodeURIComponent(rowId)}`;
|
||||
|
||||
if (Object.keys(queryState).length) {
|
||||
path = setStateToKbnUrl<GlobalQueryStateFromUrl>('_g', queryState, { useHash }, path);
|
||||
}
|
||||
|
||||
if (Object.keys(appState).length) {
|
||||
path = setStateToKbnUrl('_a', appState, { useHash }, path);
|
||||
}
|
||||
|
||||
return {
|
||||
app: 'discover',
|
||||
path,
|
||||
state,
|
||||
};
|
||||
};
|
||||
}
|
||||
export type DiscoverContextAppLocatorGetLocation =
|
||||
LocatorDefinition<DiscoverContextAppLocatorParams>['getLocation'];
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { Filter } from '@kbn/es-query';
|
||||
import type { GlobalQueryStateFromUrl } from '@kbn/data-plugin/public';
|
||||
import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public';
|
||||
import type { ContextHistoryLocationState, DiscoverContextAppLocatorGetLocation } from './locator';
|
||||
|
||||
export const contextAppLocatorGetLocation = async (
|
||||
{ useHash }: { useHash: boolean },
|
||||
...[params]: Parameters<DiscoverContextAppLocatorGetLocation>
|
||||
): ReturnType<DiscoverContextAppLocatorGetLocation> => {
|
||||
const { index, rowId, columns, filters, referrer } = params;
|
||||
|
||||
const appState: { filters?: Filter[]; columns?: string[] } = {};
|
||||
const queryState: GlobalQueryStateFromUrl = {};
|
||||
|
||||
const { isFilterPinned } = await import('@kbn/es-query');
|
||||
if (filters && filters.length) appState.filters = filters?.filter((f) => !isFilterPinned(f));
|
||||
if (columns) appState.columns = columns;
|
||||
|
||||
if (filters && filters.length) queryState.filters = filters?.filter((f) => isFilterPinned(f));
|
||||
|
||||
let dataViewId;
|
||||
const state: ContextHistoryLocationState = { referrer };
|
||||
if (typeof index === 'object') {
|
||||
state.dataViewSpec = index;
|
||||
dataViewId = index.id!;
|
||||
} else {
|
||||
dataViewId = index;
|
||||
}
|
||||
|
||||
let path = `#/context/${dataViewId}/${encodeURIComponent(rowId)}`;
|
||||
|
||||
if (Object.keys(queryState).length) {
|
||||
path = setStateToKbnUrl<GlobalQueryStateFromUrl>('_g', queryState, { useHash }, path);
|
||||
}
|
||||
|
||||
if (Object.keys(appState).length) {
|
||||
path = setStateToKbnUrl('_a', appState, { useHash }, path);
|
||||
}
|
||||
|
||||
return {
|
||||
app: 'discover',
|
||||
path,
|
||||
state,
|
||||
};
|
||||
};
|
|
@ -7,12 +7,20 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { DiscoverSingleDocLocatorDefinition } from './locator';
|
||||
import type { DiscoverSingleDocLocatorParams } from './locator';
|
||||
import { DISCOVER_SINGLE_DOC_LOCATOR } from './locator';
|
||||
import { singleDocLocatorGetLocation } from './locator_get_location';
|
||||
|
||||
const dataViewId: string = 'c367b774-a4c2-11ea-bb37-0242ac130002';
|
||||
|
||||
const setup = () => {
|
||||
const locator = new DiscoverSingleDocLocatorDefinition();
|
||||
const locator = {
|
||||
id: DISCOVER_SINGLE_DOC_LOCATOR,
|
||||
getLocation: async (params: DiscoverSingleDocLocatorParams) => {
|
||||
return singleDocLocatorGetLocation(params);
|
||||
},
|
||||
};
|
||||
|
||||
return { locator };
|
||||
};
|
||||
|
||||
|
|
|
@ -27,31 +27,5 @@ export interface DocHistoryLocationState {
|
|||
dataViewSpec?: DataViewSpec;
|
||||
}
|
||||
|
||||
export class DiscoverSingleDocLocatorDefinition
|
||||
implements LocatorDefinition<DiscoverSingleDocLocatorParams>
|
||||
{
|
||||
public readonly id = DISCOVER_SINGLE_DOC_LOCATOR;
|
||||
|
||||
constructor() {}
|
||||
|
||||
public readonly getLocation = async (params: DiscoverSingleDocLocatorParams) => {
|
||||
const { index, rowId, rowIndex, referrer } = params;
|
||||
|
||||
let dataViewId;
|
||||
const state: DocHistoryLocationState = { referrer };
|
||||
if (typeof index === 'object') {
|
||||
state.dataViewSpec = index;
|
||||
dataViewId = index.id!;
|
||||
} else {
|
||||
dataViewId = index;
|
||||
}
|
||||
|
||||
const path = `#/doc/${dataViewId}/${rowIndex}?id=${encodeURIComponent(rowId)}`;
|
||||
|
||||
return {
|
||||
app: 'discover',
|
||||
path,
|
||||
state,
|
||||
};
|
||||
};
|
||||
}
|
||||
export type DiscoverSingleDocLocatorGetLocation =
|
||||
LocatorDefinition<DiscoverSingleDocLocatorParams>['getLocation'];
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { DiscoverSingleDocLocatorGetLocation, DocHistoryLocationState } from './locator';
|
||||
|
||||
export const singleDocLocatorGetLocation = async (
|
||||
...[params]: Parameters<DiscoverSingleDocLocatorGetLocation>
|
||||
): ReturnType<DiscoverSingleDocLocatorGetLocation> => {
|
||||
const { index, rowId, rowIndex, referrer } = params;
|
||||
|
||||
let dataViewId;
|
||||
const state: DocHistoryLocationState = { referrer };
|
||||
if (typeof index === 'object') {
|
||||
state.dataViewSpec = index;
|
||||
dataViewId = index.id!;
|
||||
} else {
|
||||
dataViewId = index;
|
||||
}
|
||||
|
||||
const path = `#/doc/${dataViewId}/${rowIndex}?id=${encodeURIComponent(rowId)}`;
|
||||
|
||||
return {
|
||||
app: 'discover',
|
||||
path,
|
||||
state,
|
||||
};
|
||||
};
|
|
@ -21,7 +21,7 @@ import type { SavedObjectSaveOpts } from '@kbn/saved-objects-plugin/public';
|
|||
import { isEqual, isFunction } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { VIEW_MODE } from '../../../../common/constants';
|
||||
import { restoreStateFromSavedSearch } from '../../../services/saved_searches/restore_from_saved_search';
|
||||
import { restoreStateFromSavedSearch } from './utils/restore_from_saved_search';
|
||||
import { updateSavedSearch } from './utils/update_saved_search';
|
||||
import { addLog } from '../../../utils/add_log';
|
||||
import { handleSourceColumnState } from '../../../utils/state_helpers';
|
||||
|
|
|
@ -23,7 +23,7 @@ import type { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query';
|
|||
import { isOfAggregateQueryType, isOfQueryType } from '@kbn/es-query';
|
||||
import { isFunction } from 'lodash';
|
||||
import { loadSavedSearch as loadSavedSearchFn } from './utils/load_saved_search';
|
||||
import { restoreStateFromSavedSearch } from '../../../services/saved_searches/restore_from_saved_search';
|
||||
import { restoreStateFromSavedSearch } from './utils/restore_from_saved_search';
|
||||
import { FetchStatus } from '../../types';
|
||||
import { changeDataView } from './utils/change_data_view';
|
||||
import { buildStateSubscribe } from './utils/build_state_subscribe';
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
import type { TimefilterContract } from '@kbn/data-plugin/public';
|
||||
import type { TimeRange, RefreshInterval } from '@kbn/data-plugin/common';
|
||||
import { savedSearchMock, savedSearchMockWithTimeField } from '../../__mocks__/saved_search';
|
||||
import { savedSearchMock, savedSearchMockWithTimeField } from '../../../../__mocks__/saved_search';
|
||||
import { restoreStateFromSavedSearch } from './restore_from_saved_search';
|
||||
|
||||
describe('discover restore state from saved search', () => {
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
import type { TimefilterContract } from '@kbn/data-plugin/public';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { isRefreshIntervalValid, isTimeRangeValid } from '../../utils/validate_time';
|
||||
import { isRefreshIntervalValid, isTimeRangeValid } from '../../../../utils/validate_time';
|
||||
|
||||
export const restoreStateFromSavedSearch = ({
|
||||
savedSearch,
|
|
@ -55,7 +55,7 @@ import type { UiActionsStart } from '@kbn/ui-actions-plugin/public';
|
|||
import type { SettingsStart } from '@kbn/core-ui-settings-browser';
|
||||
import type { ContentClient } from '@kbn/content-management-plugin/public';
|
||||
import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import { memoize, noop } from 'lodash';
|
||||
import { noop } from 'lodash';
|
||||
import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public';
|
||||
import type { AiopsPluginStart } from '@kbn/aiops-plugin/public';
|
||||
import type { DataVisualizerPluginStart } from '@kbn/data-visualizer-plugin/public';
|
||||
|
@ -68,7 +68,7 @@ import type { DiscoverContextAppLocator } from './application/context/services/l
|
|||
import type { DiscoverSingleDocLocator } from './application/doc/locator';
|
||||
import type { DiscoverAppLocator } from '../common';
|
||||
import type { ProfilesManager } from './context_awareness';
|
||||
import type { DiscoverEBTManager } from './services/discover_ebt_manager';
|
||||
import type { DiscoverEBTManager } from './plugin_imports/discover_ebt_manager';
|
||||
|
||||
/**
|
||||
* Location state of internal Discover history instance
|
||||
|
@ -144,98 +144,96 @@ export interface DiscoverServices {
|
|||
embeddableEnhanced?: EmbeddableEnhancedPluginStart;
|
||||
}
|
||||
|
||||
export const buildServices = memoize(
|
||||
({
|
||||
export const buildServices = ({
|
||||
core,
|
||||
plugins,
|
||||
context,
|
||||
locator,
|
||||
contextLocator,
|
||||
singleDocLocator,
|
||||
history,
|
||||
scopedHistory,
|
||||
urlTracker,
|
||||
profilesManager,
|
||||
ebtManager,
|
||||
setHeaderActionMenu = noop,
|
||||
}: {
|
||||
core: CoreStart;
|
||||
plugins: DiscoverStartPlugins;
|
||||
context: PluginInitializerContext;
|
||||
locator: DiscoverAppLocator;
|
||||
contextLocator: DiscoverContextAppLocator;
|
||||
singleDocLocator: DiscoverSingleDocLocator;
|
||||
history: History<HistoryLocationState>;
|
||||
scopedHistory?: ScopedHistory;
|
||||
urlTracker: UrlTracker;
|
||||
profilesManager: ProfilesManager;
|
||||
ebtManager: DiscoverEBTManager;
|
||||
setHeaderActionMenu?: AppMountParameters['setHeaderActionMenu'];
|
||||
}): DiscoverServices => {
|
||||
const { usageCollection } = plugins;
|
||||
const storage = new Storage(localStorage);
|
||||
|
||||
return {
|
||||
aiops: plugins.aiops,
|
||||
application: core.application,
|
||||
addBasePath: core.http.basePath.prepend,
|
||||
analytics: core.analytics,
|
||||
capabilities: core.application.capabilities,
|
||||
chrome: core.chrome,
|
||||
core,
|
||||
plugins,
|
||||
context,
|
||||
data: plugins.data,
|
||||
dataVisualizer: plugins.dataVisualizer,
|
||||
discoverShared: plugins.discoverShared,
|
||||
docLinks: core.docLinks,
|
||||
embeddable: plugins.embeddable,
|
||||
i18n: core.i18n,
|
||||
theme: core.theme,
|
||||
userProfile: core.userProfile,
|
||||
fieldFormats: plugins.fieldFormats,
|
||||
filterManager: plugins.data.query.filterManager,
|
||||
history,
|
||||
getScopedHistory: <T>() => scopedHistory as ScopedHistory<T | undefined>,
|
||||
setHeaderActionMenu,
|
||||
dataViews: plugins.data.dataViews,
|
||||
inspector: plugins.inspector,
|
||||
metadata: {
|
||||
branch: context.env.packageInfo.branch,
|
||||
},
|
||||
navigation: plugins.navigation,
|
||||
share: plugins.share,
|
||||
urlForwarding: plugins.urlForwarding,
|
||||
urlTracker,
|
||||
timefilter: plugins.data.query.timefilter.timefilter,
|
||||
toastNotifications: core.notifications.toasts,
|
||||
notifications: core.notifications,
|
||||
uiSettings: core.uiSettings,
|
||||
settings: core.settings,
|
||||
storage,
|
||||
trackUiMetric: usageCollection?.reportUiCounter.bind(usageCollection, 'discover'),
|
||||
dataViewFieldEditor: plugins.dataViewFieldEditor,
|
||||
http: core.http,
|
||||
spaces: plugins.spaces,
|
||||
dataViewEditor: plugins.dataViewEditor,
|
||||
triggersActionsUi: plugins.triggersActionsUi,
|
||||
locator,
|
||||
contextLocator,
|
||||
singleDocLocator,
|
||||
history,
|
||||
scopedHistory,
|
||||
urlTracker,
|
||||
expressions: plugins.expressions,
|
||||
charts: plugins.charts,
|
||||
savedObjectsTagging: plugins.savedObjectsTaggingOss?.getTaggingApi(),
|
||||
savedObjectsManagement: plugins.savedObjectsManagement,
|
||||
savedSearch: plugins.savedSearch,
|
||||
unifiedSearch: plugins.unifiedSearch,
|
||||
lens: plugins.lens,
|
||||
uiActions: plugins.uiActions,
|
||||
contentClient: plugins.contentManagement.client,
|
||||
noDataPage: plugins.noDataPage,
|
||||
observabilityAIAssistant: plugins.observabilityAIAssistant,
|
||||
profilesManager,
|
||||
ebtManager,
|
||||
setHeaderActionMenu = noop,
|
||||
}: {
|
||||
core: CoreStart;
|
||||
plugins: DiscoverStartPlugins;
|
||||
context: PluginInitializerContext;
|
||||
locator: DiscoverAppLocator;
|
||||
contextLocator: DiscoverContextAppLocator;
|
||||
singleDocLocator: DiscoverSingleDocLocator;
|
||||
history: History<HistoryLocationState>;
|
||||
scopedHistory?: ScopedHistory;
|
||||
urlTracker: UrlTracker;
|
||||
profilesManager: ProfilesManager;
|
||||
ebtManager: DiscoverEBTManager;
|
||||
setHeaderActionMenu?: AppMountParameters['setHeaderActionMenu'];
|
||||
}): DiscoverServices => {
|
||||
const { usageCollection } = plugins;
|
||||
const storage = new Storage(localStorage);
|
||||
|
||||
return {
|
||||
aiops: plugins.aiops,
|
||||
application: core.application,
|
||||
addBasePath: core.http.basePath.prepend,
|
||||
analytics: core.analytics,
|
||||
capabilities: core.application.capabilities,
|
||||
chrome: core.chrome,
|
||||
core,
|
||||
data: plugins.data,
|
||||
dataVisualizer: plugins.dataVisualizer,
|
||||
discoverShared: plugins.discoverShared,
|
||||
docLinks: core.docLinks,
|
||||
embeddable: plugins.embeddable,
|
||||
i18n: core.i18n,
|
||||
theme: core.theme,
|
||||
userProfile: core.userProfile,
|
||||
fieldFormats: plugins.fieldFormats,
|
||||
filterManager: plugins.data.query.filterManager,
|
||||
history,
|
||||
getScopedHistory: <T>() => scopedHistory as ScopedHistory<T | undefined>,
|
||||
setHeaderActionMenu,
|
||||
dataViews: plugins.data.dataViews,
|
||||
inspector: plugins.inspector,
|
||||
metadata: {
|
||||
branch: context.env.packageInfo.branch,
|
||||
},
|
||||
navigation: plugins.navigation,
|
||||
share: plugins.share,
|
||||
urlForwarding: plugins.urlForwarding,
|
||||
urlTracker,
|
||||
timefilter: plugins.data.query.timefilter.timefilter,
|
||||
toastNotifications: core.notifications.toasts,
|
||||
notifications: core.notifications,
|
||||
uiSettings: core.uiSettings,
|
||||
settings: core.settings,
|
||||
storage,
|
||||
trackUiMetric: usageCollection?.reportUiCounter.bind(usageCollection, 'discover'),
|
||||
dataViewFieldEditor: plugins.dataViewFieldEditor,
|
||||
http: core.http,
|
||||
spaces: plugins.spaces,
|
||||
dataViewEditor: plugins.dataViewEditor,
|
||||
triggersActionsUi: plugins.triggersActionsUi,
|
||||
locator,
|
||||
contextLocator,
|
||||
singleDocLocator,
|
||||
expressions: plugins.expressions,
|
||||
charts: plugins.charts,
|
||||
savedObjectsTagging: plugins.savedObjectsTaggingOss?.getTaggingApi(),
|
||||
savedObjectsManagement: plugins.savedObjectsManagement,
|
||||
savedSearch: plugins.savedSearch,
|
||||
unifiedSearch: plugins.unifiedSearch,
|
||||
lens: plugins.lens,
|
||||
uiActions: plugins.uiActions,
|
||||
contentClient: plugins.contentManagement.client,
|
||||
noDataPage: plugins.noDataPage,
|
||||
observabilityAIAssistant: plugins.observabilityAIAssistant,
|
||||
profilesManager,
|
||||
ebtManager,
|
||||
fieldsMetadata: plugins.fieldsMetadata,
|
||||
logsDataAccess: plugins.logsDataAccess,
|
||||
embeddableEnhanced: plugins.embeddableEnhanced,
|
||||
};
|
||||
}
|
||||
);
|
||||
fieldsMetadata: plugins.fieldsMetadata,
|
||||
logsDataAccess: plugins.logsDataAccess,
|
||||
embeddableEnhanced: plugins.embeddableEnhanced,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -39,7 +39,7 @@ const TestComponent = (props: Partial<DiscoverContainerInternalProps>) => {
|
|||
overrideServices={props.overrideServices ?? mockOverrideService}
|
||||
customizationCallbacks={props.customizationCallbacks ?? [customizeMock]}
|
||||
scopedHistory={props.scopedHistory ?? getScopedHistory()!}
|
||||
getDiscoverServices={getDiscoverServicesMock}
|
||||
getDiscoverServices={() => Promise.resolve(getDiscoverServicesMock())}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
|
|||
import React, { useMemo } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import type { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { DiscoverMainRoute } from '../../application/main';
|
||||
import type { DiscoverServices } from '../../build_services';
|
||||
import type { CustomizationCallback, DiscoverCustomizationContext } from '../../customizations';
|
||||
|
@ -26,7 +27,7 @@ export interface DiscoverContainerInternalProps {
|
|||
* already consumes.
|
||||
*/
|
||||
overrideServices: Partial<DiscoverServices>;
|
||||
getDiscoverServices: () => DiscoverServices;
|
||||
getDiscoverServices: () => Promise<DiscoverServices>;
|
||||
scopedHistory: ScopedHistory;
|
||||
customizationCallbacks: CustomizationCallback[];
|
||||
stateStorageContainer?: IKbnUrlStateStorage;
|
||||
|
@ -60,15 +61,20 @@ export const DiscoverContainerInternal = ({
|
|||
stateStorageContainer,
|
||||
isLoading = false,
|
||||
}: DiscoverContainerInternalProps) => {
|
||||
const services = useMemo<DiscoverServices>(() => {
|
||||
const { value: discoverServices } = useAsync(getDiscoverServices, [getDiscoverServices]);
|
||||
const services = useMemo(() => {
|
||||
if (!discoverServices) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
...getDiscoverServices(),
|
||||
...discoverServices,
|
||||
...overrideServices,
|
||||
getScopedHistory: <T,>() => scopedHistory as ScopedHistory<T | undefined>,
|
||||
};
|
||||
}, [getDiscoverServices, overrideServices, scopedHistory]);
|
||||
}, [discoverServices, overrideServices, scopedHistory]);
|
||||
|
||||
if (isLoading) {
|
||||
if (isLoading || !services) {
|
||||
return (
|
||||
<EuiFlexGroup css={discoverContainerWrapperCss}>
|
||||
<LoadingIndicator type="spinner" />
|
||||
|
|
|
@ -25,7 +25,7 @@ import {
|
|||
} from '../profiles';
|
||||
import type { ProfileProviderServices } from '../profile_providers/profile_provider_services';
|
||||
import { ProfilesManager } from '../profiles_manager';
|
||||
import { DiscoverEBTManager } from '../../services/discover_ebt_manager';
|
||||
import { DiscoverEBTManager } from '../../plugin_imports/discover_ebt_manager';
|
||||
import { createLogsContextServiceMock } from '@kbn/discover-utils/src/__mocks__';
|
||||
import { discoverSharedPluginMock } from '@kbn/discover-shared-plugin/public/mocks';
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ import type {
|
|||
DocumentContext,
|
||||
} from './profiles';
|
||||
import type { ContextWithProfileId } from './profile_service';
|
||||
import type { DiscoverEBTManager } from '../services/discover_ebt_manager';
|
||||
import type { DiscoverEBTManager } from '../plugin_imports/discover_ebt_manager';
|
||||
import type { AppliedProfile } from './composable_profile';
|
||||
|
||||
interface SerializedRootProfileParams {
|
||||
|
|
|
@ -9,6 +9,5 @@
|
|||
|
||||
export * from './customization_types';
|
||||
export * from './customization_provider';
|
||||
export * from './defaults';
|
||||
export * from './types';
|
||||
export type { DiscoverCustomization, DiscoverCustomizationService } from './customization_service';
|
||||
|
|
|
@ -11,11 +11,10 @@ import type { ApplicationStart } from '@kbn/core/public';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import type { EmbeddableApiContext } from '@kbn/presentation-publishing';
|
||||
import type { Action } from '@kbn/ui-actions-plugin/public';
|
||||
|
||||
import type { DiscoverAppLocator } from '../../../common';
|
||||
import { getDiscoverLocatorParams } from '../utils/get_discover_locator_params';
|
||||
|
||||
export const ACTION_VIEW_SAVED_SEARCH = 'ACTION_VIEW_SAVED_SEARCH';
|
||||
import { compatibilityCheck } from './view_saved_search_compatibility_check';
|
||||
import { ACTION_VIEW_SAVED_SEARCH } from '../constants';
|
||||
|
||||
export class ViewSavedSearchAction implements Action<EmbeddableApiContext> {
|
||||
public id = ACTION_VIEW_SAVED_SEARCH;
|
||||
|
@ -28,7 +27,6 @@ export class ViewSavedSearchAction implements Action<EmbeddableApiContext> {
|
|||
) {}
|
||||
|
||||
async execute({ embeddable }: EmbeddableApiContext): Promise<void> {
|
||||
const { compatibilityCheck } = await import('./view_saved_search_compatibility_check');
|
||||
if (!compatibilityCheck(embeddable)) {
|
||||
return;
|
||||
}
|
||||
|
@ -53,7 +51,7 @@ export class ViewSavedSearchAction implements Action<EmbeddableApiContext> {
|
|||
(capabilities.discover.show as boolean) || (capabilities.discover.save as boolean);
|
||||
|
||||
if (!hasDiscoverPermissions) return false; // early return to delay async import until absolutely necessary
|
||||
const { compatibilityCheck } = await import('./view_saved_search_compatibility_check');
|
||||
|
||||
return compatibilityCheck(embeddable);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ import {
|
|||
} from '@kbn/discover-utils';
|
||||
import { DiscoverDocTableEmbeddable } from '../../components/doc_table/create_doc_table_embeddable';
|
||||
import { useDiscoverServices } from '../../hooks/use_discover_services';
|
||||
import { getSortForEmbeddable } from '../../utils';
|
||||
import { getSortForEmbeddable } from '../../utils/sorting';
|
||||
import { getAllowedSampleSize, getMaxAllowedSampleSize } from '../../utils/get_allowed_sample_size';
|
||||
import { SEARCH_EMBEDDABLE_CELL_ACTIONS_TRIGGER_ID } from '../constants';
|
||||
import { isEsqlMode } from '../initialize_fetch';
|
||||
|
|
|
@ -23,6 +23,8 @@ export const SEARCH_EMBEDDABLE_CELL_ACTIONS_TRIGGER: Trigger = {
|
|||
'This trigger is used to replace the cell actions for Discover session embeddable grid.',
|
||||
} as const;
|
||||
|
||||
export const ACTION_VIEW_SAVED_SEARCH = 'ACTION_VIEW_SAVED_SEARCH';
|
||||
|
||||
export const DEFAULT_HEADER_ROW_HEIGHT_LINES = 3;
|
||||
|
||||
/** This constant refers to the parts of the saved search state that can be edited from a dashboard */
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { EmbeddableSetup } from '@kbn/embeddable-plugin/public';
|
||||
import { SEARCH_EMBEDDABLE_TYPE } from '@kbn/discover-utils';
|
||||
import type { DiscoverServices } from '../build_services';
|
||||
import { deserializeState } from './utils/serialization_utils';
|
||||
|
||||
export const getOnAddSearchEmbeddable =
|
||||
(
|
||||
discoverServices: DiscoverServices
|
||||
): Parameters<EmbeddableSetup['registerAddFromLibraryType']>[0]['onAdd'] =>
|
||||
async (container, savedObject) => {
|
||||
const initialState = await deserializeState({
|
||||
serializedState: {
|
||||
rawState: { savedObjectId: savedObject.id },
|
||||
references: savedObject.references,
|
||||
},
|
||||
discoverServices,
|
||||
});
|
||||
|
||||
container.addNewPanel({
|
||||
panelType: SEARCH_EMBEDDABLE_TYPE,
|
||||
initialState,
|
||||
});
|
||||
};
|
|
@ -9,17 +9,18 @@
|
|||
|
||||
import { omit, pick } from 'lodash';
|
||||
import deepEqual from 'react-fast-compare';
|
||||
|
||||
import type { EmbeddableStateWithType } from '@kbn/embeddable-plugin/common';
|
||||
import type {
|
||||
SerializedTimeRange,
|
||||
SerializedTitles,
|
||||
SerializedPanelState,
|
||||
} from '@kbn/presentation-publishing';
|
||||
import type { SavedSearch, SavedSearchAttributes } from '@kbn/saved-search-plugin/common';
|
||||
import { toSavedSearchAttributes } from '@kbn/saved-search-plugin/common';
|
||||
import {
|
||||
toSavedSearchAttributes,
|
||||
type SavedSearch,
|
||||
type SavedSearchAttributes,
|
||||
} from '@kbn/saved-search-plugin/common';
|
||||
import type { SavedSearchUnwrapResult } from '@kbn/saved-search-plugin/public';
|
||||
|
||||
import type { DynamicActionsSerializedState } from '@kbn/embeddable-enhanced-plugin/public/plugin';
|
||||
import { extract, inject } from '../../../common/embeddable/search_inject_extract';
|
||||
import type { DiscoverServices } from '../../build_services';
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { ApplicationStart } from '@kbn/core/public';
|
||||
import { from, of } from 'rxjs';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { DEFAULT_APP_CATEGORIES } from '@kbn/core/public';
|
||||
import type { GlobalSearchResultProvider } from '@kbn/global-search-plugin/public';
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import { getInitialESQLQuery } from '@kbn/esql-utils';
|
||||
import type { DiscoverAppLocator } from '../../common';
|
||||
|
||||
/**
|
||||
* Global search provider adding an ES|QL and ESQL entry.
|
||||
* This is necessary because ES|QL is part of the Discover application.
|
||||
*
|
||||
* It navigates to Discover with a default query extracted from the default dataview
|
||||
*/
|
||||
export const getESQLSearchProvider: (
|
||||
isESQLEnabled: boolean,
|
||||
uiCapabilities: Promise<ApplicationStart['capabilities']>,
|
||||
data: Promise<DataPublicPluginStart>,
|
||||
locator?: DiscoverAppLocator
|
||||
) => GlobalSearchResultProvider = (isESQLEnabled, uiCapabilities, data, locator) => ({
|
||||
id: 'esql',
|
||||
find: ({ term = '', types, tags }) => {
|
||||
if (tags || (types && !types.includes('application')) || !locator || !isESQLEnabled) {
|
||||
return of([]);
|
||||
}
|
||||
|
||||
return from(
|
||||
Promise.all([uiCapabilities, data]).then(async ([{ navLinks }, { dataViews }]) => {
|
||||
if (!navLinks.discover) {
|
||||
return [];
|
||||
}
|
||||
const title = i18n.translate('discover.globalSearch.esqlSearchTitle', {
|
||||
defaultMessage: 'Create ES|QL queries',
|
||||
description: 'ES|QL is a product name and should not be translated',
|
||||
});
|
||||
const defaultDataView = await dataViews.getDefaultDataView({ displayErrors: false });
|
||||
|
||||
if (!defaultDataView) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const params = {
|
||||
query: {
|
||||
esql: getInitialESQLQuery(defaultDataView),
|
||||
},
|
||||
dataViewSpec: defaultDataView?.toSpec(),
|
||||
};
|
||||
|
||||
const discoverLocation = await locator?.getLocation(params);
|
||||
|
||||
term = term.toLowerCase();
|
||||
let score = 0;
|
||||
|
||||
if (term === 'es|ql' || term === 'esql') {
|
||||
score = 100;
|
||||
} else if (term && ('es|ql'.includes(term) || 'esql'.includes(term))) {
|
||||
score = 90;
|
||||
}
|
||||
|
||||
if (score === 0) return [];
|
||||
|
||||
return [
|
||||
{
|
||||
id: 'esql',
|
||||
title,
|
||||
type: 'application',
|
||||
icon: 'logoKibana',
|
||||
meta: {
|
||||
categoryId: DEFAULT_APP_CATEGORIES.kibana.id,
|
||||
categoryLabel: DEFAULT_APP_CATEGORIES.kibana.label,
|
||||
},
|
||||
score,
|
||||
url: `/app/${discoverLocation.app}${discoverLocation.path}`,
|
||||
},
|
||||
];
|
||||
})
|
||||
);
|
||||
},
|
||||
getSearchableTypes: () => ['application'],
|
||||
});
|
|
@ -39,5 +39,6 @@ export {
|
|||
type SearchEmbeddableApi,
|
||||
type NonPersistedDisplayOptions,
|
||||
} from './embeddable';
|
||||
export { loadSharingDataHelpers } from './utils';
|
||||
export { LogsExplorerTabs, type LogsExplorerTabsProps } from './components/logs_explorer_tabs';
|
||||
|
||||
export const loadSharingDataHelpers = () => import('./utils/get_sharing_data');
|
||||
|
|
|
@ -21,33 +21,36 @@ import type {
|
|||
} from '@kbn/core/public';
|
||||
import { DEFAULT_APP_CATEGORIES } from '@kbn/core/public';
|
||||
import { ENABLE_ESQL } from '@kbn/esql-utils';
|
||||
import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public';
|
||||
import { SEARCH_EMBEDDABLE_TYPE, TRUNCATE_MAX_HEIGHT } from '@kbn/discover-utils';
|
||||
import type { SavedSearchAttributes } from '@kbn/saved-search-plugin/common';
|
||||
import { SavedSearchType } from '@kbn/saved-search-plugin/common';
|
||||
import type { SavedSearchAttributes } from '@kbn/saved-search-plugin/common';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { PLUGIN_ID } from '../common';
|
||||
import { registerFeature } from './register_feature';
|
||||
import { once } from 'lodash';
|
||||
import { DISCOVER_ESQL_LOCATOR } from '@kbn/deeplinks-analytics';
|
||||
import { DISCOVER_APP_LOCATOR, PLUGIN_ID, type DiscoverAppLocator } from '../common';
|
||||
import {
|
||||
DISCOVER_CONTEXT_APP_LOCATOR,
|
||||
type DiscoverContextAppLocator,
|
||||
} from './application/context/services/locator';
|
||||
import {
|
||||
DISCOVER_SINGLE_DOC_LOCATOR,
|
||||
type DiscoverSingleDocLocator,
|
||||
} from './application/doc/locator';
|
||||
import { registerFeature } from './plugin_imports/register_feature';
|
||||
import type { UrlTracker } from './build_services';
|
||||
import { buildServices } from './build_services';
|
||||
import { ViewSavedSearchAction } from './embeddable/actions/view_saved_search_action';
|
||||
import { injectTruncateStyles } from './utils/truncate_styles';
|
||||
import { initializeKbnUrlTracking } from './utils/initialize_kbn_url_tracking';
|
||||
import type { DiscoverContextAppLocator } from './application/context/services/locator';
|
||||
import { DiscoverContextAppLocatorDefinition } from './application/context/services/locator';
|
||||
import type { DiscoverSingleDocLocator } from './application/doc/locator';
|
||||
import { DiscoverSingleDocLocatorDefinition } from './application/doc/locator';
|
||||
import type { DiscoverAppLocator } from '../common';
|
||||
import { DiscoverAppLocatorDefinition, DiscoverESQLLocatorDefinition } from '../common';
|
||||
import { defaultCustomizationContext } from './customizations/defaults';
|
||||
import {
|
||||
SEARCH_EMBEDDABLE_CELL_ACTIONS_TRIGGER,
|
||||
ACTION_VIEW_SAVED_SEARCH,
|
||||
} from './embeddable/constants';
|
||||
import type { DiscoverCustomizationContext } from './customizations';
|
||||
import { defaultCustomizationContext } from './customizations';
|
||||
import { SEARCH_EMBEDDABLE_CELL_ACTIONS_TRIGGER } from './embeddable/constants';
|
||||
import {
|
||||
DiscoverContainerInternal,
|
||||
type DiscoverContainerProps,
|
||||
} from './components/discover_container';
|
||||
import { getESQLSearchProvider } from './global_search/search_provider';
|
||||
import { HistoryService } from './history_service';
|
||||
import { getESQLSearchProvider } from './plugin_imports/search_provider';
|
||||
import type { ConfigSchema, ExperimentalFeatures } from '../server/config';
|
||||
import type {
|
||||
DiscoverSetup,
|
||||
|
@ -55,13 +58,14 @@ import type {
|
|||
DiscoverStart,
|
||||
DiscoverStartPlugins,
|
||||
} from './types';
|
||||
import { deserializeState } from './embeddable/utils/serialization_utils';
|
||||
import { DISCOVER_CELL_ACTIONS_TRIGGER } from './context_awareness/types';
|
||||
import { RootProfileService } from './context_awareness/profiles/root_profile';
|
||||
import { DataSourceProfileService } from './context_awareness/profiles/data_source_profile';
|
||||
import { DocumentProfileService } from './context_awareness/profiles/document_profile';
|
||||
import { ProfilesManager } from './context_awareness/profiles_manager';
|
||||
import { DiscoverEBTManager } from './services/discover_ebt_manager';
|
||||
import type {
|
||||
DiscoverEBTContextProps,
|
||||
DiscoverEBTManager,
|
||||
} from './plugin_imports/discover_ebt_manager';
|
||||
import type { ProfilesManager } from './context_awareness';
|
||||
import { forwardLegacyUrls } from './plugin_imports/forward_legacy_urls';
|
||||
import { registerDiscoverEBTManagerAnalytics } from './plugin_imports/discover_ebt_manager_registrations';
|
||||
|
||||
/**
|
||||
* Contains Discover, one of the oldest parts of Kibana
|
||||
|
@ -70,8 +74,10 @@ import { DiscoverEBTManager } from './services/discover_ebt_manager';
|
|||
export class DiscoverPlugin
|
||||
implements Plugin<DiscoverSetup, DiscoverStart, DiscoverSetupPlugins, DiscoverStartPlugins>
|
||||
{
|
||||
private readonly discoverEbtContext$ = new BehaviorSubject<DiscoverEBTContextProps>({
|
||||
discoverProfiles: [],
|
||||
});
|
||||
private readonly appStateUpdater = new BehaviorSubject<AppUpdater>(() => ({}));
|
||||
private readonly historyService = new HistoryService();
|
||||
private readonly inlineTopNav: Map<string | null, DiscoverCustomizationContext['inlineTopNav']> =
|
||||
new Map([[null, defaultCustomizationContext.inlineTopNav]]);
|
||||
private readonly experimentalFeatures: ExperimentalFeatures;
|
||||
|
@ -101,35 +107,41 @@ export class DiscoverPlugin
|
|||
if (plugins.share) {
|
||||
const useHash = core.uiSettings.get('state:storeInSessionStorage');
|
||||
|
||||
this.locator = plugins.share.url.locators.create(
|
||||
new DiscoverAppLocatorDefinition({ useHash, setStateToKbnUrl })
|
||||
);
|
||||
this.contextLocator = plugins.share.url.locators.create(
|
||||
new DiscoverContextAppLocatorDefinition({ useHash })
|
||||
);
|
||||
this.singleDocLocator = plugins.share.url.locators.create(
|
||||
new DiscoverSingleDocLocatorDefinition()
|
||||
);
|
||||
this.locator = plugins.share.url.locators.create({
|
||||
id: DISCOVER_APP_LOCATOR,
|
||||
getLocation: async (params) => {
|
||||
const { appLocatorGetLocation } = await getLocators();
|
||||
return appLocatorGetLocation({ useHash }, params);
|
||||
},
|
||||
});
|
||||
|
||||
this.contextLocator = plugins.share.url.locators.create({
|
||||
id: DISCOVER_CONTEXT_APP_LOCATOR,
|
||||
getLocation: async (params) => {
|
||||
const { contextAppLocatorGetLocation } = await getLocators();
|
||||
return contextAppLocatorGetLocation({ useHash }, params);
|
||||
},
|
||||
});
|
||||
|
||||
this.singleDocLocator = plugins.share.url.locators.create({
|
||||
id: DISCOVER_SINGLE_DOC_LOCATOR,
|
||||
getLocation: async (params) => {
|
||||
const { singleDocLocatorGetLocation } = await getLocators();
|
||||
return singleDocLocatorGetLocation(params);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (plugins.globalSearch) {
|
||||
const enableESQL = core.uiSettings.get(ENABLE_ESQL);
|
||||
plugins.globalSearch.registerResultProvider(
|
||||
getESQLSearchProvider(
|
||||
enableESQL,
|
||||
core.getStartServices().then(
|
||||
([
|
||||
{
|
||||
application: { capabilities },
|
||||
},
|
||||
]) => capabilities
|
||||
),
|
||||
core.getStartServices().then((deps) => {
|
||||
const { data } = deps[1];
|
||||
return data;
|
||||
}),
|
||||
this.locator
|
||||
)
|
||||
getESQLSearchProvider({
|
||||
isESQLEnabled: core.uiSettings.get(ENABLE_ESQL),
|
||||
locator: this.locator,
|
||||
getServices: async () => {
|
||||
const [coreStart, startPlugins] = await core.getStartServices();
|
||||
return [coreStart, startPlugins];
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -151,13 +163,15 @@ export class DiscoverPlugin
|
|||
this.urlTracker = { setTrackedUrl, restorePreviousUrl, setTrackingEnabled };
|
||||
this.stopUrlTracking = stopUrlTracker;
|
||||
|
||||
const ebtManager = new DiscoverEBTManager();
|
||||
ebtManager.initialize({
|
||||
core,
|
||||
shouldInitializeCustomContext: true,
|
||||
shouldInitializeCustomEvents: true,
|
||||
const getEbtManager = once(async () => {
|
||||
const { DiscoverEBTManager } = await getSharedServices();
|
||||
const ebtManager = new DiscoverEBTManager();
|
||||
ebtManager.initialize({ core, discoverEbtContext$: this.discoverEbtContext$ });
|
||||
return ebtManager;
|
||||
});
|
||||
|
||||
registerDiscoverEBTManagerAnalytics(core, this.discoverEbtContext$);
|
||||
|
||||
core.application.register({
|
||||
id: PLUGIN_ID,
|
||||
title: 'Discover',
|
||||
|
@ -173,7 +187,7 @@ export class DiscoverPlugin
|
|||
// Store the current scoped history so initializeKbnUrlTracking can access it
|
||||
this.scopedHistory = params.history;
|
||||
|
||||
this.historyService.syncHistoryLocations();
|
||||
(await getHistoryService()).syncHistoryLocations();
|
||||
appMounted();
|
||||
|
||||
// dispatch synthetic hash change event to update hash history objects
|
||||
|
@ -182,24 +196,14 @@ export class DiscoverPlugin
|
|||
window.dispatchEvent(new HashChangeEvent('hashchange'));
|
||||
});
|
||||
|
||||
const ebtManager = await getEbtManager();
|
||||
ebtManager.onDiscoverAppMounted();
|
||||
|
||||
const services = buildServices({
|
||||
const services = await this.getDiscoverServicesWithProfiles({
|
||||
core: coreStart,
|
||||
plugins: discoverStartPlugins,
|
||||
context: this.initializerContext,
|
||||
locator: this.locator!,
|
||||
contextLocator: this.contextLocator!,
|
||||
singleDocLocator: this.singleDocLocator!,
|
||||
history: this.historyService.getHistory(),
|
||||
scopedHistory: this.scopedHistory,
|
||||
urlTracker: this.urlTracker!,
|
||||
profilesManager: await this.createProfilesManager({
|
||||
core: coreStart,
|
||||
plugins: discoverStartPlugins,
|
||||
ebtManager,
|
||||
}),
|
||||
ebtManager,
|
||||
scopedHistory: this.scopedHistory,
|
||||
setHeaderActionMenu: params.setHeaderActionMenu,
|
||||
});
|
||||
|
||||
|
@ -239,32 +243,11 @@ export class DiscoverPlugin
|
|||
},
|
||||
});
|
||||
|
||||
plugins.urlForwarding.forwardApp('doc', 'discover', (path) => {
|
||||
return `#${path}`;
|
||||
});
|
||||
plugins.urlForwarding.forwardApp('context', 'discover', (path) => {
|
||||
const urlParts = path.split('/');
|
||||
// take care of urls containing legacy url, those split in the following way
|
||||
// ["", "context", indexPatternId, _type, id + params]
|
||||
if (urlParts[4]) {
|
||||
// remove _type part
|
||||
const newPath = [...urlParts.slice(0, 3), ...urlParts.slice(4)].join('/');
|
||||
return `#${newPath}`;
|
||||
}
|
||||
return `#${path}`;
|
||||
});
|
||||
plugins.urlForwarding.forwardApp('discover', 'discover', (path) => {
|
||||
const [, id, tail] = /discover\/([^\?]+)(.*)/.exec(path) || [];
|
||||
if (!id) {
|
||||
return `#${path.replace('/discover', '') || '/'}`;
|
||||
}
|
||||
return `#/view/${id}${tail || ''}`;
|
||||
});
|
||||
|
||||
if (plugins.home) {
|
||||
registerFeature(plugins.home);
|
||||
}
|
||||
|
||||
forwardLegacyUrls(plugins.urlForwarding);
|
||||
this.registerEmbeddable(core, plugins);
|
||||
|
||||
return {
|
||||
|
@ -282,9 +265,14 @@ export class DiscoverPlugin
|
|||
}
|
||||
|
||||
start(core: CoreStart, plugins: DiscoverStartPlugins): DiscoverStart {
|
||||
const viewSavedSearchAction = new ViewSavedSearchAction(core.application, this.locator!);
|
||||
|
||||
plugins.uiActions.addTriggerAction('CONTEXT_MENU_TRIGGER', viewSavedSearchAction);
|
||||
plugins.uiActions.addTriggerActionAsync(
|
||||
'CONTEXT_MENU_TRIGGER',
|
||||
ACTION_VIEW_SAVED_SEARCH,
|
||||
async () => {
|
||||
const { ViewSavedSearchAction } = await getEmbeddableServices();
|
||||
return new ViewSavedSearchAction(core.application, this.locator!);
|
||||
}
|
||||
);
|
||||
plugins.uiActions.registerTrigger(SEARCH_EMBEDDABLE_CELL_ACTIONS_TRIGGER);
|
||||
plugins.uiActions.registerTrigger(DISCOVER_CELL_ACTIONS_TRIGGER);
|
||||
injectTruncateStyles(core.uiSettings.get(TRUNCATE_MAX_HEIGHT));
|
||||
|
@ -292,22 +280,23 @@ export class DiscoverPlugin
|
|||
const isEsqlEnabled = core.uiSettings.get(ENABLE_ESQL);
|
||||
|
||||
if (plugins.share && this.locator && isEsqlEnabled) {
|
||||
plugins.share?.url.locators.create(
|
||||
new DiscoverESQLLocatorDefinition({
|
||||
discoverAppLocator: this.locator,
|
||||
dataViews: plugins.dataViews,
|
||||
})
|
||||
);
|
||||
const discoverAppLocator = this.locator;
|
||||
plugins.share?.url.locators.create({
|
||||
id: DISCOVER_ESQL_LOCATOR,
|
||||
getLocation: async () => {
|
||||
const { esqlLocatorGetLocation } = await getLocators();
|
||||
return esqlLocatorGetLocation({
|
||||
discoverAppLocator,
|
||||
dataViews: plugins.dataViews,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const getDiscoverServicesInternal = () => {
|
||||
const ebtManager = new DiscoverEBTManager(); // It is not initialized outside of Discover
|
||||
return this.getDiscoverServices(
|
||||
core,
|
||||
plugins,
|
||||
this.createEmptyProfilesManager({ ebtManager }),
|
||||
ebtManager
|
||||
);
|
||||
const getDiscoverServicesInternal = async () => {
|
||||
const ebtManager = await getEmptyEbtManager();
|
||||
const { profilesManager } = await this.createProfileServices(ebtManager);
|
||||
return this.getDiscoverServices({ core, plugins, profilesManager, ebtManager });
|
||||
};
|
||||
|
||||
return {
|
||||
|
@ -324,29 +313,17 @@ export class DiscoverPlugin
|
|||
}
|
||||
}
|
||||
|
||||
private createProfileServices() {
|
||||
private async createProfileServices(ebtManager: DiscoverEBTManager) {
|
||||
const {
|
||||
RootProfileService,
|
||||
DataSourceProfileService,
|
||||
DocumentProfileService,
|
||||
ProfilesManager,
|
||||
} = await getSharedServices();
|
||||
|
||||
const rootProfileService = new RootProfileService();
|
||||
const dataSourceProfileService = new DataSourceProfileService();
|
||||
const documentProfileService = new DocumentProfileService();
|
||||
|
||||
return { rootProfileService, dataSourceProfileService, documentProfileService };
|
||||
}
|
||||
|
||||
private async createProfilesManager({
|
||||
core,
|
||||
plugins,
|
||||
ebtManager,
|
||||
}: {
|
||||
core: CoreStart;
|
||||
plugins: DiscoverStartPlugins;
|
||||
ebtManager: DiscoverEBTManager;
|
||||
}) {
|
||||
const { registerProfileProviders } = await import('./context_awareness/profile_providers');
|
||||
const { rootProfileService, dataSourceProfileService, documentProfileService } =
|
||||
this.createProfileServices();
|
||||
|
||||
const enabledExperimentalProfileIds = this.experimentalFeatures.enabledProfiles ?? [];
|
||||
|
||||
const profilesManager = new ProfilesManager(
|
||||
rootProfileService,
|
||||
dataSourceProfileService,
|
||||
|
@ -354,32 +331,70 @@ export class DiscoverPlugin
|
|||
ebtManager
|
||||
);
|
||||
|
||||
return {
|
||||
rootProfileService,
|
||||
dataSourceProfileService,
|
||||
documentProfileService,
|
||||
profilesManager,
|
||||
};
|
||||
}
|
||||
|
||||
private async getDiscoverServicesWithProfiles({
|
||||
core,
|
||||
plugins,
|
||||
ebtManager,
|
||||
scopedHistory,
|
||||
setHeaderActionMenu,
|
||||
}: {
|
||||
core: CoreStart;
|
||||
plugins: DiscoverStartPlugins;
|
||||
ebtManager: DiscoverEBTManager;
|
||||
scopedHistory?: ScopedHistory;
|
||||
setHeaderActionMenu?: AppMountParameters['setHeaderActionMenu'];
|
||||
}) {
|
||||
const {
|
||||
rootProfileService,
|
||||
dataSourceProfileService,
|
||||
documentProfileService,
|
||||
profilesManager,
|
||||
} = await this.createProfileServices(ebtManager);
|
||||
const services = await this.getDiscoverServices({
|
||||
core,
|
||||
plugins,
|
||||
profilesManager,
|
||||
ebtManager,
|
||||
scopedHistory,
|
||||
setHeaderActionMenu,
|
||||
});
|
||||
const { registerProfileProviders } = await import('./context_awareness/profile_providers');
|
||||
|
||||
await registerProfileProviders({
|
||||
rootProfileService,
|
||||
dataSourceProfileService,
|
||||
documentProfileService,
|
||||
enabledExperimentalProfileIds,
|
||||
services: this.getDiscoverServices(core, plugins, profilesManager, ebtManager),
|
||||
enabledExperimentalProfileIds: this.experimentalFeatures.enabledProfiles ?? [],
|
||||
services,
|
||||
});
|
||||
|
||||
return profilesManager;
|
||||
return services;
|
||||
}
|
||||
|
||||
private createEmptyProfilesManager({ ebtManager }: { ebtManager: DiscoverEBTManager }) {
|
||||
return new ProfilesManager(
|
||||
new RootProfileService(),
|
||||
new DataSourceProfileService(),
|
||||
new DocumentProfileService(),
|
||||
ebtManager
|
||||
);
|
||||
}
|
||||
|
||||
private getDiscoverServices = (
|
||||
core: CoreStart,
|
||||
plugins: DiscoverStartPlugins,
|
||||
profilesManager: ProfilesManager,
|
||||
ebtManager: DiscoverEBTManager
|
||||
) => {
|
||||
private getDiscoverServices = async ({
|
||||
core,
|
||||
plugins,
|
||||
profilesManager,
|
||||
ebtManager,
|
||||
scopedHistory,
|
||||
setHeaderActionMenu,
|
||||
}: {
|
||||
core: CoreStart;
|
||||
plugins: DiscoverStartPlugins;
|
||||
profilesManager: ProfilesManager;
|
||||
ebtManager: DiscoverEBTManager;
|
||||
scopedHistory?: ScopedHistory;
|
||||
setHeaderActionMenu?: AppMountParameters['setHeaderActionMenu'];
|
||||
}) => {
|
||||
const { buildServices } = await getSharedServices();
|
||||
return buildServices({
|
||||
core,
|
||||
plugins,
|
||||
|
@ -387,16 +402,16 @@ export class DiscoverPlugin
|
|||
locator: this.locator!,
|
||||
contextLocator: this.contextLocator!,
|
||||
singleDocLocator: this.singleDocLocator!,
|
||||
history: this.historyService.getHistory(),
|
||||
history: (await getHistoryService()).getHistory(),
|
||||
scopedHistory,
|
||||
urlTracker: this.urlTracker!,
|
||||
profilesManager,
|
||||
ebtManager,
|
||||
setHeaderActionMenu,
|
||||
});
|
||||
};
|
||||
|
||||
private registerEmbeddable(core: CoreSetup<DiscoverStartPlugins>, plugins: DiscoverSetupPlugins) {
|
||||
const ebtManager = new DiscoverEBTManager(); // It is not initialized outside of Discover
|
||||
|
||||
const getStartServices = async () => {
|
||||
const [coreStart, deps] = await core.getStartServices();
|
||||
return {
|
||||
|
@ -407,29 +422,19 @@ export class DiscoverPlugin
|
|||
|
||||
const getDiscoverServicesForEmbeddable = async () => {
|
||||
const [coreStart, deps] = await core.getStartServices();
|
||||
|
||||
const profilesManager = await this.createProfilesManager({
|
||||
const ebtManager = await getEmptyEbtManager();
|
||||
return this.getDiscoverServicesWithProfiles({
|
||||
core: coreStart,
|
||||
plugins: deps,
|
||||
ebtManager,
|
||||
});
|
||||
return this.getDiscoverServices(coreStart, deps, profilesManager, ebtManager);
|
||||
};
|
||||
|
||||
plugins.embeddable.registerAddFromLibraryType<SavedSearchAttributes>({
|
||||
onAdd: async (container, savedObject) => {
|
||||
onAdd: async (...params) => {
|
||||
const services = await getDiscoverServicesForEmbeddable();
|
||||
const initialState = await deserializeState({
|
||||
serializedState: {
|
||||
rawState: { savedObjectId: savedObject.id },
|
||||
references: savedObject.references,
|
||||
},
|
||||
discoverServices: services,
|
||||
});
|
||||
container.addNewPanel({
|
||||
panelType: SEARCH_EMBEDDABLE_TYPE,
|
||||
initialState,
|
||||
});
|
||||
const { getOnAddSearchEmbeddable } = await getEmbeddableServices();
|
||||
return getOnAddSearchEmbeddable(services)(...params);
|
||||
},
|
||||
savedObjectType: SavedSearchType,
|
||||
savedObjectName: i18n.translate('discover.savedSearch.savedObjectName', {
|
||||
|
@ -442,7 +447,7 @@ export class DiscoverPlugin
|
|||
const [startServices, discoverServices, { getSearchEmbeddableFactory }] = await Promise.all([
|
||||
getStartServices(),
|
||||
getDiscoverServicesForEmbeddable(),
|
||||
import('./embeddable/get_search_embeddable_factory'),
|
||||
getEmbeddableServices(),
|
||||
]);
|
||||
|
||||
return getSearchEmbeddableFactory({
|
||||
|
@ -452,3 +457,17 @@ export class DiscoverPlugin
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
const getLocators = () => import('./plugin_imports/locators');
|
||||
const getEmbeddableServices = () => import('./plugin_imports/embeddable_services');
|
||||
const getSharedServices = () => import('./plugin_imports/shared_services');
|
||||
|
||||
const getHistoryService = once(async () => {
|
||||
const { HistoryService } = await getSharedServices();
|
||||
return new HistoryService();
|
||||
});
|
||||
|
||||
const getEmptyEbtManager = once(async () => {
|
||||
const { DiscoverEBTManager } = await getSharedServices();
|
||||
return new DiscoverEBTManager(); // It is not initialized outside of Discover
|
||||
});
|
||||
|
|
|
@ -9,12 +9,14 @@
|
|||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { DiscoverEBTManager } from './discover_ebt_manager';
|
||||
import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public';
|
||||
import { type DiscoverEBTContextProps, DiscoverEBTManager } from './discover_ebt_manager';
|
||||
import { registerDiscoverEBTManagerAnalytics } from './discover_ebt_manager_registrations';
|
||||
import { ContextualProfileLevel } from '../context_awareness/profiles_manager';
|
||||
import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public';
|
||||
|
||||
describe('DiscoverEBTManager', () => {
|
||||
let discoverEBTContextManager: DiscoverEBTManager;
|
||||
let discoverEbtContext$: BehaviorSubject<DiscoverEBTContextProps>;
|
||||
|
||||
const coreSetupMock = coreMock.createSetup();
|
||||
|
||||
|
@ -32,15 +34,19 @@ describe('DiscoverEBTManager', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
discoverEBTContextManager = new DiscoverEBTManager();
|
||||
discoverEbtContext$ = new BehaviorSubject<DiscoverEBTContextProps>({
|
||||
discoverProfiles: [],
|
||||
});
|
||||
(coreSetupMock.analytics.reportEvent as jest.Mock).mockClear();
|
||||
});
|
||||
|
||||
describe('register', () => {
|
||||
it('should register the context provider and custom events', () => {
|
||||
registerDiscoverEBTManagerAnalytics(coreSetupMock, discoverEbtContext$);
|
||||
|
||||
discoverEBTContextManager.initialize({
|
||||
core: coreSetupMock,
|
||||
shouldInitializeCustomContext: true,
|
||||
shouldInitializeCustomEvents: true,
|
||||
discoverEbtContext$,
|
||||
});
|
||||
|
||||
expect(coreSetupMock.analytics.registerContextProvider).toHaveBeenCalledWith({
|
||||
|
@ -94,8 +100,7 @@ describe('DiscoverEBTManager', () => {
|
|||
const dscProfiles2 = ['profile21', 'profile22'];
|
||||
discoverEBTContextManager.initialize({
|
||||
core: coreSetupMock,
|
||||
shouldInitializeCustomContext: true,
|
||||
shouldInitializeCustomEvents: false,
|
||||
discoverEbtContext$,
|
||||
});
|
||||
discoverEBTContextManager.onDiscoverAppMounted();
|
||||
|
||||
|
@ -111,8 +116,7 @@ describe('DiscoverEBTManager', () => {
|
|||
const dscProfiles2 = ['profile1', 'profile2'];
|
||||
discoverEBTContextManager.initialize({
|
||||
core: coreSetupMock,
|
||||
shouldInitializeCustomContext: true,
|
||||
shouldInitializeCustomEvents: false,
|
||||
discoverEbtContext$,
|
||||
});
|
||||
discoverEBTContextManager.onDiscoverAppMounted();
|
||||
|
||||
|
@ -127,8 +131,7 @@ describe('DiscoverEBTManager', () => {
|
|||
const dscProfiles = ['profile1', 'profile2'];
|
||||
discoverEBTContextManager.initialize({
|
||||
core: coreSetupMock,
|
||||
shouldInitializeCustomContext: true,
|
||||
shouldInitializeCustomEvents: false,
|
||||
discoverEbtContext$,
|
||||
});
|
||||
|
||||
discoverEBTContextManager.updateProfilesContextWith(dscProfiles);
|
||||
|
@ -139,8 +142,7 @@ describe('DiscoverEBTManager', () => {
|
|||
const dscProfiles = ['profile1', 'profile2'];
|
||||
discoverEBTContextManager.initialize({
|
||||
core: coreSetupMock,
|
||||
shouldInitializeCustomContext: true,
|
||||
shouldInitializeCustomEvents: false,
|
||||
discoverEbtContext$,
|
||||
});
|
||||
discoverEBTContextManager.onDiscoverAppMounted();
|
||||
discoverEBTContextManager.updateProfilesContextWith(dscProfiles);
|
||||
|
@ -159,8 +161,7 @@ describe('DiscoverEBTManager', () => {
|
|||
it('should track the field usage when a field is added to the table', async () => {
|
||||
discoverEBTContextManager.initialize({
|
||||
core: coreSetupMock,
|
||||
shouldInitializeCustomContext: false,
|
||||
shouldInitializeCustomEvents: true,
|
||||
discoverEbtContext$,
|
||||
});
|
||||
|
||||
await discoverEBTContextManager.trackDataTableSelection({
|
||||
|
@ -186,8 +187,7 @@ describe('DiscoverEBTManager', () => {
|
|||
it('should track the field usage when a field is removed from the table', async () => {
|
||||
discoverEBTContextManager.initialize({
|
||||
core: coreSetupMock,
|
||||
shouldInitializeCustomContext: false,
|
||||
shouldInitializeCustomEvents: true,
|
||||
discoverEbtContext$,
|
||||
});
|
||||
|
||||
await discoverEBTContextManager.trackDataTableRemoval({
|
||||
|
@ -213,8 +213,7 @@ describe('DiscoverEBTManager', () => {
|
|||
it('should track the field usage when a filter is created', async () => {
|
||||
discoverEBTContextManager.initialize({
|
||||
core: coreSetupMock,
|
||||
shouldInitializeCustomContext: false,
|
||||
shouldInitializeCustomEvents: true,
|
||||
discoverEbtContext$,
|
||||
});
|
||||
|
||||
await discoverEBTContextManager.trackFilterAddition({
|
||||
|
@ -246,8 +245,7 @@ describe('DiscoverEBTManager', () => {
|
|||
it('should track the event when a next contextual profile is resolved', async () => {
|
||||
discoverEBTContextManager.initialize({
|
||||
core: coreSetupMock,
|
||||
shouldInitializeCustomContext: false,
|
||||
shouldInitializeCustomEvents: true,
|
||||
discoverEbtContext$,
|
||||
});
|
||||
|
||||
discoverEBTContextManager.trackContextualProfileResolvedEvent({
|
||||
|
@ -296,8 +294,7 @@ describe('DiscoverEBTManager', () => {
|
|||
it('should not trigger duplicate requests', async () => {
|
||||
discoverEBTContextManager.initialize({
|
||||
core: coreSetupMock,
|
||||
shouldInitializeCustomContext: false,
|
||||
shouldInitializeCustomEvents: true,
|
||||
discoverEbtContext$,
|
||||
});
|
||||
|
||||
discoverEBTContextManager.trackContextualProfileResolvedEvent({
|
||||
|
@ -325,8 +322,7 @@ describe('DiscoverEBTManager', () => {
|
|||
it('should trigger similar requests after remount', async () => {
|
||||
discoverEBTContextManager.initialize({
|
||||
core: coreSetupMock,
|
||||
shouldInitializeCustomContext: false,
|
||||
shouldInitializeCustomEvents: true,
|
||||
discoverEbtContext$,
|
||||
});
|
||||
|
||||
discoverEBTContextManager.trackContextualProfileResolvedEvent({
|
|
@ -7,19 +7,20 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import type { BehaviorSubject } from 'rxjs';
|
||||
import { isEqual } from 'lodash';
|
||||
import type { CoreSetup } from '@kbn/core-lifecycle-browser';
|
||||
import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public';
|
||||
import { ContextualProfileLevel } from '../context_awareness/profiles_manager';
|
||||
|
||||
/**
|
||||
* Field usage events i.e. when a field is selected in the data table, removed from the data table, or a filter is added
|
||||
*/
|
||||
const FIELD_USAGE_EVENT_TYPE = 'discover_field_usage';
|
||||
const FIELD_USAGE_EVENT_NAME = 'eventName';
|
||||
const FIELD_USAGE_FIELD_NAME = 'fieldName';
|
||||
const FIELD_USAGE_FILTER_OPERATION = 'filterOperation';
|
||||
import {
|
||||
CONTEXTUAL_PROFILE_ID,
|
||||
CONTEXTUAL_PROFILE_LEVEL,
|
||||
CONTEXTUAL_PROFILE_RESOLVED_EVENT_TYPE,
|
||||
FIELD_USAGE_EVENT_NAME,
|
||||
FIELD_USAGE_EVENT_TYPE,
|
||||
FIELD_USAGE_FIELD_NAME,
|
||||
FIELD_USAGE_FILTER_OPERATION,
|
||||
} from './discover_ebt_manager_registrations';
|
||||
|
||||
type FilterOperation = '+' | '-' | '_exists_';
|
||||
|
||||
|
@ -34,14 +35,6 @@ interface FieldUsageEventData {
|
|||
[FIELD_USAGE_FILTER_OPERATION]?: FilterOperation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contextual profile resolved event i.e. when a different contextual profile is resolved at root, data source, or document level
|
||||
* Duplicated events for the same profile level will not be sent.
|
||||
*/
|
||||
const CONTEXTUAL_PROFILE_RESOLVED_EVENT_TYPE = 'discover_profile_resolved';
|
||||
const CONTEXTUAL_PROFILE_LEVEL = 'contextLevel';
|
||||
const CONTEXTUAL_PROFILE_ID = 'profileId';
|
||||
|
||||
interface ContextualProfileResolvedEventData {
|
||||
[CONTEXTUAL_PROFILE_LEVEL]: ContextualProfileLevel;
|
||||
[CONTEXTUAL_PROFILE_ID]: string;
|
||||
|
@ -73,85 +66,13 @@ export class DiscoverEBTManager {
|
|||
// https://docs.elastic.dev/telemetry/collection/event-based-telemetry
|
||||
public initialize({
|
||||
core,
|
||||
shouldInitializeCustomContext,
|
||||
shouldInitializeCustomEvents,
|
||||
discoverEbtContext$,
|
||||
}: {
|
||||
core: CoreSetup;
|
||||
shouldInitializeCustomContext: boolean;
|
||||
shouldInitializeCustomEvents: boolean;
|
||||
discoverEbtContext$: BehaviorSubject<DiscoverEBTContextProps>;
|
||||
}) {
|
||||
if (shouldInitializeCustomContext) {
|
||||
// Register Discover specific context to be used in EBT
|
||||
const context$ = new BehaviorSubject<DiscoverEBTContextProps>({
|
||||
discoverProfiles: [],
|
||||
});
|
||||
core.analytics.registerContextProvider({
|
||||
name: 'discover_context',
|
||||
context$,
|
||||
schema: {
|
||||
discoverProfiles: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description: 'List of active Discover context awareness profiles',
|
||||
},
|
||||
},
|
||||
},
|
||||
// If we decide to extend EBT context with more properties, we can do it here
|
||||
},
|
||||
});
|
||||
this.customContext$ = context$;
|
||||
}
|
||||
|
||||
if (shouldInitializeCustomEvents) {
|
||||
// Register Discover events to be used with EBT
|
||||
core.analytics.registerEventType({
|
||||
eventType: FIELD_USAGE_EVENT_TYPE,
|
||||
schema: {
|
||||
[FIELD_USAGE_EVENT_NAME]: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description:
|
||||
'The name of the event that is tracked in the metrics i.e. dataTableSelection, dataTableRemoval',
|
||||
},
|
||||
},
|
||||
[FIELD_USAGE_FIELD_NAME]: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description: "Field name if it's a part of ECS schema",
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
[FIELD_USAGE_FILTER_OPERATION]: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description: "Operation type when a filter is added i.e. '+', '-', '_exists_'",
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
core.analytics.registerEventType({
|
||||
eventType: CONTEXTUAL_PROFILE_RESOLVED_EVENT_TYPE,
|
||||
schema: {
|
||||
[CONTEXTUAL_PROFILE_LEVEL]: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description:
|
||||
'The context level at which it was resolved i.e. rootLevel, dataSourceLevel, documentLevel',
|
||||
},
|
||||
},
|
||||
[CONTEXTUAL_PROFILE_ID]: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description: 'The resolved name of the active profile',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
this.reportEvent = core.analytics.reportEvent;
|
||||
}
|
||||
this.customContext$ = discoverEbtContext$;
|
||||
this.reportEvent = core.analytics.reportEvent;
|
||||
}
|
||||
|
||||
public onDiscoverAppMounted() {
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { CoreSetup } from '@kbn/core/public';
|
||||
import type { BehaviorSubject } from 'rxjs';
|
||||
import type { DiscoverStartPlugins } from '../types';
|
||||
import type { DiscoverEBTContextProps } from './discover_ebt_manager';
|
||||
|
||||
/**
|
||||
* Field usage events i.e. when a field is selected in the data table, removed from the data table, or a filter is added
|
||||
*/
|
||||
export const FIELD_USAGE_EVENT_TYPE = 'discover_field_usage';
|
||||
export const FIELD_USAGE_EVENT_NAME = 'eventName';
|
||||
export const FIELD_USAGE_FIELD_NAME = 'fieldName';
|
||||
export const FIELD_USAGE_FILTER_OPERATION = 'filterOperation';
|
||||
|
||||
/**
|
||||
* Contextual profile resolved event i.e. when a different contextual profile is resolved at root, data source, or document level
|
||||
* Duplicated events for the same profile level will not be sent.
|
||||
*/
|
||||
export const CONTEXTUAL_PROFILE_RESOLVED_EVENT_TYPE = 'discover_profile_resolved';
|
||||
export const CONTEXTUAL_PROFILE_LEVEL = 'contextLevel';
|
||||
export const CONTEXTUAL_PROFILE_ID = 'profileId';
|
||||
|
||||
/**
|
||||
* This function is statically imported since analytics registrations must happen at setup,
|
||||
* while the EBT manager is loaded dynamically when needed to avoid page load bundle bloat
|
||||
*/
|
||||
export const registerDiscoverEBTManagerAnalytics = (
|
||||
core: CoreSetup<DiscoverStartPlugins>,
|
||||
discoverEbtContext$: BehaviorSubject<DiscoverEBTContextProps>
|
||||
) => {
|
||||
// Register Discover specific context to be used in EBT
|
||||
core.analytics.registerContextProvider({
|
||||
name: 'discover_context',
|
||||
context$: discoverEbtContext$,
|
||||
schema: {
|
||||
discoverProfiles: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description: 'List of active Discover context awareness profiles',
|
||||
},
|
||||
},
|
||||
},
|
||||
// If we decide to extend EBT context with more properties, we can do it here
|
||||
},
|
||||
});
|
||||
|
||||
// Register Discover events to be used with EBT
|
||||
core.analytics.registerEventType({
|
||||
eventType: FIELD_USAGE_EVENT_TYPE,
|
||||
schema: {
|
||||
[FIELD_USAGE_EVENT_NAME]: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description:
|
||||
'The name of the event that is tracked in the metrics i.e. dataTableSelection, dataTableRemoval',
|
||||
},
|
||||
},
|
||||
[FIELD_USAGE_FIELD_NAME]: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description: "Field name if it's a part of ECS schema",
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
[FIELD_USAGE_FILTER_OPERATION]: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description: "Operation type when a filter is added i.e. '+', '-', '_exists_'",
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
core.analytics.registerEventType({
|
||||
eventType: CONTEXTUAL_PROFILE_RESOLVED_EVENT_TYPE,
|
||||
schema: {
|
||||
[CONTEXTUAL_PROFILE_LEVEL]: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description:
|
||||
'The context level at which it was resolved i.e. rootLevel, dataSourceLevel, documentLevel',
|
||||
},
|
||||
},
|
||||
[CONTEXTUAL_PROFILE_ID]: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description: 'The resolved name of the active profile',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
|
@ -7,11 +7,6 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
/*
|
||||
* Allows the getSharingData function to be lazy loadable
|
||||
*/
|
||||
export async function loadSharingDataHelpers() {
|
||||
return await import('./get_sharing_data');
|
||||
}
|
||||
|
||||
export { getSortForEmbeddable } from './sorting';
|
||||
export { ViewSavedSearchAction } from '../embeddable/actions/view_saved_search_action';
|
||||
export { getOnAddSearchEmbeddable } from '../embeddable/get_on_add_search_embeddable';
|
||||
export { getSearchEmbeddableFactory } from '../embeddable/get_search_embeddable_factory';
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { UrlForwardingSetup } from '@kbn/url-forwarding-plugin/public';
|
||||
|
||||
export const forwardLegacyUrls = (urlForwarding: UrlForwardingSetup) => {
|
||||
urlForwarding.forwardApp('doc', 'discover', (path) => {
|
||||
return `#${path}`;
|
||||
});
|
||||
|
||||
urlForwarding.forwardApp('context', 'discover', (path) => {
|
||||
const urlParts = path.split('/');
|
||||
// take care of urls containing legacy url, those split in the following way
|
||||
// ["", "context", indexPatternId, _type, id + params]
|
||||
if (urlParts[4]) {
|
||||
// remove _type part
|
||||
const newPath = [...urlParts.slice(0, 3), ...urlParts.slice(4)].join('/');
|
||||
return `#${newPath}`;
|
||||
}
|
||||
return `#${path}`;
|
||||
});
|
||||
|
||||
urlForwarding.forwardApp('discover', 'discover', (path) => {
|
||||
const [, id, tail] = /discover\/([^\?]+)(.*)/.exec(path) || [];
|
||||
if (!id) {
|
||||
return `#${path.replace('/discover', '') || '/'}`;
|
||||
}
|
||||
return `#/view/${id}${tail || ''}`;
|
||||
});
|
||||
};
|
|
@ -7,9 +7,8 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { History } from 'history';
|
||||
import { createHashHistory } from 'history';
|
||||
import type { HistoryLocationState } from './build_services';
|
||||
import { createHashHistory, type History } from 'history';
|
||||
import type { HistoryLocationState } from '../build_services';
|
||||
|
||||
export class HistoryService {
|
||||
private history?: History<HistoryLocationState>;
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public';
|
||||
import type { DiscoverAppLocatorParams } from '../../common';
|
||||
import { appLocatorGetLocationCommon } from '../../common/app_locator_get_location';
|
||||
|
||||
export const appLocatorGetLocation = (
|
||||
{
|
||||
useHash,
|
||||
}: {
|
||||
useHash: boolean;
|
||||
},
|
||||
params: DiscoverAppLocatorParams
|
||||
) => appLocatorGetLocationCommon({ useHash, setStateToKbnUrl }, params);
|
||||
|
||||
export { contextAppLocatorGetLocation } from '../application/context/services/locator_get_location';
|
||||
export { singleDocLocatorGetLocation } from '../application/doc/locator_get_location';
|
||||
export { esqlLocatorGetLocation } from '../../common/esql_locator_get_location';
|
|
@ -8,19 +8,21 @@
|
|||
*/
|
||||
|
||||
import { NEVER, lastValueFrom } from 'rxjs';
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { ApplicationStart } from '@kbn/core/public';
|
||||
import type { CoreStart } from '@kbn/core/public';
|
||||
import { getESQLSearchProvider } from './search_provider';
|
||||
import { createDiscoverDataViewsMock } from '../__mocks__/data_views';
|
||||
import type { DiscoverAppLocator } from '../../common';
|
||||
import type { DiscoverStartPlugins } from '../types';
|
||||
import type { DataViewsServicePublic } from '@kbn/data-views-plugin/public';
|
||||
|
||||
describe('ES|QL search provider', () => {
|
||||
const uiCapabilitiesMock = new Promise<ApplicationStart['capabilities']>((resolve) => {
|
||||
resolve({ navLinks: { discover: true } } as unknown as ApplicationStart['capabilities']);
|
||||
});
|
||||
const dataMock = new Promise<DataPublicPluginStart>((resolve) => {
|
||||
resolve({ dataViews: createDiscoverDataViewsMock() } as unknown as DataPublicPluginStart);
|
||||
});
|
||||
const getServices = (): Promise<[CoreStart, DiscoverStartPlugins]> =>
|
||||
Promise.resolve([
|
||||
{
|
||||
application: { capabilities: { navLinks: { discover: true } } },
|
||||
} as unknown as CoreStart,
|
||||
{ dataViews: createDiscoverDataViewsMock() } as unknown as DiscoverStartPlugins,
|
||||
]);
|
||||
const locator = {
|
||||
useUrl: jest.fn(() => ''),
|
||||
navigate: jest.fn(),
|
||||
|
@ -33,7 +35,11 @@ describe('ES|QL search provider', () => {
|
|||
getRedirectUrl: jest.fn(() => ''),
|
||||
} as unknown as DiscoverAppLocator;
|
||||
test('returns score 100 if term is esql', async () => {
|
||||
const esqlSearchProvider = getESQLSearchProvider(true, uiCapabilitiesMock, dataMock, locator);
|
||||
const esqlSearchProvider = getESQLSearchProvider({
|
||||
isESQLEnabled: true,
|
||||
locator,
|
||||
getServices,
|
||||
});
|
||||
const observable = esqlSearchProvider.find(
|
||||
{ term: 'esql' },
|
||||
{ aborted$: NEVER, maxResults: 100, preference: '' }
|
||||
|
@ -53,7 +59,11 @@ describe('ES|QL search provider', () => {
|
|||
});
|
||||
|
||||
test('returns score 90 if user tries to write es|ql', async () => {
|
||||
const esqlSearchProvider = getESQLSearchProvider(true, uiCapabilitiesMock, dataMock, locator);
|
||||
const esqlSearchProvider = getESQLSearchProvider({
|
||||
isESQLEnabled: true,
|
||||
locator,
|
||||
getServices,
|
||||
});
|
||||
const observable = esqlSearchProvider.find(
|
||||
{ term: 'es|' },
|
||||
{ aborted$: NEVER, maxResults: 100, preference: '' }
|
||||
|
@ -73,7 +83,11 @@ describe('ES|QL search provider', () => {
|
|||
});
|
||||
|
||||
test('returns empty results if user tries to write something irrelevant', async () => {
|
||||
const esqlSearchProvider = getESQLSearchProvider(true, uiCapabilitiesMock, dataMock, locator);
|
||||
const esqlSearchProvider = getESQLSearchProvider({
|
||||
isESQLEnabled: true,
|
||||
locator,
|
||||
getServices,
|
||||
});
|
||||
const observable = esqlSearchProvider.find(
|
||||
{ term: 'woof' },
|
||||
{ aborted$: NEVER, maxResults: 100, preference: '' }
|
||||
|
@ -83,7 +97,11 @@ describe('ES|QL search provider', () => {
|
|||
});
|
||||
|
||||
test('returns empty results if ESQL is disabled', async () => {
|
||||
const esqlSearchProvider = getESQLSearchProvider(false, uiCapabilitiesMock, dataMock, locator);
|
||||
const esqlSearchProvider = getESQLSearchProvider({
|
||||
isESQLEnabled: false,
|
||||
locator,
|
||||
getServices,
|
||||
});
|
||||
const observable = esqlSearchProvider.find(
|
||||
{ term: 'esql' },
|
||||
{ aborted$: NEVER, maxResults: 100, preference: '' }
|
||||
|
@ -94,17 +112,18 @@ describe('ES|QL search provider', () => {
|
|||
|
||||
test('returns empty results if no default dataview', async () => {
|
||||
const dataViewMock = createDiscoverDataViewsMock();
|
||||
const updatedDataMock = new Promise<DataPublicPluginStart>((resolve) => {
|
||||
resolve({
|
||||
dataViews: { ...dataViewMock, getDefaultDataView: jest.fn(() => undefined) },
|
||||
} as unknown as DataPublicPluginStart);
|
||||
const esqlSearchProvider = getESQLSearchProvider({
|
||||
isESQLEnabled: true,
|
||||
locator,
|
||||
getServices: async () => {
|
||||
const [core, start] = await getServices();
|
||||
start.dataViews = {
|
||||
...dataViewMock,
|
||||
getDefaultDataView: jest.fn(() => undefined),
|
||||
} as unknown as DataViewsServicePublic;
|
||||
return [core, start];
|
||||
},
|
||||
});
|
||||
const esqlSearchProvider = getESQLSearchProvider(
|
||||
true,
|
||||
uiCapabilitiesMock,
|
||||
updatedDataMock,
|
||||
locator
|
||||
);
|
||||
const observable = esqlSearchProvider.find(
|
||||
{ term: 'woof' },
|
||||
{ aborted$: NEVER, maxResults: 100, preference: '' }
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { CoreStart } from '@kbn/core/public';
|
||||
import { defer } from 'rxjs';
|
||||
import type { GlobalSearchResultProvider } from '@kbn/global-search-plugin/public';
|
||||
import type { DiscoverAppLocator } from '../../common';
|
||||
import type { DiscoverStartPlugins } from '../types';
|
||||
|
||||
/**
|
||||
* Global search provider adding an ES|QL and ESQL entry.
|
||||
* This is necessary because ES|QL is part of the Discover application.
|
||||
*
|
||||
* It navigates to Discover with a default query extracted from the default dataview
|
||||
*/
|
||||
export const getESQLSearchProvider = (options: {
|
||||
isESQLEnabled: boolean;
|
||||
locator?: DiscoverAppLocator;
|
||||
getServices: () => Promise<[CoreStart, DiscoverStartPlugins]>;
|
||||
}): GlobalSearchResultProvider => ({
|
||||
id: 'esql',
|
||||
find: (...findParams) => {
|
||||
return defer(async () => {
|
||||
const { searchProviderFind } = await import('./search_provider_find');
|
||||
return searchProviderFind(options, ...findParams);
|
||||
});
|
||||
},
|
||||
getSearchableTypes: () => ['application'],
|
||||
});
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type {
|
||||
GlobalSearchProviderResult,
|
||||
GlobalSearchResultProvider,
|
||||
} from '@kbn/global-search-plugin/public';
|
||||
import { DEFAULT_APP_CATEGORIES, type CoreStart } from '@kbn/core/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { getInitialESQLQuery } from '@kbn/esql-utils';
|
||||
import type { DiscoverAppLocator } from '../../common';
|
||||
import type { DiscoverStartPlugins } from '../types';
|
||||
|
||||
export const searchProviderFind: (
|
||||
options: {
|
||||
isESQLEnabled: boolean;
|
||||
locator?: DiscoverAppLocator;
|
||||
getServices: () => Promise<[CoreStart, DiscoverStartPlugins]>;
|
||||
},
|
||||
...findParams: Parameters<GlobalSearchResultProvider['find']>
|
||||
) => Promise<GlobalSearchProviderResult[]> = async (
|
||||
{ isESQLEnabled, locator, getServices },
|
||||
{ term = '', types, tags }
|
||||
) => {
|
||||
if (tags || (types && !types.includes('application')) || !locator || !isESQLEnabled) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const [core, { dataViews }] = await getServices();
|
||||
|
||||
if (!core.application.capabilities.navLinks.discover) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const title = i18n.translate('discover.globalSearch.esqlSearchTitle', {
|
||||
defaultMessage: 'Create ES|QL queries',
|
||||
description: 'ES|QL is a product name and should not be translated',
|
||||
});
|
||||
const defaultDataView = await dataViews.getDefaultDataView({ displayErrors: false });
|
||||
|
||||
if (!defaultDataView) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const params = {
|
||||
query: {
|
||||
esql: getInitialESQLQuery(defaultDataView),
|
||||
},
|
||||
dataViewSpec: defaultDataView?.toSpec(),
|
||||
};
|
||||
|
||||
const discoverLocation = await locator?.getLocation(params);
|
||||
|
||||
term = term.toLowerCase();
|
||||
let score = 0;
|
||||
|
||||
if (term === 'es|ql' || term === 'esql') {
|
||||
score = 100;
|
||||
} else if (term && ('es|ql'.includes(term) || 'esql'.includes(term))) {
|
||||
score = 90;
|
||||
}
|
||||
|
||||
if (score === 0) return [];
|
||||
|
||||
return [
|
||||
{
|
||||
id: 'esql',
|
||||
title,
|
||||
type: 'application',
|
||||
icon: 'logoKibana',
|
||||
meta: {
|
||||
categoryId: DEFAULT_APP_CATEGORIES.kibana.id,
|
||||
categoryLabel: DEFAULT_APP_CATEGORIES.kibana.label,
|
||||
},
|
||||
score,
|
||||
url: `/app/${discoverLocation.app}${discoverLocation.path}`,
|
||||
},
|
||||
];
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
export { HistoryService } from './history_service';
|
||||
export { DiscoverEBTManager } from './discover_ebt_manager';
|
||||
export { RootProfileService } from '../context_awareness/profiles/root_profile';
|
||||
export { DataSourceProfileService } from '../context_awareness/profiles/data_source_profile';
|
||||
export { DocumentProfileService } from '../context_awareness/profiles/document_profile';
|
||||
export { ProfilesManager } from '../context_awareness/profiles_manager';
|
||||
export { buildServices } from '../build_services';
|
|
@ -46,7 +46,7 @@ import type { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/publ
|
|||
import type { EmbeddableEnhancedPluginStart } from '@kbn/embeddable-enhanced-plugin/public';
|
||||
import type { DiscoverAppLocator } from '../common';
|
||||
import type { DiscoverCustomizationContext } from './customizations';
|
||||
import { type DiscoverContainerProps } from './components/discover_container';
|
||||
import type { DiscoverContainerProps } from './components/discover_container';
|
||||
|
||||
/**
|
||||
* @public
|
||||
|
@ -122,6 +122,11 @@ export interface DiscoverStart {
|
|||
* ```
|
||||
*/
|
||||
readonly locator: undefined | DiscoverAppLocator;
|
||||
/**
|
||||
* @deprecated
|
||||
* Embedding Discover in other applications is discouraged and will be removed in the future.
|
||||
* Use the Discover context awareness framework instead to register a custom Discover profile.
|
||||
*/
|
||||
readonly DiscoverContainer: ComponentType<DiscoverContainerProps>;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
|
||||
import type { AppUpdater, CoreSetup, ScopedHistory } from '@kbn/core/public';
|
||||
import type { BehaviorSubject } from 'rxjs';
|
||||
import { filter, map } from 'rxjs';
|
||||
import { filter, switchMap } from 'rxjs';
|
||||
import { createKbnUrlTracker } from '@kbn/kibana-utils-plugin/public';
|
||||
import { replaceUrlHashQuery } from '@kbn/kibana-utils-plugin/common';
|
||||
import { isFilterPinned } from '@kbn/es-query';
|
||||
import { SEARCH_SESSION_ID_QUERY_PARAM } from '../constants';
|
||||
import type { DiscoverSetupPlugins } from '../types';
|
||||
|
||||
|
@ -69,10 +68,13 @@ export function initializeKbnUrlTracking({
|
|||
filter(
|
||||
({ changes }) => !!(changes.globalFilters || changes.time || changes.refreshInterval)
|
||||
),
|
||||
map(({ state }) => ({
|
||||
...state,
|
||||
filters: state.filters?.filter(isFilterPinned),
|
||||
}))
|
||||
switchMap(async ({ state }) => {
|
||||
const { isFilterPinned } = await import('@kbn/es-query');
|
||||
return {
|
||||
...state,
|
||||
filters: state.filters?.filter(isFilterPinned),
|
||||
};
|
||||
})
|
||||
),
|
||||
},
|
||||
],
|
||||
|
|
|
@ -15,13 +15,14 @@ import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/common';
|
|||
import type { SharePluginSetup } from '@kbn/share-plugin/server';
|
||||
import type { PluginInitializerContext } from '@kbn/core/server';
|
||||
import type { DiscoverServerPluginStart, DiscoverServerPluginStartDeps } from '.';
|
||||
import { DiscoverAppLocatorDefinition } from '../common';
|
||||
import { DISCOVER_APP_LOCATOR } from '../common';
|
||||
import { capabilitiesProvider } from './capabilities_provider';
|
||||
import { createSearchEmbeddableFactory } from './embeddable';
|
||||
import { initializeLocatorServices } from './locator';
|
||||
import { registerSampleData } from './sample_data';
|
||||
import { getUiSettings } from './ui_settings';
|
||||
import type { ConfigSchema } from './config';
|
||||
import { appLocatorGetLocationCommon } from '../common/app_locator_get_location';
|
||||
|
||||
export class DiscoverServerPlugin
|
||||
implements Plugin<object, DiscoverServerPluginStart, object, DiscoverServerPluginStartDeps>
|
||||
|
@ -49,9 +50,12 @@ export class DiscoverServerPlugin
|
|||
}
|
||||
|
||||
if (plugins.share) {
|
||||
plugins.share.url.locators.create(
|
||||
new DiscoverAppLocatorDefinition({ useHash: false, setStateToKbnUrl })
|
||||
);
|
||||
plugins.share.url.locators.create({
|
||||
id: DISCOVER_APP_LOCATOR,
|
||||
getLocation: (params) => {
|
||||
return appLocatorGetLocationCommon({ useHash: false, setStateToKbnUrl }, params);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
plugins.embeddable.registerEmbeddableFactory(createSearchEmbeddableFactory());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue