mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
parent
6e6c9614f5
commit
e603d92552
156 changed files with 1878 additions and 2315 deletions
|
@ -20,7 +20,7 @@ const STORYBOOKS = [
|
|||
'custom_integrations',
|
||||
'dashboard_enhanced',
|
||||
'dashboard',
|
||||
'data_enhanced',
|
||||
'data',
|
||||
'embeddable',
|
||||
'expression_error',
|
||||
'expression_image',
|
||||
|
|
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -79,7 +79,6 @@
|
|||
/src/plugins/inspector/ @elastic/kibana-app-services
|
||||
/src/plugins/unified_search/ @elastic/kibana-app-services
|
||||
/x-pack/examples/ui_actions_enhanced_examples/ @elastic/kibana-app-services
|
||||
/x-pack/plugins/data_enhanced/ @elastic/kibana-app-services
|
||||
/x-pack/plugins/embeddable_enhanced/ @elastic/kibana-app-services
|
||||
/x-pack/plugins/ui_actions_enhanced/ @elastic/kibana-app-services
|
||||
/x-pack/plugins/runtime_fields @elastic/kibana-app-services
|
||||
|
|
|
@ -259,7 +259,7 @@ export const myEnhancedSearchStrategyProvider = (
|
|||
await ese.cancel(id, options, deps);
|
||||
},
|
||||
extend: async (id, keepAlive, options, deps) => {
|
||||
// async search results are not stored indefinitely. By default, they expire after 7 days (or as defined by xpack.data_enhanced.search.sessions.defaultExpiration setting in kibana.yml).
|
||||
// async search results are not stored indefinitely. By default, they expire after 7 days (or as defined by data.search.sessions.defaultExpiration setting in kibana.yml).
|
||||
// call the extend method of the async strategy you are using or implement your own extend function.
|
||||
await ese.extend(id, options, deps);
|
||||
},
|
||||
|
|
|
@ -412,10 +412,6 @@ The plugin exposes the static DefaultEditorController class to consume.
|
|||
|Adds drilldown capabilities to dashboard. Owned by the Kibana App team.
|
||||
|
||||
|
||||
|{kib-repo}blob/{branch}/x-pack/plugins/data_enhanced/README.md[dataEnhanced]
|
||||
|The data_enhanced plugin is the x-pack counterpart to the src/plguins/data plugin.
|
||||
|
||||
|
||||
|{kib-repo}blob/{branch}/x-pack/plugins/data_visualizer/README.md[dataVisualizer]
|
||||
|The data_visualizer plugin enables you to explore the fields in your data.
|
||||
|
||||
|
|
|
@ -104,8 +104,7 @@ pageLoadAssetSize:
|
|||
fieldFormats: 65209
|
||||
kibanaReact: 74422
|
||||
share: 71239
|
||||
uiActions: 35121
|
||||
dataEnhanced: 24980
|
||||
uiActions: 35121
|
||||
embeddable: 87309
|
||||
embeddableEnhanced: 22107
|
||||
uiActionsEnhanced: 38494
|
||||
|
|
|
@ -40,6 +40,13 @@ kibana_vars=(
|
|||
csp.report_to
|
||||
data.autocomplete.valueSuggestions.terminateAfter
|
||||
data.autocomplete.valueSuggestions.timeout
|
||||
data.search.sessions.defaultExpiration
|
||||
data.search.sessions.enabled
|
||||
data.search.sessions.maxUpdateRetries
|
||||
data.search.sessions.notTouchedInProgressTimeout
|
||||
data.search.sessions.notTouchedTimeout
|
||||
data.search.sessions.pageSize
|
||||
data.search.sessions.trackingInterval
|
||||
unifiedSearch.autocomplete.valueSuggestions.terminateAfter
|
||||
unifiedSearch.autocomplete.valueSuggestions.timeout
|
||||
unifiedSearch.autocomplete.querySuggestions.enabled
|
||||
|
|
|
@ -17,7 +17,7 @@ export const storybookAliases = {
|
|||
custom_integrations: 'src/plugins/custom_integrations/storybook',
|
||||
dashboard_enhanced: 'x-pack/plugins/dashboard_enhanced/.storybook',
|
||||
dashboard: 'src/plugins/dashboard/.storybook',
|
||||
data_enhanced: 'x-pack/plugins/data_enhanced/.storybook',
|
||||
data: 'src/plugins/data/.storybook',
|
||||
discover: 'src/plugins/discover/.storybook',
|
||||
embeddable: 'src/plugins/embeddable/.storybook',
|
||||
expression_error: 'src/plugins/expression_error/.storybook',
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
module.exports = require('@kbn/storybook').defaultConfig;
|
|
@ -8,21 +8,6 @@
|
|||
|
||||
import { schema, TypeOf } from '@kbn/config-schema';
|
||||
|
||||
export const configSchema = schema.object({
|
||||
search: schema.object({
|
||||
aggs: schema.object({
|
||||
shardDelay: schema.object({
|
||||
// Whether or not to register the shard_delay (which is only available in snapshot versions
|
||||
// of Elasticsearch) agg type/expression function to make it available in the UI for either
|
||||
// functional or manual testing
|
||||
enabled: schema.boolean({ defaultValue: false }),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
export type ConfigSchema = TypeOf<typeof configSchema>;
|
||||
|
||||
export const searchSessionsConfigSchema = schema.object({
|
||||
/**
|
||||
* Turns the feature on \ off (incl. removing indicator and management screens)
|
||||
|
@ -90,4 +75,20 @@ export const searchSessionsConfigSchema = schema.object({
|
|||
}),
|
||||
});
|
||||
|
||||
export const configSchema = schema.object({
|
||||
search: schema.object({
|
||||
aggs: schema.object({
|
||||
shardDelay: schema.object({
|
||||
// Whether or not to register the shard_delay (which is only available in snapshot versions
|
||||
// of Elasticsearch) agg type/expression function to make it available in the UI for either
|
||||
// functional or manual testing
|
||||
enabled: schema.boolean({ defaultValue: false }),
|
||||
}),
|
||||
}),
|
||||
sessions: searchSessionsConfigSchema,
|
||||
}),
|
||||
});
|
||||
|
||||
export type ConfigSchema = TypeOf<typeof configSchema>;
|
||||
|
||||
export type SearchSessionsConfigSchema = TypeOf<typeof searchSessionsConfigSchema>;
|
||||
|
|
|
@ -3,7 +3,17 @@
|
|||
"version": "kibana",
|
||||
"server": true,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["bfetch", "expressions", "uiActions", "share", "inspector", "fieldFormats", "dataViews"],
|
||||
"requiredPlugins": [
|
||||
"bfetch",
|
||||
"expressions",
|
||||
"uiActions",
|
||||
"share",
|
||||
"inspector",
|
||||
"fieldFormats",
|
||||
"dataViews",
|
||||
"screenshotMode",
|
||||
"management"
|
||||
],
|
||||
"serviceFolders": ["search", "query", "ui"],
|
||||
"optionalPlugins": ["usageCollection", "taskManager", "security"],
|
||||
"extraPublicDirs": ["common"],
|
||||
|
|
|
@ -73,6 +73,7 @@ export class DataPublicPlugin
|
|||
usageCollection,
|
||||
inspector,
|
||||
fieldFormats,
|
||||
management,
|
||||
}: DataSetupDependencies
|
||||
): DataPublicPluginSetup {
|
||||
const startServices = createStartServicesGetter(core.getStartServices);
|
||||
|
@ -84,6 +85,7 @@ export class DataPublicPlugin
|
|||
usageCollection,
|
||||
expressions,
|
||||
nowProvider: this.nowProvider,
|
||||
management,
|
||||
});
|
||||
|
||||
const queryService = this.queryService.setup({
|
||||
|
@ -117,7 +119,7 @@ export class DataPublicPlugin
|
|||
|
||||
public start(
|
||||
core: CoreStart,
|
||||
{ uiActions, fieldFormats, dataViews }: DataStartDependencies
|
||||
{ uiActions, fieldFormats, dataViews, screenshotMode }: DataStartDependencies
|
||||
): DataPublicPluginStart {
|
||||
const { uiSettings, notifications, overlays } = core;
|
||||
setNotifications(notifications);
|
||||
|
@ -131,7 +133,11 @@ export class DataPublicPlugin
|
|||
uiSettings,
|
||||
});
|
||||
|
||||
const search = this.searchService.start(core, { fieldFormats, indexPatterns: dataViews });
|
||||
const search = this.searchService.start(core, {
|
||||
fieldFormats,
|
||||
indexPatterns: dataViews,
|
||||
screenshotMode,
|
||||
});
|
||||
setSearchService(search);
|
||||
|
||||
uiActions.addTriggerAction(
|
||||
|
|
|
@ -12,6 +12,8 @@ import { CoreSetup, CoreStart } from '@kbn/core/public';
|
|||
|
||||
import { SearchService, SearchServiceSetupDependencies } from './search_service';
|
||||
import { bfetchPluginMock } from '@kbn/bfetch-plugin/public/mocks';
|
||||
import { managementPluginMock } from '@kbn/management-plugin/public/mocks';
|
||||
import { screenshotModePluginMock } from '@kbn/screenshot-mode-plugin/public/mocks';
|
||||
|
||||
describe('Search service', () => {
|
||||
let searchService: SearchService;
|
||||
|
@ -19,7 +21,7 @@ describe('Search service', () => {
|
|||
let mockCoreStart: MockedKeys<CoreStart>;
|
||||
const initializerContext = coreMock.createPluginInitializerContext();
|
||||
initializerContext.config.get = jest.fn().mockReturnValue({
|
||||
search: { aggs: { shardDelay: { enabled: false } } },
|
||||
search: { aggs: { shardDelay: { enabled: false } }, sessions: { enabled: true } },
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -35,6 +37,7 @@ describe('Search service', () => {
|
|||
packageInfo: { version: '8' },
|
||||
bfetch,
|
||||
expressions: { registerFunction: jest.fn(), registerType: jest.fn() },
|
||||
management: managementPluginMock.createSetupContract(),
|
||||
} as unknown as SearchServiceSetupDependencies);
|
||||
expect(setup).toHaveProperty('aggs');
|
||||
expect(setup).toHaveProperty('usageCollector');
|
||||
|
@ -45,9 +48,18 @@ describe('Search service', () => {
|
|||
|
||||
describe('start()', () => {
|
||||
it('exposes proper contract', async () => {
|
||||
const bfetch = bfetchPluginMock.createSetupContract();
|
||||
searchService.setup(mockCoreSetup, {
|
||||
packageInfo: { version: '8' },
|
||||
bfetch,
|
||||
expressions: { registerFunction: jest.fn(), registerType: jest.fn() },
|
||||
management: managementPluginMock.createSetupContract(),
|
||||
} as unknown as SearchServiceSetupDependencies);
|
||||
|
||||
const start = searchService.start(mockCoreStart, {
|
||||
fieldFormats: {},
|
||||
indexPatterns: {},
|
||||
screenshotMode: screenshotModePluginMock.createStartContract(),
|
||||
} as any);
|
||||
expect(start).toHaveProperty('aggs');
|
||||
expect(start).toHaveProperty('search');
|
||||
|
|
|
@ -7,62 +7,71 @@
|
|||
*/
|
||||
|
||||
import {
|
||||
Plugin,
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
Plugin,
|
||||
PluginInitializerContext,
|
||||
StartServicesAccessor,
|
||||
} from '@kbn/core/public';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import React from 'react';
|
||||
import moment from 'moment';
|
||||
import { BfetchPublicSetup } from '@kbn/bfetch-plugin/public';
|
||||
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
|
||||
import { ExpressionsSetup } from '@kbn/expressions-plugin/public';
|
||||
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
|
||||
import { Storage } from '@kbn/kibana-utils-plugin/public';
|
||||
import { ScreenshotModePluginStart } from '@kbn/screenshot-mode-plugin/public';
|
||||
import { ManagementSetup } from '@kbn/management-plugin/public';
|
||||
import type { ISearchSetup, ISearchStart } from './types';
|
||||
|
||||
import { handleResponse } from './fetch';
|
||||
import {
|
||||
kibana,
|
||||
kibanaContext,
|
||||
ISearchGeneric,
|
||||
SearchSourceDependencies,
|
||||
SearchSourceService,
|
||||
extendedBoundsFunction,
|
||||
ipRangeFunction,
|
||||
kibanaTimerangeFunction,
|
||||
luceneFunction,
|
||||
kqlFunction,
|
||||
fieldFunction,
|
||||
numericalRangeFunction,
|
||||
rangeFunction,
|
||||
cidrFunction,
|
||||
dateRangeFunction,
|
||||
esRawResponse,
|
||||
existsFilterFunction,
|
||||
extendedBoundsFunction,
|
||||
fieldFunction,
|
||||
geoBoundingBoxFunction,
|
||||
geoPointFunction,
|
||||
ipRangeFunction,
|
||||
ISearchGeneric,
|
||||
kibana,
|
||||
kibanaContext,
|
||||
kibanaFilterFunction,
|
||||
kibanaTimerangeFunction,
|
||||
kqlFunction,
|
||||
luceneFunction,
|
||||
numericalRangeFunction,
|
||||
phraseFilterFunction,
|
||||
queryFilterFunction,
|
||||
rangeFilterFunction,
|
||||
rangeFunction,
|
||||
removeFilterFunction,
|
||||
SearchSourceDependencies,
|
||||
SearchSourceService,
|
||||
selectFilterFunction,
|
||||
kibanaFilterFunction,
|
||||
phraseFilterFunction,
|
||||
esRawResponse,
|
||||
eqlRawResponse,
|
||||
} from '../../common/search';
|
||||
import { AggsService, AggsStartDependencies } from './aggs';
|
||||
import { IKibanaSearchResponse, IndexPatternsContract, SearchRequest } from '..';
|
||||
import { ISearchInterceptor, SearchInterceptor } from './search_interceptor';
|
||||
import { SearchUsageCollector, createUsageCollector } from './collectors';
|
||||
import { createUsageCollector, SearchUsageCollector } from './collectors';
|
||||
import { getEsaggs, getEsdsl, getEql } from './expressions';
|
||||
import { ISessionsClient, ISessionService, SessionsClient, SessionService } from './session';
|
||||
import { ConfigSchema } from '../../config';
|
||||
import {
|
||||
SHARD_DELAY_AGG_NAME,
|
||||
getShardDelayBucketAgg,
|
||||
SHARD_DELAY_AGG_NAME,
|
||||
} from '../../common/search/aggs/buckets/shard_delay';
|
||||
import { aggShardDelay } from '../../common/search/aggs/buckets/shard_delay_fn';
|
||||
import { DataPublicPluginStart, DataStartDependencies } from '../types';
|
||||
import { NowProviderInternalContract } from '../now_provider';
|
||||
import { getKibanaContext } from './expressions/kibana_context';
|
||||
import { createConnectedSearchSessionIndicator } from './session/session_indicator';
|
||||
|
||||
import { registerSearchSessionsMgmt } from './session/sessions_mgmt';
|
||||
|
||||
/** @internal */
|
||||
export interface SearchServiceSetupDependencies {
|
||||
|
@ -70,12 +79,14 @@ export interface SearchServiceSetupDependencies {
|
|||
expressions: ExpressionsSetup;
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
nowProvider: NowProviderInternalContract;
|
||||
management: ManagementSetup;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface SearchServiceStartDependencies {
|
||||
fieldFormats: AggsStartDependencies['fieldFormats'];
|
||||
indexPatterns: IndexPatternsContract;
|
||||
screenshotMode: ScreenshotModePluginStart;
|
||||
}
|
||||
|
||||
export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
||||
|
@ -89,9 +100,16 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
constructor(private initializerContext: PluginInitializerContext<ConfigSchema>) {}
|
||||
|
||||
public setup(
|
||||
{ http, getStartServices, notifications, uiSettings, executionContext, theme }: CoreSetup,
|
||||
{ bfetch, expressions, usageCollection, nowProvider }: SearchServiceSetupDependencies
|
||||
core: CoreSetup,
|
||||
{
|
||||
bfetch,
|
||||
expressions,
|
||||
usageCollection,
|
||||
nowProvider,
|
||||
management,
|
||||
}: SearchServiceSetupDependencies
|
||||
): ISearchSetup {
|
||||
const { http, getStartServices, notifications, uiSettings, executionContext, theme } = core;
|
||||
this.usageCollector = createUsageCollector(getStartServices, usageCollection);
|
||||
|
||||
this.sessionsClient = new SessionsClient({ http });
|
||||
|
@ -173,6 +191,21 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
expressions.registerFunction(aggShardDelay);
|
||||
}
|
||||
|
||||
const config = this.initializerContext.config.get<ConfigSchema>();
|
||||
if (config.search.sessions.enabled) {
|
||||
const sessionsConfig = config.search.sessions;
|
||||
registerSearchSessionsMgmt(
|
||||
core as CoreSetup<DataStartDependencies>,
|
||||
{
|
||||
searchUsageCollector: this.usageCollector!,
|
||||
sessionsClient: this.sessionsClient,
|
||||
management,
|
||||
},
|
||||
sessionsConfig,
|
||||
this.initializerContext.env.packageInfo.version
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
aggs,
|
||||
usageCollector: this.usageCollector!,
|
||||
|
@ -182,8 +215,8 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
}
|
||||
|
||||
public start(
|
||||
{ http, theme, uiSettings }: CoreStart,
|
||||
{ fieldFormats, indexPatterns }: SearchServiceStartDependencies
|
||||
{ http, theme, uiSettings, chrome, application }: CoreStart,
|
||||
{ fieldFormats, indexPatterns, screenshotMode }: SearchServiceStartDependencies
|
||||
): ISearchStart {
|
||||
const search = ((request, options = {}) => {
|
||||
return this.searchInterceptor.search(request, options);
|
||||
|
@ -199,6 +232,28 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
handleResponse(request, response, theme),
|
||||
};
|
||||
|
||||
const config = this.initializerContext.config.get();
|
||||
if (config.search.sessions.enabled) {
|
||||
chrome.setBreadcrumbsAppendExtension({
|
||||
content: toMountPoint(
|
||||
React.createElement(
|
||||
createConnectedSearchSessionIndicator({
|
||||
sessionService: this.sessionService,
|
||||
application,
|
||||
basePath: http.basePath,
|
||||
storage: new Storage(window.localStorage),
|
||||
disableSaveAfterSessionCompletesTimeout: moment
|
||||
.duration(config.search.sessions.notTouchedTimeout)
|
||||
.asMilliseconds(),
|
||||
usageCollector: this.usageCollector,
|
||||
tourDisabled: screenshotMode.isScreenshotMode(),
|
||||
})
|
||||
),
|
||||
{ theme$: theme.theme$ }
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
aggs: this.aggsService.start({ fieldFormats, uiSettings, indexPatterns }),
|
||||
search,
|
||||
|
|
|
@ -1,15 +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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { ReactNode } from 'react';
|
||||
import { StubBrowserStorage } from '@kbn/test-jest-helpers';
|
||||
import { render, waitFor, screen, act } from '@testing-library/react';
|
||||
import { Storage } from '@kbn/kibana-utils-plugin/public';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { dataPluginMock } from '../../../../mocks';
|
||||
import { createConnectedSearchSessionIndicator } from './connected_search_session_indicator';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
@ -19,12 +20,12 @@ import {
|
|||
SearchSessionState,
|
||||
SearchUsageCollector,
|
||||
TimefilterContract,
|
||||
} from '@kbn/data-plugin/public';
|
||||
} from '../../../..';
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { TOUR_RESTORE_STEP_KEY, TOUR_TAKING_TOO_LONG_STEP_KEY } from './search_session_tour';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
|
||||
import { createSearchUsageCollectorMock } from '@kbn/data-plugin/public/search/collectors/mocks';
|
||||
import { createSearchUsageCollectorMock } from '../../../collectors/mocks';
|
||||
|
||||
const coreStart = coreMock.createStart();
|
||||
const application = coreStart.application;
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
|
@ -10,12 +11,14 @@ import { debounce, distinctUntilChanged, mapTo, switchMap, tap } from 'rxjs/oper
|
|||
import { merge, of, timer } from 'rxjs';
|
||||
import useObservable from 'react-use/lib/useObservable';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ISessionService, SearchSessionState, SearchUsageCollector } from '@kbn/data-plugin/public';
|
||||
import { RedirectAppLinks } from '@kbn/kibana-react-plugin/public';
|
||||
import { ApplicationStart, IBasePath } from '@kbn/core/public';
|
||||
import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public';
|
||||
import { ApplicationStart, IBasePath } from '@kbn/core/public';
|
||||
import { SearchSessionIndicator, SearchSessionIndicatorRef } from '../search_session_indicator';
|
||||
import { useSearchSessionTour } from './search_session_tour';
|
||||
import { SearchUsageCollector } from '../../../collectors';
|
||||
import { ISessionService } from '../../session_service';
|
||||
import { SearchSessionState } from '../../search_session_state';
|
||||
|
||||
export interface SearchSessionIndicatorDeps {
|
||||
sessionService: ISessionService;
|
||||
|
@ -82,7 +85,7 @@ export const createConnectedSearchSessionIndicator = ({
|
|||
if (disableSaveAfterSessionCompleteTimedOut) {
|
||||
saveDisabled = true;
|
||||
saveDisabledReasonText = i18n.translate(
|
||||
'xpack.data.searchSessionIndicator.disabledDueToTimeoutMessage',
|
||||
'data.searchSessionIndicator.disabledDueToTimeoutMessage',
|
||||
{
|
||||
defaultMessage: 'Search session results expired.',
|
||||
}
|
||||
|
@ -99,7 +102,7 @@ export const createConnectedSearchSessionIndicator = ({
|
|||
if (!sessionService.hasAccess()) {
|
||||
managementDisabled = saveDisabled = true;
|
||||
managementDisabledReasonText = saveDisabledReasonText = i18n.translate(
|
||||
'xpack.data.searchSessionIndicator.disabledDueToDisabledGloballyMessage',
|
||||
'data.searchSessionIndicator.disabledDueToDisabledGloballyMessage',
|
||||
{
|
||||
defaultMessage: "You don't have permissions to manage search sessions",
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export type { SearchSessionIndicatorDeps } from './connected_search_session_indicator';
|
|
@ -1,15 +1,17 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { once } from 'lodash';
|
||||
import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public';
|
||||
import { SearchSessionState, SearchUsageCollector } from '@kbn/data-plugin/public';
|
||||
import { SearchSessionIndicatorRef } from '../search_session_indicator';
|
||||
import { SearchSessionState } from '../../search_session_state';
|
||||
import { SearchUsageCollector } from '../../../collectors';
|
||||
|
||||
const TOUR_TAKING_TOO_LONG_TIMEOUT = 10000;
|
||||
export const TOUR_TAKING_TOO_LONG_STEP_KEY = `data.searchSession.tour.takingTooLong`;
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export enum SearchSessionViewState {
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export * from './connected_search_session_indicator';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export * from './search_session_name';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export * from './search_session_name';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
|
@ -45,7 +46,7 @@ export const SearchSessionName: React.FC<SearchSessionNameProps> = ({ name, edit
|
|||
autoFocus={true}
|
||||
iconType={'pencil'}
|
||||
color={'text'}
|
||||
aria-label={i18n.translate('xpack.data.searchSessionName.editAriaLabelText', {
|
||||
aria-label={i18n.translate('data.searchSessionName.editAriaLabelText', {
|
||||
defaultMessage: 'Edit search session name',
|
||||
})}
|
||||
data-test-subj={'searchSessionNameEdit'}
|
||||
|
@ -56,14 +57,14 @@ export const SearchSessionName: React.FC<SearchSessionNameProps> = ({ name, edit
|
|||
<EuiFieldText
|
||||
autoFocus={true}
|
||||
compressed={true}
|
||||
placeholder={i18n.translate('xpack.data.searchSessionName.placeholderText', {
|
||||
placeholder={i18n.translate('data.searchSessionName.placeholderText', {
|
||||
defaultMessage: 'Enter a name for the search session',
|
||||
})}
|
||||
value={newName}
|
||||
onChange={(e) => {
|
||||
setNewName(e.target.value);
|
||||
}}
|
||||
aria-label={i18n.translate('xpack.data.searchSessionName.ariaLabelText', {
|
||||
aria-label={i18n.translate('data.searchSessionName.ariaLabelText', {
|
||||
defaultMessage: 'Search session name',
|
||||
})}
|
||||
data-test-subj={'searchSessionNameInput'}
|
||||
|
@ -89,10 +90,7 @@ export const SearchSessionName: React.FC<SearchSessionNameProps> = ({ name, edit
|
|||
isLoading={isSaving}
|
||||
data-test-subj={'searchSessionNameSave'}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.data.searchSessionName.saveButtonText"
|
||||
defaultMessage="Save"
|
||||
/>
|
||||
<FormattedMessage id="data.searchSessionName.saveButtonText" defaultMessage="Save" />
|
||||
</EuiButtonEmpty>
|
||||
}
|
||||
/>
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EuiDelayRender, EuiLoadingSpinner } from '@elastic/eui';
|
|
@ -1,14 +1,15 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { SearchSessionState } from '@kbn/data-plugin/public';
|
||||
import { SearchSessionIndicator } from './search_session_indicator';
|
||||
import { SearchSessionState } from '../../search_session_state';
|
||||
|
||||
storiesOf('components/SearchSessionIndicator', module).add('default', () => {
|
||||
const [searchSessionName, setSearchSessionName] = React.useState('Discover session');
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { ReactNode } from 'react';
|
||||
|
@ -10,7 +11,7 @@ import { screen, render } from '@testing-library/react';
|
|||
import userEvent from '@testing-library/user-event';
|
||||
import { SearchSessionIndicator } from './search_session_indicator';
|
||||
import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
|
||||
import { SearchSessionState } from '@kbn/data-plugin/public';
|
||||
import { SearchSessionState } from '../../../..';
|
||||
|
||||
function Container({ children }: { children?: ReactNode }) {
|
||||
return <IntlProvider locale="en">{children}</IntlProvider>;
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useImperativeHandle } from 'react';
|
||||
|
@ -22,10 +23,10 @@ import {
|
|||
import moment from 'moment';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { SearchSessionState } from '@kbn/data-plugin/public';
|
||||
import { CheckInEmptyCircle, PartialClock } from './custom_icons';
|
||||
import './search_session_indicator.scss';
|
||||
import { SearchSessionName } from './components';
|
||||
import { SearchSessionState } from '../../search_session_state';
|
||||
|
||||
export interface SearchSessionIndicatorProps {
|
||||
state: SearchSessionState;
|
||||
|
@ -59,7 +60,7 @@ const CancelButton = ({ onCancel = () => {}, buttonProps = {} }: ActionButtonPro
|
|||
{...buttonProps}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.data.searchSessionIndicator.cancelButtonText"
|
||||
id="data.searchSessionIndicator.cancelButtonText"
|
||||
defaultMessage="Stop session"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
|
@ -79,7 +80,7 @@ const ContinueInBackgroundButton = ({
|
|||
{...buttonProps}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.data.searchSessionIndicator.continueInBackgroundButtonText"
|
||||
id="data.searchSessionIndicator.continueInBackgroundButtonText"
|
||||
defaultMessage="Save session"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
|
@ -103,7 +104,7 @@ const ViewAllSearchSessionsButton = ({
|
|||
{...buttonProps}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.data.searchSessionIndicator.viewSearchSessionsLinkText"
|
||||
id="data.searchSessionIndicator.viewSearchSessionsLinkText"
|
||||
defaultMessage="Manage sessions"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
|
@ -124,7 +125,7 @@ const SaveButton = ({
|
|||
{...buttonProps}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.data.searchSessionIndicator.saveButtonText"
|
||||
id="data.searchSessionIndicator.saveButtonText"
|
||||
defaultMessage="Save session"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
|
@ -150,24 +151,22 @@ const searchSessionIndicatorViewStateToProps: {
|
|||
button: {
|
||||
color: 'text',
|
||||
iconType: PartialClock,
|
||||
'aria-label': i18n.translate(
|
||||
'xpack.data.searchSessionIndicator.loadingResultsIconAriaLabel',
|
||||
{ defaultMessage: 'Search session loading' }
|
||||
),
|
||||
tooltipText: i18n.translate(
|
||||
'xpack.data.searchSessionIndicator.loadingResultsIconTooltipText',
|
||||
{ defaultMessage: 'Search session loading' }
|
||||
),
|
||||
'aria-label': i18n.translate('data.searchSessionIndicator.loadingResultsIconAriaLabel', {
|
||||
defaultMessage: 'Search session loading',
|
||||
}),
|
||||
tooltipText: i18n.translate('data.searchSessionIndicator.loadingResultsIconTooltipText', {
|
||||
defaultMessage: 'Search session loading',
|
||||
}),
|
||||
},
|
||||
popover: {
|
||||
title: i18n.translate('xpack.data.searchSessionIndicator.loadingResultsTitle', {
|
||||
title: i18n.translate('data.searchSessionIndicator.loadingResultsTitle', {
|
||||
defaultMessage: 'Your search is taking a while...',
|
||||
}),
|
||||
description: i18n.translate('xpack.data.searchSessionIndicator.loadingResultsDescription', {
|
||||
description: i18n.translate('data.searchSessionIndicator.loadingResultsDescription', {
|
||||
defaultMessage: 'Save your session, continue your work, and return to completed results',
|
||||
}),
|
||||
whenText: (props: SearchSessionIndicatorProps) =>
|
||||
i18n.translate('xpack.data.searchSessionIndicator.loadingResultsWhenText', {
|
||||
i18n.translate('data.searchSessionIndicator.loadingResultsWhenText', {
|
||||
defaultMessage: 'Started {when}',
|
||||
values: {
|
||||
when: props.startedTime ? moment(props.startedTime).format(`L @ LTS`) : '',
|
||||
|
@ -181,28 +180,22 @@ const searchSessionIndicatorViewStateToProps: {
|
|||
button: {
|
||||
color: 'text',
|
||||
iconType: 'check',
|
||||
'aria-label': i18n.translate('xpack.data.searchSessionIndicator.resultsLoadedIconAriaLabel', {
|
||||
'aria-label': i18n.translate('data.searchSessionIndicator.resultsLoadedIconAriaLabel', {
|
||||
defaultMessage: 'Search session complete',
|
||||
}),
|
||||
tooltipText: i18n.translate('data.searchSessionIndicator.resultsLoadedIconTooltipText', {
|
||||
defaultMessage: 'Search session complete',
|
||||
}),
|
||||
tooltipText: i18n.translate(
|
||||
'xpack.data.searchSessionIndicator.resultsLoadedIconTooltipText',
|
||||
{
|
||||
defaultMessage: 'Search session complete',
|
||||
}
|
||||
),
|
||||
},
|
||||
popover: {
|
||||
title: i18n.translate('xpack.data.searchSessionIndicator.resultsLoadedText', {
|
||||
title: i18n.translate('data.searchSessionIndicator.resultsLoadedText', {
|
||||
defaultMessage: 'Search session complete',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'xpack.data.searchSessionIndicator.resultsLoadedDescriptionText',
|
||||
{
|
||||
defaultMessage: 'Save your session and return to it later',
|
||||
}
|
||||
),
|
||||
description: i18n.translate('data.searchSessionIndicator.resultsLoadedDescriptionText', {
|
||||
defaultMessage: 'Save your session and return to it later',
|
||||
}),
|
||||
whenText: (props: SearchSessionIndicatorProps) =>
|
||||
i18n.translate('xpack.data.searchSessionIndicator.resultsLoadedWhenText', {
|
||||
i18n.translate('data.searchSessionIndicator.resultsLoadedWhenText', {
|
||||
defaultMessage: 'Completed {when}',
|
||||
values: {
|
||||
when: props.completedTime ? moment(props.completedTime).format(`L @ LTS`) : '',
|
||||
|
@ -216,30 +209,30 @@ const searchSessionIndicatorViewStateToProps: {
|
|||
button: {
|
||||
iconType: EuiLoadingSpinner,
|
||||
'aria-label': i18n.translate(
|
||||
'xpack.data.searchSessionIndicator.loadingInTheBackgroundIconAriaLabel',
|
||||
'data.searchSessionIndicator.loadingInTheBackgroundIconAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Saved session in progress',
|
||||
}
|
||||
),
|
||||
tooltipText: i18n.translate(
|
||||
'xpack.data.searchSessionIndicator.loadingInTheBackgroundIconTooltipText',
|
||||
'data.searchSessionIndicator.loadingInTheBackgroundIconTooltipText',
|
||||
{
|
||||
defaultMessage: 'Saved session in progress',
|
||||
}
|
||||
),
|
||||
},
|
||||
popover: {
|
||||
title: i18n.translate('xpack.data.searchSessionIndicator.loadingInTheBackgroundTitleText', {
|
||||
title: i18n.translate('data.searchSessionIndicator.loadingInTheBackgroundTitleText', {
|
||||
defaultMessage: 'Saved session in progress',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'xpack.data.searchSessionIndicator.loadingInTheBackgroundDescriptionText',
|
||||
'data.searchSessionIndicator.loadingInTheBackgroundDescriptionText',
|
||||
{
|
||||
defaultMessage: 'You can return to completed results from Management',
|
||||
}
|
||||
),
|
||||
whenText: (props: SearchSessionIndicatorProps) =>
|
||||
i18n.translate('xpack.data.searchSessionIndicator.loadingInTheBackgroundWhenText', {
|
||||
i18n.translate('data.searchSessionIndicator.loadingInTheBackgroundWhenText', {
|
||||
defaultMessage: 'Started {when}',
|
||||
values: {
|
||||
when: props.startedTime ? moment(props.startedTime).format(`L @ LTS`) : '',
|
||||
|
@ -254,33 +247,30 @@ const searchSessionIndicatorViewStateToProps: {
|
|||
color: 'success',
|
||||
iconType: 'checkInCircleFilled',
|
||||
'aria-label': i18n.translate(
|
||||
'xpack.data.searchSessionIndicator.resultLoadedInTheBackgroundIconAriaLabel',
|
||||
'data.searchSessionIndicator.resultLoadedInTheBackgroundIconAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Saved session complete',
|
||||
}
|
||||
),
|
||||
tooltipText: i18n.translate(
|
||||
'xpack.data.searchSessionIndicator.resultLoadedInTheBackgroundIconTooltipText',
|
||||
'data.searchSessionIndicator.resultLoadedInTheBackgroundIconTooltipText',
|
||||
{
|
||||
defaultMessage: 'Saved session complete',
|
||||
}
|
||||
),
|
||||
},
|
||||
popover: {
|
||||
title: i18n.translate(
|
||||
'xpack.data.searchSessionIndicator.resultLoadedInTheBackgroundTitleText',
|
||||
{
|
||||
defaultMessage: 'Search session saved',
|
||||
}
|
||||
),
|
||||
title: i18n.translate('data.searchSessionIndicator.resultLoadedInTheBackgroundTitleText', {
|
||||
defaultMessage: 'Search session saved',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'xpack.data.searchSessionIndicator.resultLoadedInTheBackgroundDescriptionText',
|
||||
'data.searchSessionIndicator.resultLoadedInTheBackgroundDescriptionText',
|
||||
{
|
||||
defaultMessage: 'You can return to these results from Management',
|
||||
}
|
||||
),
|
||||
whenText: (props: SearchSessionIndicatorProps) =>
|
||||
i18n.translate('xpack.data.searchSessionIndicator.resultLoadedInTheBackgroundWhenText', {
|
||||
i18n.translate('data.searchSessionIndicator.resultLoadedInTheBackgroundWhenText', {
|
||||
defaultMessage: 'Completed {when}',
|
||||
values: {
|
||||
when: props.completedTime ? moment(props.completedTime).format(`L @ LTS`) : '',
|
||||
|
@ -293,26 +283,23 @@ const searchSessionIndicatorViewStateToProps: {
|
|||
button: {
|
||||
color: 'success',
|
||||
iconType: CheckInEmptyCircle,
|
||||
'aria-label': i18n.translate(
|
||||
'xpack.data.searchSessionIndicator.restoredResultsIconAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Saved session restored',
|
||||
}
|
||||
),
|
||||
tooltipText: i18n.translate('xpack.data.searchSessionIndicator.restoredResultsTooltipText', {
|
||||
'aria-label': i18n.translate('data.searchSessionIndicator.restoredResultsIconAriaLabel', {
|
||||
defaultMessage: 'Saved session restored',
|
||||
}),
|
||||
tooltipText: i18n.translate('data.searchSessionIndicator.restoredResultsTooltipText', {
|
||||
defaultMessage: 'Search session restored',
|
||||
}),
|
||||
},
|
||||
popover: {
|
||||
title: i18n.translate('xpack.data.searchSessionIndicator.restoredTitleText', {
|
||||
title: i18n.translate('data.searchSessionIndicator.restoredTitleText', {
|
||||
defaultMessage: 'Search session restored',
|
||||
}),
|
||||
description: i18n.translate('xpack.data.searchSessionIndicator.restoredDescriptionText', {
|
||||
description: i18n.translate('data.searchSessionIndicator.restoredDescriptionText', {
|
||||
defaultMessage:
|
||||
'You are viewing cached data from a specific time range. Changing the time range or filters will re-run the session',
|
||||
}),
|
||||
whenText: (props: SearchSessionIndicatorProps) =>
|
||||
i18n.translate('xpack.data.searchSessionIndicator.restoredWhenText', {
|
||||
i18n.translate('data.searchSessionIndicator.restoredWhenText', {
|
||||
defaultMessage: 'Completed {when}',
|
||||
values: {
|
||||
when: props.completedTime ? moment(props.completedTime).format(`L @ LTS`) : '',
|
||||
|
@ -325,22 +312,22 @@ const searchSessionIndicatorViewStateToProps: {
|
|||
button: {
|
||||
color: 'danger',
|
||||
iconType: 'alert',
|
||||
'aria-label': i18n.translate('xpack.data.searchSessionIndicator.canceledIconAriaLabel', {
|
||||
'aria-label': i18n.translate('data.searchSessionIndicator.canceledIconAriaLabel', {
|
||||
defaultMessage: 'Search session stopped',
|
||||
}),
|
||||
tooltipText: i18n.translate('xpack.data.searchSessionIndicator.canceledTooltipText', {
|
||||
tooltipText: i18n.translate('data.searchSessionIndicator.canceledTooltipText', {
|
||||
defaultMessage: 'Search session stopped',
|
||||
}),
|
||||
},
|
||||
popover: {
|
||||
title: i18n.translate('xpack.data.searchSessionIndicator.canceledTitleText', {
|
||||
title: i18n.translate('data.searchSessionIndicator.canceledTitleText', {
|
||||
defaultMessage: 'Search session stopped',
|
||||
}),
|
||||
description: i18n.translate('xpack.data.searchSessionIndicator.canceledDescriptionText', {
|
||||
description: i18n.translate('data.searchSessionIndicator.canceledDescriptionText', {
|
||||
defaultMessage: 'You are viewing incomplete data',
|
||||
}),
|
||||
whenText: (props: SearchSessionIndicatorProps) =>
|
||||
i18n.translate('xpack.data.searchSessionIndicator.canceledWhenText', {
|
||||
i18n.translate('data.searchSessionIndicator.canceledWhenText', {
|
||||
defaultMessage: 'Stopped {when}',
|
||||
values: {
|
||||
when: props.canceledTime ? moment(props.canceledTime).format(`L @ LTS`) : '',
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { ReactNode } from 'react';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { CoreSetup } from '@kbn/core/public';
|
||||
|
@ -11,24 +12,24 @@ import type {
|
|||
AppDependencies,
|
||||
IManagementSectionsPluginsSetup,
|
||||
IManagementSectionsPluginsStart,
|
||||
SessionsConfigSchema,
|
||||
} from '..';
|
||||
import { APP } from '..';
|
||||
import { SearchSessionsMgmtAPI } from '../lib/api';
|
||||
import { AsyncSearchIntroDocumentation } from '../lib/documentation';
|
||||
import { renderApp } from './render';
|
||||
import { SearchSessionsConfigSchema } from '../../../../../config';
|
||||
|
||||
export class SearchSessionsMgmtApp {
|
||||
constructor(
|
||||
private coreSetup: CoreSetup<IManagementSectionsPluginsStart>,
|
||||
private config: SessionsConfigSchema,
|
||||
private setupDeps: IManagementSectionsPluginsSetup,
|
||||
private config: SearchSessionsConfigSchema,
|
||||
private kibanaVersion: string,
|
||||
private params: ManagementAppMountParams,
|
||||
private pluginsSetup: IManagementSectionsPluginsSetup
|
||||
private params: ManagementAppMountParams
|
||||
) {}
|
||||
|
||||
public async mountManagementSection() {
|
||||
const { coreSetup, params, pluginsSetup } = this;
|
||||
const { coreSetup, params, setupDeps } = this;
|
||||
const [coreStart, pluginsStart] = await coreSetup.getStartServices();
|
||||
|
||||
const {
|
||||
|
@ -40,24 +41,21 @@ export class SearchSessionsMgmtApp {
|
|||
uiSettings,
|
||||
application,
|
||||
} = coreStart;
|
||||
const { data, share } = pluginsStart;
|
||||
|
||||
const pluginName = APP.getI18nName();
|
||||
docTitle.change(pluginName);
|
||||
params.setBreadcrumbs([{ text: pluginName }]);
|
||||
this.params.setBreadcrumbs([{ text: pluginName }]);
|
||||
|
||||
const { sessionsClient } = data.search;
|
||||
const api = new SearchSessionsMgmtAPI(sessionsClient, this.config, {
|
||||
const api = new SearchSessionsMgmtAPI(setupDeps.sessionsClient, this.config, {
|
||||
notifications,
|
||||
locators: share.url.locators,
|
||||
locators: pluginsStart.share.url.locators,
|
||||
application,
|
||||
usageCollector: pluginsSetup.data.search.usageCollector,
|
||||
usageCollector: setupDeps.searchUsageCollector,
|
||||
});
|
||||
|
||||
const documentation = new AsyncSearchIntroDocumentation(docLinks);
|
||||
|
||||
const dependencies: AppDependencies = {
|
||||
plugins: pluginsSetup,
|
||||
config: this.config,
|
||||
documentation,
|
||||
core: coreStart,
|
||||
|
@ -65,8 +63,9 @@ export class SearchSessionsMgmtApp {
|
|||
http,
|
||||
i18n,
|
||||
uiSettings,
|
||||
share,
|
||||
share: pluginsStart.share,
|
||||
kibanaVersion: this.kibanaVersion,
|
||||
searchUsageCollector: setupDeps.searchUsageCollector,
|
||||
};
|
||||
|
||||
const { element } = params;
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EuiConfirmModal } from '@elastic/eui';
|
||||
|
@ -26,16 +27,16 @@ const DeleteConfirm = (props: DeleteButtonProps & { onActionDismiss: OnActionDis
|
|||
const { name, id } = searchSession;
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const title = i18n.translate('xpack.data.mgmt.searchSessions.cancelModal.title', {
|
||||
const title = i18n.translate('data.mgmt.searchSessions.cancelModal.title', {
|
||||
defaultMessage: 'Delete search session',
|
||||
});
|
||||
const confirm = i18n.translate('xpack.data.mgmt.searchSessions.cancelModal.deleteButton', {
|
||||
const confirm = i18n.translate('data.mgmt.searchSessions.cancelModal.deleteButton', {
|
||||
defaultMessage: 'Delete',
|
||||
});
|
||||
const cancel = i18n.translate('xpack.data.mgmt.searchSessions.cancelModal.cancelButton', {
|
||||
const cancel = i18n.translate('data.mgmt.searchSessions.cancelModal.cancelButton', {
|
||||
defaultMessage: 'Cancel',
|
||||
});
|
||||
const message = i18n.translate('xpack.data.mgmt.searchSessions.cancelModal.message', {
|
||||
const message = i18n.translate('data.mgmt.searchSessions.cancelModal.message', {
|
||||
defaultMessage: `Deleting the search session \'{name}\' deletes all cached results.`,
|
||||
values: {
|
||||
name,
|
||||
|
@ -68,9 +69,7 @@ export const createDeleteActionDescriptor = (
|
|||
core: CoreStart
|
||||
): IClickActionDescriptor => ({
|
||||
iconType: 'crossInACircleFilled',
|
||||
label: (
|
||||
<FormattedMessage id="xpack.data.mgmt.searchSessions.actionDelete" defaultMessage="Delete" />
|
||||
),
|
||||
label: <FormattedMessage id="data.mgmt.searchSessions.actionDelete" defaultMessage="Delete" />,
|
||||
onClick: async () => {
|
||||
const ref = core.overlays.openModal(
|
||||
toMountPoint(
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EuiConfirmModal } from '@elastic/eui';
|
||||
|
@ -31,16 +32,16 @@ const ExtendConfirm = ({ ...props }: ExtendButtonProps & { onActionDismiss: OnAc
|
|||
|
||||
const newExpiration = moment(expires).add(extendByDuration);
|
||||
|
||||
const title = i18n.translate('xpack.data.mgmt.searchSessions.extendModal.title', {
|
||||
const title = i18n.translate('data.mgmt.searchSessions.extendModal.title', {
|
||||
defaultMessage: 'Extend search session expiration',
|
||||
});
|
||||
const confirm = i18n.translate('xpack.data.mgmt.searchSessions.extendModal.extendButton', {
|
||||
const confirm = i18n.translate('data.mgmt.searchSessions.extendModal.extendButton', {
|
||||
defaultMessage: 'Extend expiration',
|
||||
});
|
||||
const extend = i18n.translate('xpack.data.mgmt.searchSessions.extendModal.dontExtendButton', {
|
||||
const extend = i18n.translate('data.mgmt.searchSessions.extendModal.dontExtendButton', {
|
||||
defaultMessage: 'Cancel',
|
||||
});
|
||||
const message = i18n.translate('xpack.data.mgmt.searchSessions.extendModal.extendMessage', {
|
||||
const message = i18n.translate('data.mgmt.searchSessions.extendModal.extendMessage', {
|
||||
defaultMessage: "The search session '{name}' expiration would be extended until {newExpires}.",
|
||||
values: {
|
||||
name,
|
||||
|
@ -75,9 +76,7 @@ export const createExtendActionDescriptor = (
|
|||
core: CoreStart
|
||||
): IClickActionDescriptor => ({
|
||||
iconType: extendSessionIcon,
|
||||
label: (
|
||||
<FormattedMessage id="xpack.data.mgmt.searchSessions.actionExtend" defaultMessage="Extend" />
|
||||
),
|
||||
label: <FormattedMessage id="data.mgmt.searchSessions.actionExtend" defaultMessage="Extend" />,
|
||||
onClick: async () => {
|
||||
const ref = core.overlays.openModal(
|
||||
toMountPoint(
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { CoreStart } from '@kbn/core/public';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { PopoverActionsMenu } from './popover_actions';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EuiFlyoutBody, EuiFlyoutHeader, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
|
||||
|
@ -58,7 +59,7 @@ const InspectFlyout = ({ uiSettings, searchSession }: InspectFlyoutProps) => {
|
|||
<EuiTitle size="m">
|
||||
<h2 id="flyoutTitle">
|
||||
<FormattedMessage
|
||||
id="xpack.data.sessions.management.flyoutTitle"
|
||||
id="data.sessions.management.flyoutTitle"
|
||||
defaultMessage="Inspect search session"
|
||||
/>
|
||||
</h2>
|
||||
|
@ -69,7 +70,7 @@ const InspectFlyout = ({ uiSettings, searchSession }: InspectFlyoutProps) => {
|
|||
<EuiText size="xs">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.data.sessions.management.flyoutText"
|
||||
id="data.sessions.management.flyoutText"
|
||||
defaultMessage="Configuration for this search session"
|
||||
/>
|
||||
</p>
|
||||
|
@ -90,7 +91,7 @@ export const createInspectActionDescriptor = (
|
|||
iconType: 'document',
|
||||
label: (
|
||||
<FormattedMessage
|
||||
id="xpack.data.mgmt.searchSessions.flyoutTitle"
|
||||
id="data.mgmt.searchSessions.flyoutTitle"
|
||||
aria-label="Inspect"
|
||||
defaultMessage="Inspect"
|
||||
/>
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
|
@ -49,12 +50,12 @@ export const PopoverActionsMenu = ({
|
|||
|
||||
const renderPopoverButton = () => (
|
||||
<EuiToolTip
|
||||
content={i18n.translate('xpack.data.mgmt.searchSessions.actions.tooltip.moreActions', {
|
||||
content={i18n.translate('data.mgmt.searchSessions.actions.tooltip.moreActions', {
|
||||
defaultMessage: 'More actions',
|
||||
})}
|
||||
>
|
||||
<EuiButtonIcon
|
||||
aria-label={i18n.translate('xpack.data.mgmt.searchSessions.ariaLabel.moreActions', {
|
||||
aria-label={i18n.translate('data.mgmt.searchSessions.ariaLabel.moreActions', {
|
||||
defaultMessage: 'More actions',
|
||||
})}
|
||||
color="text"
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
|
@ -41,22 +42,19 @@ const RenameDialog = ({
|
|||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [newName, setNewName] = useState(originalName);
|
||||
|
||||
const title = i18n.translate('xpack.data.mgmt.searchSessions.renameModal.title', {
|
||||
const title = i18n.translate('data.mgmt.searchSessions.renameModal.title', {
|
||||
defaultMessage: 'Edit search session name',
|
||||
});
|
||||
const confirm = i18n.translate('xpack.data.mgmt.searchSessions.renameModal.renameButton', {
|
||||
const confirm = i18n.translate('data.mgmt.searchSessions.renameModal.renameButton', {
|
||||
defaultMessage: 'Save',
|
||||
});
|
||||
const cancel = i18n.translate('xpack.data.mgmt.searchSessions.renameModal.cancelButton', {
|
||||
const cancel = i18n.translate('data.mgmt.searchSessions.renameModal.cancelButton', {
|
||||
defaultMessage: 'Cancel',
|
||||
});
|
||||
|
||||
const label = i18n.translate(
|
||||
'xpack.data.mgmt.searchSessions.renameModal.searchSessionNameInputLabel',
|
||||
{
|
||||
defaultMessage: 'Search session name',
|
||||
}
|
||||
);
|
||||
const label = i18n.translate('data.mgmt.searchSessions.renameModal.searchSessionNameInputLabel', {
|
||||
defaultMessage: 'Search session name',
|
||||
});
|
||||
|
||||
const isNewNameValid = newName && originalName !== newName;
|
||||
|
||||
|
@ -109,9 +107,7 @@ export const createRenameActionDescriptor = (
|
|||
core: CoreStart
|
||||
): IClickActionDescriptor => ({
|
||||
iconType: 'pencil',
|
||||
label: (
|
||||
<FormattedMessage id="xpack.data.mgmt.searchSessions.actionRename" defaultMessage="Edit name" />
|
||||
),
|
||||
label: <FormattedMessage id="data.mgmt.searchSessions.actionRename" defaultMessage="Edit name" />,
|
||||
onClick: async () => {
|
||||
const ref = core.overlays.openModal(
|
||||
toMountPoint(
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export type OnActionComplete = () => void;
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EuiLinkProps, EuiText, EuiTextProps } from '@elastic/eui';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { MockedKeys } from '@kbn/utility-types/jest';
|
||||
|
@ -12,34 +13,30 @@ import moment from 'moment';
|
|||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { SessionsClient } from '@kbn/data-plugin/public/search';
|
||||
import { IManagementSectionsPluginsSetup, SessionsConfigSchema } from '..';
|
||||
import { SearchUsageCollector, SessionsClient } from '../../..';
|
||||
import { SearchSessionsMgmtAPI } from '../lib/api';
|
||||
import { AsyncSearchIntroDocumentation } from '../lib/documentation';
|
||||
import { LocaleWrapper } from '../__mocks__';
|
||||
import { SearchSessionsMgmtMain } from './main';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { managementPluginMock } from '@kbn/management-plugin/public/mocks';
|
||||
import { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { sharePluginMock } from '@kbn/share-plugin/public/mocks';
|
||||
import { SearchSessionsConfigSchema } from '../../../../../config';
|
||||
import { createSearchUsageCollectorMock } from '../../../collectors/mocks';
|
||||
|
||||
let mockCoreSetup: MockedKeys<CoreSetup>;
|
||||
let mockCoreStart: MockedKeys<CoreStart>;
|
||||
let mockShareStart: jest.Mocked<SharePluginStart>;
|
||||
let mockPluginsSetup: IManagementSectionsPluginsSetup;
|
||||
let mockConfig: SessionsConfigSchema;
|
||||
let mockConfig: SearchSessionsConfigSchema;
|
||||
let sessionsClient: SessionsClient;
|
||||
let api: SearchSessionsMgmtAPI;
|
||||
let mockSearchUsageCollector: SearchUsageCollector;
|
||||
|
||||
describe('Background Search Session Management Main', () => {
|
||||
beforeEach(() => {
|
||||
mockCoreSetup = coreMock.createSetup();
|
||||
mockCoreStart = coreMock.createStart();
|
||||
mockShareStart = sharePluginMock.createStartContract();
|
||||
mockPluginsSetup = {
|
||||
data: dataPluginMock.createSetupContract(),
|
||||
management: managementPluginMock.createSetupContract(),
|
||||
};
|
||||
mockSearchUsageCollector = createSearchUsageCollectorMock();
|
||||
mockConfig = {
|
||||
defaultExpiration: moment.duration('7d'),
|
||||
management: {
|
||||
|
@ -80,13 +77,13 @@ describe('Background Search Session Management Main', () => {
|
|||
<LocaleWrapper>
|
||||
<SearchSessionsMgmtMain
|
||||
core={mockCoreStart}
|
||||
plugins={mockPluginsSetup}
|
||||
api={api}
|
||||
http={mockCoreSetup.http}
|
||||
timezone="UTC"
|
||||
documentation={new AsyncSearchIntroDocumentation(docLinks)}
|
||||
config={mockConfig}
|
||||
kibanaVersion={'8.0.0'}
|
||||
searchUsageCollector={mockSearchUsageCollector}
|
||||
/>
|
||||
</LocaleWrapper>
|
||||
);
|
|
@ -1,19 +1,20 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EuiButtonEmpty, EuiPageHeader, EuiSpacer } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import type { CoreStart, HttpStart } from '@kbn/core/public';
|
||||
import React from 'react';
|
||||
import type { SessionsConfigSchema } from '..';
|
||||
import { IManagementSectionsPluginsSetup } from '..';
|
||||
import type { SearchSessionsMgmtAPI } from '../lib/api';
|
||||
import type { AsyncSearchIntroDocumentation } from '../lib/documentation';
|
||||
import { SearchSessionsMgmtTable } from './table';
|
||||
import { SearchSessionsConfigSchema } from '../../../../../config';
|
||||
import { SearchUsageCollector } from '../../../collectors';
|
||||
|
||||
interface Props {
|
||||
documentation: AsyncSearchIntroDocumentation;
|
||||
|
@ -21,9 +22,9 @@ interface Props {
|
|||
api: SearchSessionsMgmtAPI;
|
||||
http: HttpStart;
|
||||
timezone: string;
|
||||
config: SessionsConfigSchema;
|
||||
plugins: IManagementSectionsPluginsSetup;
|
||||
config: SearchSessionsConfigSchema;
|
||||
kibanaVersion: string;
|
||||
searchUsageCollector: SearchUsageCollector;
|
||||
}
|
||||
|
||||
export function SearchSessionsMgmtMain({ documentation, ...tableProps }: Props) {
|
||||
|
@ -32,13 +33,13 @@ export function SearchSessionsMgmtMain({ documentation, ...tableProps }: Props)
|
|||
<EuiPageHeader
|
||||
pageTitle={
|
||||
<FormattedMessage
|
||||
id="xpack.data.mgmt.searchSessions.main.sectionTitle"
|
||||
id="data.mgmt.searchSessions.main.sectionTitle"
|
||||
defaultMessage="Search Sessions"
|
||||
/>
|
||||
}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="xpack.data.mgmt.searchSessions.main.sectionDescription"
|
||||
id="data.mgmt.searchSessions.main.sectionDescription"
|
||||
defaultMessage="Manage your saved search sessions."
|
||||
/>
|
||||
}
|
||||
|
@ -50,7 +51,7 @@ export function SearchSessionsMgmtMain({ documentation, ...tableProps }: Props)
|
|||
iconType="help"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.data.mgmt.searchSessions.main.backgroundSessionsDocsLinkText"
|
||||
id="data.mgmt.searchSessions.main.backgroundSessionsDocsLinkText"
|
||||
defaultMessage="Documentation"
|
||||
/>
|
||||
</EuiButtonEmpty>,
|
|
@ -1,14 +1,15 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EuiTextProps, EuiToolTipProps } from '@elastic/eui';
|
||||
import { mount } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { SearchSessionStatus } from '@kbn/data-plugin/common';
|
||||
import { SearchSessionStatus } from '../../../../../common';
|
||||
import { UISession } from '../types';
|
||||
import { LocaleWrapper } from '../__mocks__';
|
||||
import { getStatusText, StatusIndicator } from './status';
|
|
@ -1,14 +1,15 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLoadingSpinner, EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { ReactElement } from 'react';
|
||||
import { SearchSessionStatus } from '@kbn/data-plugin/common';
|
||||
import { SearchSessionStatus } from '../../../../../common';
|
||||
import { dateString } from '../lib/date_string';
|
||||
import { UISession } from '../types';
|
||||
import { StatusDef as StatusAttributes, TableText } from '.';
|
||||
|
@ -17,23 +18,23 @@ import { StatusDef as StatusAttributes, TableText } from '.';
|
|||
export const getStatusText = (statusType: string): string => {
|
||||
switch (statusType) {
|
||||
case SearchSessionStatus.IN_PROGRESS:
|
||||
return i18n.translate('xpack.data.mgmt.searchSessions.status.label.inProgress', {
|
||||
return i18n.translate('data.mgmt.searchSessions.status.label.inProgress', {
|
||||
defaultMessage: 'In progress',
|
||||
});
|
||||
case SearchSessionStatus.EXPIRED:
|
||||
return i18n.translate('xpack.data.mgmt.searchSessions.status.label.expired', {
|
||||
return i18n.translate('data.mgmt.searchSessions.status.label.expired', {
|
||||
defaultMessage: 'Expired',
|
||||
});
|
||||
case SearchSessionStatus.CANCELLED:
|
||||
return i18n.translate('xpack.data.mgmt.searchSessions.status.label.cancelled', {
|
||||
return i18n.translate('data.mgmt.searchSessions.status.label.cancelled', {
|
||||
defaultMessage: 'Cancelled',
|
||||
});
|
||||
case SearchSessionStatus.COMPLETE:
|
||||
return i18n.translate('xpack.data.mgmt.searchSessions.status.label.complete', {
|
||||
return i18n.translate('data.mgmt.searchSessions.status.label.complete', {
|
||||
defaultMessage: 'Complete',
|
||||
});
|
||||
case SearchSessionStatus.ERROR:
|
||||
return i18n.translate('xpack.data.mgmt.searchSessions.status.label.error', {
|
||||
return i18n.translate('data.mgmt.searchSessions.status.label.error', {
|
||||
defaultMessage: 'Error',
|
||||
});
|
||||
default:
|
||||
|
@ -60,7 +61,7 @@ const getStatusAttributes = ({
|
|||
if (session.expires) {
|
||||
expireDate = dateString(session.expires!, timezone);
|
||||
} else {
|
||||
expireDate = i18n.translate('xpack.data.mgmt.searchSessions.status.expireDateUnknown', {
|
||||
expireDate = i18n.translate('data.mgmt.searchSessions.status.expireDateUnknown', {
|
||||
defaultMessage: 'unknown',
|
||||
});
|
||||
}
|
||||
|
@ -72,13 +73,10 @@ const getStatusAttributes = ({
|
|||
textColor: 'default',
|
||||
icon: <EuiLoadingSpinner />,
|
||||
label: <TableText>{getStatusText(session.status)}</TableText>,
|
||||
toolTipContent: i18n.translate(
|
||||
'xpack.data.mgmt.searchSessions.status.message.createdOn',
|
||||
{
|
||||
defaultMessage: 'Expires on {expireDate}',
|
||||
values: { expireDate },
|
||||
}
|
||||
),
|
||||
toolTipContent: i18n.translate('data.mgmt.searchSessions.status.message.createdOn', {
|
||||
defaultMessage: 'Expires on {expireDate}',
|
||||
values: { expireDate },
|
||||
}),
|
||||
};
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -88,13 +86,10 @@ const getStatusAttributes = ({
|
|||
|
||||
case SearchSessionStatus.EXPIRED:
|
||||
try {
|
||||
const toolTipContent = i18n.translate(
|
||||
'xpack.data.mgmt.searchSessions.status.message.expiredOn',
|
||||
{
|
||||
defaultMessage: 'Expired on {expireDate}',
|
||||
values: { expireDate },
|
||||
}
|
||||
);
|
||||
const toolTipContent = i18n.translate('data.mgmt.searchSessions.status.message.expiredOn', {
|
||||
defaultMessage: 'Expired on {expireDate}',
|
||||
values: { expireDate },
|
||||
});
|
||||
|
||||
return {
|
||||
icon: <EuiIcon color="#9AA" type="clock" />,
|
||||
|
@ -111,7 +106,7 @@ const getStatusAttributes = ({
|
|||
return {
|
||||
icon: <EuiIcon color="#9AA" type="crossInACircleFilled" />,
|
||||
label: <TableText>{getStatusText(session.status)}</TableText>,
|
||||
toolTipContent: i18n.translate('xpack.data.mgmt.searchSessions.status.message.cancelled', {
|
||||
toolTipContent: i18n.translate('data.mgmt.searchSessions.status.message.cancelled', {
|
||||
defaultMessage: 'Cancelled by user',
|
||||
}),
|
||||
};
|
||||
|
@ -121,7 +116,7 @@ const getStatusAttributes = ({
|
|||
textColor: 'danger',
|
||||
icon: <EuiIcon color="danger" type="crossInACircleFilled" />,
|
||||
label: <TableText>{getStatusText(session.status)}</TableText>,
|
||||
toolTipContent: i18n.translate('xpack.data.mgmt.searchSessions.status.message.error', {
|
||||
toolTipContent: i18n.translate('data.mgmt.searchSessions.status.message.error', {
|
||||
defaultMessage: 'Error: {error}',
|
||||
values: { error: (session as any).error || 'unknown' },
|
||||
}),
|
||||
|
@ -129,7 +124,7 @@ const getStatusAttributes = ({
|
|||
|
||||
case SearchSessionStatus.COMPLETE:
|
||||
try {
|
||||
const toolTipContent = i18n.translate('xpack.data.mgmt.searchSessions.status.expiresOn', {
|
||||
const toolTipContent = i18n.translate('data.mgmt.searchSessions.status.expiresOn', {
|
||||
defaultMessage: 'Expires on {expireDate}',
|
||||
values: { expireDate },
|
||||
});
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { FieldValueOptionType, SearchFilterConfig } from '@elastic/eui';
|
||||
|
@ -12,7 +13,7 @@ import { UISession } from '../../types';
|
|||
|
||||
export const getAppFilter: (tableData: UISession[]) => SearchFilterConfig = (tableData) => ({
|
||||
type: 'field_value_selection',
|
||||
name: i18n.translate('xpack.data.mgmt.searchSessions.search.filterApp', {
|
||||
name: i18n.translate('data.mgmt.searchSessions.search.filterApp', {
|
||||
defaultMessage: 'App',
|
||||
}),
|
||||
field: 'appId',
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { SearchSessionsMgmtTable } from './table';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { FieldValueOptionType, SearchFilterConfig } from '@elastic/eui';
|
||||
|
@ -14,7 +15,7 @@ import { getStatusText } from '../status';
|
|||
|
||||
export const getStatusFilter: (tableData: UISession[]) => SearchFilterConfig = (tableData) => ({
|
||||
type: 'field_value_selection',
|
||||
name: i18n.translate('xpack.data.mgmt.searchSessions.search.filterStatus', {
|
||||
name: i18n.translate('data.mgmt.searchSessions.search.filterStatus', {
|
||||
defaultMessage: 'Status',
|
||||
}),
|
||||
field: 'status',
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { MockedKeys } from '@kbn/utility-types/jest';
|
||||
|
@ -12,34 +13,29 @@ import { CoreSetup, CoreStart } from '@kbn/core/public';
|
|||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { SessionsClient } from '@kbn/data-plugin/public/search';
|
||||
import { SearchSessionStatus } from '@kbn/data-plugin/common';
|
||||
import { IManagementSectionsPluginsSetup, SessionsConfigSchema } from '../..';
|
||||
import { SearchUsageCollector, SessionsClient } from '../../../..';
|
||||
import { SearchSessionStatus } from '../../../../../../common';
|
||||
import { SearchSessionsMgmtAPI } from '../../lib/api';
|
||||
import { LocaleWrapper } from '../../__mocks__';
|
||||
import { SearchSessionsMgmtTable } from './table';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { managementPluginMock } from '@kbn/management-plugin/public/mocks';
|
||||
import { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { sharePluginMock } from '@kbn/share-plugin/public/mocks';
|
||||
import { SearchSessionsConfigSchema } from '../../../../../../config';
|
||||
import { createSearchUsageCollectorMock } from '../../../../collectors/mocks';
|
||||
|
||||
let mockCoreSetup: MockedKeys<CoreSetup>;
|
||||
let mockCoreStart: CoreStart;
|
||||
let mockShareStart: jest.Mocked<SharePluginStart>;
|
||||
let mockPluginsSetup: IManagementSectionsPluginsSetup;
|
||||
let mockConfig: SessionsConfigSchema;
|
||||
let mockConfig: SearchSessionsConfigSchema;
|
||||
let sessionsClient: SessionsClient;
|
||||
let api: SearchSessionsMgmtAPI;
|
||||
let mockSearchUsageCollector: SearchUsageCollector;
|
||||
|
||||
describe('Background Search Session Management Table', () => {
|
||||
beforeEach(async () => {
|
||||
mockCoreSetup = coreMock.createSetup();
|
||||
mockCoreStart = coreMock.createStart();
|
||||
mockShareStart = sharePluginMock.createStartContract();
|
||||
mockPluginsSetup = {
|
||||
data: dataPluginMock.createSetupContract(),
|
||||
management: managementPluginMock.createSetupContract(),
|
||||
};
|
||||
mockConfig = {
|
||||
defaultExpiration: moment.duration('7d'),
|
||||
management: {
|
||||
|
@ -49,6 +45,7 @@ describe('Background Search Session Management Table', () => {
|
|||
refreshTimeout: moment.duration(10, 'minutes'),
|
||||
},
|
||||
} as any;
|
||||
mockSearchUsageCollector = createSearchUsageCollectorMock();
|
||||
|
||||
sessionsClient = new SessionsClient({ http: mockCoreSetup.http });
|
||||
api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, {
|
||||
|
@ -91,11 +88,11 @@ describe('Background Search Session Management Table', () => {
|
|||
<LocaleWrapper>
|
||||
<SearchSessionsMgmtTable
|
||||
core={mockCoreStart}
|
||||
plugins={mockPluginsSetup}
|
||||
api={api}
|
||||
timezone="UTC"
|
||||
config={mockConfig}
|
||||
kibanaVersion={'8.0.0'}
|
||||
searchUsageCollector={mockSearchUsageCollector}
|
||||
/>
|
||||
</LocaleWrapper>
|
||||
);
|
||||
|
@ -124,11 +121,11 @@ describe('Background Search Session Management Table', () => {
|
|||
<LocaleWrapper>
|
||||
<SearchSessionsMgmtTable
|
||||
core={mockCoreStart}
|
||||
plugins={mockPluginsSetup}
|
||||
api={api}
|
||||
timezone="UTC"
|
||||
config={mockConfig}
|
||||
kibanaVersion={'8.0.0'}
|
||||
searchUsageCollector={mockSearchUsageCollector}
|
||||
/>
|
||||
</LocaleWrapper>
|
||||
);
|
||||
|
@ -168,11 +165,11 @@ describe('Background Search Session Management Table', () => {
|
|||
<LocaleWrapper>
|
||||
<SearchSessionsMgmtTable
|
||||
core={mockCoreStart}
|
||||
plugins={mockPluginsSetup}
|
||||
api={api}
|
||||
timezone="UTC"
|
||||
config={mockConfig}
|
||||
kibanaVersion={'8.0.0'}
|
||||
searchUsageCollector={mockSearchUsageCollector}
|
||||
/>
|
||||
</LocaleWrapper>
|
||||
);
|
||||
|
@ -202,11 +199,11 @@ describe('Background Search Session Management Table', () => {
|
|||
<LocaleWrapper>
|
||||
<SearchSessionsMgmtTable
|
||||
core={mockCoreStart}
|
||||
plugins={mockPluginsSetup}
|
||||
api={api}
|
||||
timezone="UTC"
|
||||
config={mockConfig}
|
||||
kibanaVersion={'8.0.0'}
|
||||
searchUsageCollector={mockSearchUsageCollector}
|
||||
/>
|
||||
</LocaleWrapper>
|
||||
);
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EuiButton, EuiInMemoryTable, EuiSearchBarProps } from '@elastic/eui';
|
||||
|
@ -12,23 +13,24 @@ import moment from 'moment';
|
|||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import useDebounce from 'react-use/lib/useDebounce';
|
||||
import useInterval from 'react-use/lib/useInterval';
|
||||
import { SEARCH_SESSIONS_TABLE_ID } from '@kbn/data-plugin/common';
|
||||
import { TableText } from '..';
|
||||
import { IManagementSectionsPluginsSetup, SessionsConfigSchema } from '../..';
|
||||
import { SEARCH_SESSIONS_TABLE_ID } from '../../../../../../common';
|
||||
import { SearchSessionsMgmtAPI } from '../../lib/api';
|
||||
import { getColumns } from '../../lib/get_columns';
|
||||
import { UISession } from '../../types';
|
||||
import { OnActionComplete } from '../actions';
|
||||
import { getAppFilter } from './app_filter';
|
||||
import { getStatusFilter } from './status_filter';
|
||||
import { SearchUsageCollector } from '../../../../collectors';
|
||||
import { SearchSessionsConfigSchema } from '../../../../../../config';
|
||||
|
||||
interface Props {
|
||||
core: CoreStart;
|
||||
api: SearchSessionsMgmtAPI;
|
||||
timezone: string;
|
||||
config: SessionsConfigSchema;
|
||||
plugins: IManagementSectionsPluginsSetup;
|
||||
config: SearchSessionsConfigSchema;
|
||||
kibanaVersion: string;
|
||||
searchUsageCollector: SearchUsageCollector;
|
||||
}
|
||||
|
||||
export function SearchSessionsMgmtTable({
|
||||
|
@ -36,8 +38,8 @@ export function SearchSessionsMgmtTable({
|
|||
api,
|
||||
timezone,
|
||||
config,
|
||||
plugins,
|
||||
kibanaVersion,
|
||||
searchUsageCollector,
|
||||
...props
|
||||
}: Props) {
|
||||
const [tableData, setTableData] = useState<UISession[]>([]);
|
||||
|
@ -80,8 +82,8 @@ export function SearchSessionsMgmtTable({
|
|||
// initial data load
|
||||
useEffect(() => {
|
||||
doRefresh();
|
||||
plugins.data.search.usageCollector?.trackSessionsListLoaded();
|
||||
}, [doRefresh, plugins]);
|
||||
searchUsageCollector.trackSessionsListLoaded();
|
||||
}, [doRefresh, searchUsageCollector]);
|
||||
|
||||
useInterval(doRefresh, refreshInterval);
|
||||
|
||||
|
@ -104,7 +106,7 @@ export function SearchSessionsMgmtTable({
|
|||
data-test-subj="sessionManagementRefreshBtn"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.data.mgmt.searchSessions.search.tools.refresh"
|
||||
id="data.mgmt.searchSessions.search.tools.refresh"
|
||||
defaultMessage="Refresh"
|
||||
/>
|
||||
</EuiButton>
|
||||
|
@ -121,7 +123,15 @@ export function SearchSessionsMgmtTable({
|
|||
'data-test-subj': `searchSessionsRow`,
|
||||
'data-test-search-session-id': `id-${searchSession.id}`,
|
||||
})}
|
||||
columns={getColumns(core, plugins, api, config, timezone, onActionComplete, kibanaVersion)}
|
||||
columns={getColumns(
|
||||
core,
|
||||
api,
|
||||
config,
|
||||
timezone,
|
||||
onActionComplete,
|
||||
kibanaVersion,
|
||||
searchUsageCollector
|
||||
)}
|
||||
items={tableData}
|
||||
pagination={pagination}
|
||||
search={search}
|
Before Width: | Height: | Size: 368 B After Width: | Height: | Size: 368 B |
|
@ -1,34 +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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { CoreStart, HttpStart, I18nStart, IUiSettingsClient } from '@kbn/core/public';
|
||||
import { CoreSetup } from '@kbn/core/public';
|
||||
import type { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { ManagementSetup } from '@kbn/management-plugin/public';
|
||||
import type { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { SEARCH_SESSIONS_MANAGEMENT_ID } from '@kbn/data-plugin/public';
|
||||
import type { ConfigSchema } from '../../../config';
|
||||
import type { DataEnhancedStartDependencies } from '../../plugin';
|
||||
import type { ISessionsClient, SearchUsageCollector } from '../../..';
|
||||
import { SEARCH_SESSIONS_MANAGEMENT_ID } from '../constants';
|
||||
import type { SearchSessionsMgmtAPI } from './lib/api';
|
||||
import type { AsyncSearchIntroDocumentation } from './lib/documentation';
|
||||
import { SearchSessionsConfigSchema } from '../../../../config';
|
||||
|
||||
export interface IManagementSectionsPluginsSetup {
|
||||
data: DataPublicPluginSetup;
|
||||
management: ManagementSetup;
|
||||
searchUsageCollector: SearchUsageCollector;
|
||||
sessionsClient: ISessionsClient;
|
||||
}
|
||||
|
||||
export interface IManagementSectionsPluginsStart {
|
||||
data: DataPublicPluginStart;
|
||||
share: SharePluginStart;
|
||||
}
|
||||
|
||||
export interface AppDependencies {
|
||||
plugins: IManagementSectionsPluginsSetup;
|
||||
share: SharePluginStart;
|
||||
uiSettings: IUiSettingsClient;
|
||||
documentation: AsyncSearchIntroDocumentation;
|
||||
|
@ -36,33 +35,32 @@ export interface AppDependencies {
|
|||
api: SearchSessionsMgmtAPI;
|
||||
http: HttpStart;
|
||||
i18n: I18nStart;
|
||||
config: SessionsConfigSchema;
|
||||
config: SearchSessionsConfigSchema;
|
||||
kibanaVersion: string;
|
||||
searchUsageCollector: SearchUsageCollector;
|
||||
}
|
||||
|
||||
export const APP = {
|
||||
id: SEARCH_SESSIONS_MANAGEMENT_ID,
|
||||
getI18nName: (): string =>
|
||||
i18n.translate('xpack.data.mgmt.searchSessions.appTitle', {
|
||||
i18n.translate('data.mgmt.searchSessions.appTitle', {
|
||||
defaultMessage: 'Search Sessions',
|
||||
}),
|
||||
};
|
||||
|
||||
export type SessionsConfigSchema = ConfigSchema['search']['sessions'];
|
||||
|
||||
export function registerSearchSessionsMgmt(
|
||||
coreSetup: CoreSetup<DataEnhancedStartDependencies>,
|
||||
config: SessionsConfigSchema,
|
||||
kibanaVersion: string,
|
||||
services: IManagementSectionsPluginsSetup
|
||||
coreSetup: CoreSetup<IManagementSectionsPluginsStart>,
|
||||
deps: IManagementSectionsPluginsSetup,
|
||||
config: SearchSessionsConfigSchema,
|
||||
kibanaVersion: string
|
||||
) {
|
||||
services.management.sections.section.kibana.registerApp({
|
||||
deps.management.sections.section.kibana.registerApp({
|
||||
id: APP.id,
|
||||
title: APP.getI18nName(),
|
||||
order: 1.75,
|
||||
mount: async (params) => {
|
||||
const { SearchSessionsMgmtApp: MgmtApp } = await import('./application');
|
||||
const mgmtApp = new MgmtApp(coreSetup, config, kibanaVersion, params, services);
|
||||
const mgmtApp = new MgmtApp(coreSetup, deps, config, kibanaVersion, params);
|
||||
return mgmtApp.mountManagementSection();
|
||||
},
|
||||
});
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { MockedKeys } from '@kbn/utility-types/jest';
|
||||
|
@ -11,17 +12,17 @@ import moment from 'moment';
|
|||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import type { SavedObjectsFindResponse } from '@kbn/core/server';
|
||||
import { SessionsClient } from '@kbn/data-plugin/public/search';
|
||||
import type { SessionsConfigSchema } from '..';
|
||||
import { SearchSessionStatus } from '@kbn/data-plugin/common';
|
||||
import { SessionsClient } from '../../..';
|
||||
import { SearchSessionStatus } from '../../../../../common';
|
||||
import { sharePluginMock } from '@kbn/share-plugin/public/mocks';
|
||||
import { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { SearchSessionsMgmtAPI } from './api';
|
||||
import { SearchSessionsConfigSchema } from '../../../../../config';
|
||||
|
||||
let mockCoreSetup: MockedKeys<CoreSetup>;
|
||||
let mockCoreStart: MockedKeys<CoreStart>;
|
||||
let mockShareStart: jest.Mocked<SharePluginStart>;
|
||||
let mockConfig: SessionsConfigSchema;
|
||||
let mockConfig: SearchSessionsConfigSchema;
|
||||
let sessionsClient: SessionsClient;
|
||||
|
||||
describe('Search Sessions Management API', () => {
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -12,15 +13,16 @@ import { from, race, timer } from 'rxjs';
|
|||
import { mapTo, tap } from 'rxjs/operators';
|
||||
import type { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { SerializableRecord } from '@kbn/utility-types';
|
||||
import { ISessionsClient, SearchUsageCollector } from '@kbn/data-plugin/public';
|
||||
import { SearchSessionStatus } from '@kbn/data-plugin/common';
|
||||
import { ACTION } from '../components/actions';
|
||||
import {
|
||||
PersistedSearchSessionSavedObjectAttributes,
|
||||
UISearchSessionState,
|
||||
UISession,
|
||||
} from '../types';
|
||||
import { SessionsConfigSchema } from '..';
|
||||
import { ISessionsClient } from '../../sessions_client';
|
||||
import { SearchUsageCollector } from '../../../collectors';
|
||||
import { SearchSessionStatus } from '../../../../../common';
|
||||
import { SearchSessionsConfigSchema } from '../../../../../config';
|
||||
|
||||
type LocatorsStart = SharePluginStart['url']['locators'];
|
||||
|
||||
|
@ -73,7 +75,7 @@ function getUrlFromState(locators: LocatorsStart, locatorId: string, state: Seri
|
|||
|
||||
// Helper: factory for a function to map server objects to UI objects
|
||||
const mapToUISession =
|
||||
(locators: LocatorsStart, config: SessionsConfigSchema) =>
|
||||
(locators: LocatorsStart, config: SearchSessionsConfigSchema) =>
|
||||
async (
|
||||
savedObject: SavedObject<PersistedSearchSessionSavedObjectAttributes>
|
||||
): Promise<UISession> => {
|
||||
|
@ -125,7 +127,7 @@ interface SearchSessionManagementDeps {
|
|||
export class SearchSessionsMgmtAPI {
|
||||
constructor(
|
||||
private sessionsClient: ISessionsClient,
|
||||
private config: SessionsConfigSchema,
|
||||
private config: SearchSessionsConfigSchema,
|
||||
private deps: SearchSessionManagementDeps
|
||||
) {}
|
||||
|
||||
|
@ -147,7 +149,7 @@ export class SearchSessionsMgmtAPI {
|
|||
const timeout$ = timer(refreshTimeout.asMilliseconds()).pipe(
|
||||
tap(() => {
|
||||
this.deps.notifications.toasts.addDanger(
|
||||
i18n.translate('xpack.data.mgmt.searchSessions.api.fetchTimeout', {
|
||||
i18n.translate('data.mgmt.searchSessions.api.fetchTimeout', {
|
||||
defaultMessage: 'Fetching the Search Session info timed out after {timeout} seconds',
|
||||
values: { timeout: refreshTimeout.asSeconds() },
|
||||
})
|
||||
|
@ -169,7 +171,7 @@ export class SearchSessionsMgmtAPI {
|
|||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
this.deps.notifications.toasts.addError(err, {
|
||||
title: i18n.translate('xpack.data.mgmt.searchSessions.api.fetchError', {
|
||||
title: i18n.translate('data.mgmt.searchSessions.api.fetchError', {
|
||||
defaultMessage: 'Failed to refresh the page!',
|
||||
}),
|
||||
});
|
||||
|
@ -194,13 +196,13 @@ export class SearchSessionsMgmtAPI {
|
|||
await this.sessionsClient.delete(id);
|
||||
|
||||
this.deps.notifications.toasts.addSuccess({
|
||||
title: i18n.translate('xpack.data.mgmt.searchSessions.api.deleted', {
|
||||
title: i18n.translate('data.mgmt.searchSessions.api.deleted', {
|
||||
defaultMessage: 'The search session was deleted.',
|
||||
}),
|
||||
});
|
||||
} catch (err) {
|
||||
this.deps.notifications.toasts.addError(err, {
|
||||
title: i18n.translate('xpack.data.mgmt.searchSessions.api.deletedError', {
|
||||
title: i18n.translate('data.mgmt.searchSessions.api.deletedError', {
|
||||
defaultMessage: 'Failed to delete the search session!',
|
||||
}),
|
||||
});
|
||||
|
@ -214,13 +216,13 @@ export class SearchSessionsMgmtAPI {
|
|||
await this.sessionsClient.extend(id, expires);
|
||||
|
||||
this.deps.notifications.toasts.addSuccess({
|
||||
title: i18n.translate('xpack.data.mgmt.searchSessions.api.extended', {
|
||||
title: i18n.translate('data.mgmt.searchSessions.api.extended', {
|
||||
defaultMessage: 'The search session was extended.',
|
||||
}),
|
||||
});
|
||||
} catch (err) {
|
||||
this.deps.notifications.toasts.addError(err, {
|
||||
title: i18n.translate('xpack.data.mgmt.searchSessions.api.extendError', {
|
||||
title: i18n.translate('data.mgmt.searchSessions.api.extendError', {
|
||||
defaultMessage: 'Failed to extend the search session!',
|
||||
}),
|
||||
});
|
||||
|
@ -233,13 +235,13 @@ export class SearchSessionsMgmtAPI {
|
|||
await this.sessionsClient.rename(id, newName);
|
||||
|
||||
this.deps.notifications.toasts.addSuccess({
|
||||
title: i18n.translate('xpack.data.mgmt.searchSessions.api.rename', {
|
||||
title: i18n.translate('data.mgmt.searchSessions.api.rename', {
|
||||
defaultMessage: 'The search session was renamed',
|
||||
}),
|
||||
});
|
||||
} catch (err) {
|
||||
this.deps.notifications.toasts.addError(err, {
|
||||
title: i18n.translate('xpack.data.mgmt.searchSessions.api.renameError', {
|
||||
title: i18n.translate('data.mgmt.searchSessions.api.renameError', {
|
||||
defaultMessage: 'Failed to rename the search session',
|
||||
}),
|
||||
});
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import moment from 'moment';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { DocLinksStart } from '@kbn/core/public';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EuiTableFieldDataColumnType } from '@elastic/eui';
|
||||
|
@ -12,23 +13,22 @@ import { CoreSetup, CoreStart } from '@kbn/core/public';
|
|||
import moment from 'moment';
|
||||
import { ReactElement } from 'react';
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { SessionsClient } from '@kbn/data-plugin/public/search';
|
||||
import { IManagementSectionsPluginsSetup, SessionsConfigSchema } from '..';
|
||||
import { SearchSessionStatus } from '@kbn/data-plugin/common';
|
||||
import { SearchUsageCollector, SessionsClient } from '../../..';
|
||||
import { SearchSessionStatus } from '../../../../../common';
|
||||
import { OnActionComplete } from '../components';
|
||||
import { UISession } from '../types';
|
||||
import { SearchSessionsMgmtAPI } from './api';
|
||||
import { getColumns } from './get_columns';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { managementPluginMock } from '@kbn/management-plugin/public/mocks';
|
||||
import { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { sharePluginMock } from '@kbn/share-plugin/public/mocks';
|
||||
import { SearchSessionsConfigSchema } from '../../../../../config';
|
||||
import { createSearchUsageCollectorMock } from '../../../collectors/mocks';
|
||||
|
||||
let mockCoreSetup: MockedKeys<CoreSetup>;
|
||||
let mockCoreStart: CoreStart;
|
||||
let mockShareStart: jest.Mocked<SharePluginStart>;
|
||||
let mockPluginsSetup: IManagementSectionsPluginsSetup;
|
||||
let mockConfig: SessionsConfigSchema;
|
||||
let mockSearchUsageCollector: SearchUsageCollector;
|
||||
let mockConfig: SearchSessionsConfigSchema;
|
||||
let api: SearchSessionsMgmtAPI;
|
||||
let sessionsClient: SessionsClient;
|
||||
let handleAction: OnActionComplete;
|
||||
|
@ -41,10 +41,6 @@ describe('Search Sessions Management table column factory', () => {
|
|||
mockCoreSetup = coreMock.createSetup();
|
||||
mockCoreStart = coreMock.createStart();
|
||||
mockShareStart = sharePluginMock.createStartContract();
|
||||
mockPluginsSetup = {
|
||||
data: dataPluginMock.createSetupContract(),
|
||||
management: managementPluginMock.createSetupContract(),
|
||||
};
|
||||
mockConfig = {
|
||||
defaultExpiration: moment.duration('7d'),
|
||||
management: {
|
||||
|
@ -55,6 +51,7 @@ describe('Search Sessions Management table column factory', () => {
|
|||
},
|
||||
} as any;
|
||||
sessionsClient = new SessionsClient({ http: mockCoreSetup.http });
|
||||
mockSearchUsageCollector = createSearchUsageCollectorMock();
|
||||
|
||||
api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, {
|
||||
locators: mockShareStart.url.locators,
|
||||
|
@ -86,12 +83,12 @@ describe('Search Sessions Management table column factory', () => {
|
|||
test('returns columns', () => {
|
||||
const columns = getColumns(
|
||||
mockCoreStart,
|
||||
mockPluginsSetup,
|
||||
api,
|
||||
mockConfig,
|
||||
tz,
|
||||
handleAction,
|
||||
'7.14.0'
|
||||
'7.14.0',
|
||||
mockSearchUsageCollector
|
||||
);
|
||||
expect(columns).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
@ -152,12 +149,12 @@ describe('Search Sessions Management table column factory', () => {
|
|||
test('rendering', () => {
|
||||
const [, nameColumn] = getColumns(
|
||||
mockCoreStart,
|
||||
mockPluginsSetup,
|
||||
api,
|
||||
mockConfig,
|
||||
tz,
|
||||
handleAction,
|
||||
'7.14.0'
|
||||
'7.14.0',
|
||||
mockSearchUsageCollector
|
||||
) as Array<EuiTableFieldDataColumnType<UISession>>;
|
||||
|
||||
const name = mount(nameColumn.render!(mockSession.name, mockSession) as ReactElement);
|
||||
|
@ -172,12 +169,12 @@ describe('Search Sessions Management table column factory', () => {
|
|||
beforeEach(() => {
|
||||
const [, nameColumn] = getColumns(
|
||||
mockCoreStart,
|
||||
mockPluginsSetup,
|
||||
api,
|
||||
mockConfig,
|
||||
tz,
|
||||
handleAction,
|
||||
currentKibanaVersion
|
||||
currentKibanaVersion,
|
||||
mockSearchUsageCollector
|
||||
) as Array<EuiTableFieldDataColumnType<UISession>>;
|
||||
|
||||
hasRenderedVersionWarning = (partialSession: Partial<UISession>): boolean => {
|
||||
|
@ -235,12 +232,12 @@ describe('Search Sessions Management table column factory', () => {
|
|||
test('renders', () => {
|
||||
const [, , numOfSearches] = getColumns(
|
||||
mockCoreStart,
|
||||
mockPluginsSetup,
|
||||
api,
|
||||
mockConfig,
|
||||
tz,
|
||||
handleAction,
|
||||
'7.14.0'
|
||||
'7.14.0',
|
||||
mockSearchUsageCollector
|
||||
) as Array<EuiTableFieldDataColumnType<UISession>>;
|
||||
|
||||
const numOfSearchesLine = mount(
|
||||
|
@ -255,12 +252,12 @@ describe('Search Sessions Management table column factory', () => {
|
|||
test('render in_progress', () => {
|
||||
const [, , , status] = getColumns(
|
||||
mockCoreStart,
|
||||
mockPluginsSetup,
|
||||
api,
|
||||
mockConfig,
|
||||
tz,
|
||||
handleAction,
|
||||
'7.14.0'
|
||||
'7.14.0',
|
||||
mockSearchUsageCollector
|
||||
) as Array<EuiTableFieldDataColumnType<UISession>>;
|
||||
|
||||
const statusLine = mount(status.render!(mockSession.status, mockSession) as ReactElement);
|
||||
|
@ -272,12 +269,12 @@ describe('Search Sessions Management table column factory', () => {
|
|||
test('error handling', () => {
|
||||
const [, , , status] = getColumns(
|
||||
mockCoreStart,
|
||||
mockPluginsSetup,
|
||||
api,
|
||||
mockConfig,
|
||||
tz,
|
||||
handleAction,
|
||||
'7.14.0'
|
||||
'7.14.0',
|
||||
mockSearchUsageCollector
|
||||
) as Array<EuiTableFieldDataColumnType<UISession>>;
|
||||
|
||||
mockSession.status = 'INVALID' as SearchSessionStatus;
|
||||
|
@ -296,12 +293,12 @@ describe('Search Sessions Management table column factory', () => {
|
|||
|
||||
const [, , , , createdDateCol] = getColumns(
|
||||
mockCoreStart,
|
||||
mockPluginsSetup,
|
||||
api,
|
||||
mockConfig,
|
||||
tz,
|
||||
handleAction,
|
||||
'7.14.0'
|
||||
'7.14.0',
|
||||
mockSearchUsageCollector
|
||||
) as Array<EuiTableFieldDataColumnType<UISession>>;
|
||||
|
||||
const date = mount(createdDateCol.render!(mockSession.created, mockSession) as ReactElement);
|
||||
|
@ -314,12 +311,12 @@ describe('Search Sessions Management table column factory', () => {
|
|||
|
||||
const [, , , , createdDateCol] = getColumns(
|
||||
mockCoreStart,
|
||||
mockPluginsSetup,
|
||||
api,
|
||||
mockConfig,
|
||||
tz,
|
||||
handleAction,
|
||||
'7.14.0'
|
||||
'7.14.0',
|
||||
mockSearchUsageCollector
|
||||
) as Array<EuiTableFieldDataColumnType<UISession>>;
|
||||
|
||||
const date = mount(createdDateCol.render!(mockSession.created, mockSession) as ReactElement);
|
||||
|
@ -330,12 +327,12 @@ describe('Search Sessions Management table column factory', () => {
|
|||
test('error handling', () => {
|
||||
const [, , , , createdDateCol] = getColumns(
|
||||
mockCoreStart,
|
||||
mockPluginsSetup,
|
||||
api,
|
||||
mockConfig,
|
||||
tz,
|
||||
handleAction,
|
||||
'7.14.0'
|
||||
'7.14.0',
|
||||
mockSearchUsageCollector
|
||||
) as Array<EuiTableFieldDataColumnType<UISession>>;
|
||||
|
||||
mockSession.created = 'INVALID';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
|
@ -21,15 +22,15 @@ import { CoreStart } from '@kbn/core/public';
|
|||
import { capitalize } from 'lodash';
|
||||
import React from 'react';
|
||||
import { RedirectAppLinks } from '@kbn/kibana-react-plugin/public';
|
||||
import { SearchSessionStatus } from '@kbn/data-plugin/common';
|
||||
import { IManagementSectionsPluginsSetup, SessionsConfigSchema } from '..';
|
||||
import { TableText } from '../components';
|
||||
import { OnActionComplete, PopoverActionsMenu } from '../components';
|
||||
import { SearchSessionStatus } from '../../../../../common';
|
||||
import { OnActionComplete, PopoverActionsMenu, TableText } from '../components';
|
||||
import { StatusIndicator } from '../components/status';
|
||||
import { dateString } from './date_string';
|
||||
import { SearchSessionsMgmtAPI } from './api';
|
||||
import { getExpirationStatus } from './get_expiration_status';
|
||||
import { UISession } from '../types';
|
||||
import { SearchUsageCollector } from '../../../collectors';
|
||||
import { SearchSessionsConfigSchema } from '../../../../../config';
|
||||
|
||||
// Helper function: translate an app string to EuiIcon-friendly string
|
||||
const appToIcon = (app: string) => {
|
||||
|
@ -46,7 +47,7 @@ const appToIcon = (app: string) => {
|
|||
// Helper function: translate an app id to user friendly string
|
||||
const appToTooltip = (appId: string | undefined) => {
|
||||
if (appId === 'ml') {
|
||||
return i18n.translate('xpack.data.mgmt.searchSessions.table.mlAppName', {
|
||||
return i18n.translate('data.mgmt.searchSessions.table.mlAppName', {
|
||||
defaultMessage: 'Machine Learning',
|
||||
});
|
||||
}
|
||||
|
@ -58,19 +59,19 @@ function isSessionRestorable(status: SearchSessionStatus) {
|
|||
|
||||
export const getColumns = (
|
||||
core: CoreStart,
|
||||
plugins: IManagementSectionsPluginsSetup,
|
||||
api: SearchSessionsMgmtAPI,
|
||||
config: SessionsConfigSchema,
|
||||
config: SearchSessionsConfigSchema,
|
||||
timezone: string,
|
||||
onActionComplete: OnActionComplete,
|
||||
kibanaVersion: string
|
||||
kibanaVersion: string,
|
||||
searchUsageCollector: SearchUsageCollector
|
||||
): Array<EuiBasicTableColumn<UISession>> => {
|
||||
// Use a literal array of table column definitions to detail a UISession object
|
||||
return [
|
||||
// App
|
||||
{
|
||||
field: 'appId',
|
||||
name: i18n.translate('xpack.data.mgmt.searchSessions.table.headerType', {
|
||||
name: i18n.translate('data.mgmt.searchSessions.table.headerType', {
|
||||
defaultMessage: 'App',
|
||||
}),
|
||||
sortable: true,
|
||||
|
@ -91,7 +92,7 @@ export const getColumns = (
|
|||
// Name, links to app and displays the search session data
|
||||
{
|
||||
field: 'name',
|
||||
name: i18n.translate('xpack.data.mgmt.searchSessions.table.headerName', {
|
||||
name: i18n.translate('data.mgmt.searchSessions.table.headerName', {
|
||||
defaultMessage: 'Name',
|
||||
}),
|
||||
sortable: true,
|
||||
|
@ -100,8 +101,8 @@ export const getColumns = (
|
|||
const isRestorable = isSessionRestorable(status);
|
||||
const href = isRestorable ? restoreUrl : reloadUrl;
|
||||
const trackAction = isRestorable
|
||||
? plugins.data.search.usageCollector?.trackSessionViewRestored
|
||||
: plugins.data.search.usageCollector?.trackSessionReloaded;
|
||||
? searchUsageCollector.trackSessionViewRestored
|
||||
: searchUsageCollector.trackSessionReloaded;
|
||||
const notRestorableWarning = isRestorable ? null : (
|
||||
<>
|
||||
{' '}
|
||||
|
@ -109,7 +110,7 @@ export const getColumns = (
|
|||
type="alert"
|
||||
content={
|
||||
<FormattedMessage
|
||||
id="xpack.data.mgmt.searchSessions.table.notRestorableWarning"
|
||||
id="data.mgmt.searchSessions.table.notRestorableWarning"
|
||||
defaultMessage="The search session will be executed again. You can then save it for future use."
|
||||
/>
|
||||
}
|
||||
|
@ -130,7 +131,7 @@ export const getColumns = (
|
|||
iconProps={{ 'data-test-subj': 'versionIncompatibleWarningTestSubj' }}
|
||||
content={
|
||||
<FormattedMessage
|
||||
id="xpack.data.mgmt.searchSessions.table.versionIncompatibleWarning"
|
||||
id="data.mgmt.searchSessions.table.versionIncompatibleWarning"
|
||||
defaultMessage="This search session was created in a Kibana instance running a different version. It may not restore correctly."
|
||||
/>
|
||||
}
|
||||
|
@ -160,7 +161,7 @@ export const getColumns = (
|
|||
// # Searches
|
||||
{
|
||||
field: 'numSearches',
|
||||
name: i18n.translate('xpack.data.mgmt.searchSessions.table.numSearches', {
|
||||
name: i18n.translate('data.mgmt.searchSessions.table.numSearches', {
|
||||
defaultMessage: '# Searches',
|
||||
}),
|
||||
sortable: true,
|
||||
|
@ -174,7 +175,7 @@ export const getColumns = (
|
|||
// Session status
|
||||
{
|
||||
field: 'status',
|
||||
name: i18n.translate('xpack.data.mgmt.searchSessions.table.headerStatus', {
|
||||
name: i18n.translate('data.mgmt.searchSessions.table.headerStatus', {
|
||||
defaultMessage: 'Status',
|
||||
}),
|
||||
sortable: true,
|
||||
|
@ -186,7 +187,7 @@ export const getColumns = (
|
|||
// Started date
|
||||
{
|
||||
field: 'created',
|
||||
name: i18n.translate('xpack.data.mgmt.searchSessions.table.headerStarted', {
|
||||
name: i18n.translate('data.mgmt.searchSessions.table.headerStarted', {
|
||||
defaultMessage: 'Created',
|
||||
}),
|
||||
sortable: true,
|
||||
|
@ -209,7 +210,7 @@ export const getColumns = (
|
|||
// Expiration date
|
||||
{
|
||||
field: 'expires',
|
||||
name: i18n.translate('xpack.data.mgmt.searchSessions.table.headerExpiration', {
|
||||
name: i18n.translate('data.mgmt.searchSessions.table.headerExpiration', {
|
||||
defaultMessage: 'Expiration',
|
||||
}),
|
||||
sortable: true,
|
|
@ -1,15 +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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import moment from 'moment';
|
||||
import { SessionsConfigSchema } from '..';
|
||||
import { SearchSessionsConfigSchema } from '../../../../../config';
|
||||
|
||||
export const getExpirationStatus = (config: SessionsConfigSchema, expires: string | null) => {
|
||||
export const getExpirationStatus = (config: SearchSessionsConfigSchema, expires: string | null) => {
|
||||
const tNow = moment.utc().valueOf();
|
||||
const tFuture = moment.utc(expires).valueOf();
|
||||
|
||||
|
@ -19,27 +20,27 @@ export const getExpirationStatus = (config: SessionsConfigSchema, expires: strin
|
|||
const expiresInDays = Math.floor(durationToExpire.asDays());
|
||||
const sufficientDays = Math.ceil(moment.duration(config.management.expiresSoonWarning).asDays());
|
||||
|
||||
let toolTipContent = i18n.translate('xpack.data.mgmt.searchSessions.status.expiresSoonInDays', {
|
||||
let toolTipContent = i18n.translate('data.mgmt.searchSessions.status.expiresSoonInDays', {
|
||||
defaultMessage: 'Expires in {numDays} days',
|
||||
values: { numDays: expiresInDays },
|
||||
});
|
||||
let statusContent = i18n.translate(
|
||||
'xpack.data.mgmt.searchSessions.status.expiresSoonInDaysTooltip',
|
||||
{ defaultMessage: '{numDays} days', values: { numDays: expiresInDays } }
|
||||
);
|
||||
let statusContent = i18n.translate('data.mgmt.searchSessions.status.expiresSoonInDaysTooltip', {
|
||||
defaultMessage: '{numDays} days',
|
||||
values: { numDays: expiresInDays },
|
||||
});
|
||||
|
||||
if (expiresInDays === 0) {
|
||||
// switch to show expires in hours
|
||||
const expiresInHours = Math.floor(durationToExpire.asHours());
|
||||
|
||||
toolTipContent = i18n.translate('xpack.data.mgmt.searchSessions.status.expiresSoonInHours', {
|
||||
toolTipContent = i18n.translate('data.mgmt.searchSessions.status.expiresSoonInHours', {
|
||||
defaultMessage: 'This session expires in {numHours} hours',
|
||||
values: { numHours: expiresInHours },
|
||||
});
|
||||
statusContent = i18n.translate(
|
||||
'xpack.data.mgmt.searchSessions.status.expiresSoonInHoursTooltip',
|
||||
{ defaultMessage: '{numHours} hours', values: { numHours: expiresInHours } }
|
||||
);
|
||||
statusContent = i18n.translate('data.mgmt.searchSessions.status.expiresSoonInHoursTooltip', {
|
||||
defaultMessage: '{numHours} hours',
|
||||
values: { numHours: expiresInHours },
|
||||
});
|
||||
}
|
||||
|
||||
if (durationToExpire.valueOf() > 0 && expiresInDays <= sufficientDays) {
|
|
@ -1,11 +1,12 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SearchSessionSavedObjectAttributes, SearchSessionStatus } from '@kbn/data-plugin/common';
|
||||
import { SearchSessionSavedObjectAttributes, SearchSessionStatus } from '../../../../common';
|
||||
import { ACTION } from './components/actions';
|
||||
|
||||
export const DATE_STRING_FORMAT = 'D MMM, YYYY, HH:mm:ss';
|
|
@ -15,6 +15,9 @@ import { UiActionsSetup, UiActionsStart } from '@kbn/ui-actions-plugin/public';
|
|||
import { FieldFormatsSetup, FieldFormatsStart } from '@kbn/field-formats-plugin/public';
|
||||
import { UsageCollectionSetup, UsageCollectionStart } from '@kbn/usage-collection-plugin/public';
|
||||
import { Setup as InspectorSetup } from '@kbn/inspector-plugin/public';
|
||||
import { ScreenshotModePluginStart } from '@kbn/screenshot-mode-plugin/public';
|
||||
import { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { ManagementSetup } from '@kbn/management-plugin/public';
|
||||
import { DatatableUtilitiesService } from '../common';
|
||||
import { createFiltersFromRangeSelectAction, createFiltersFromValueClickAction } from './actions';
|
||||
import type { ISearchSetup, ISearchStart } from './search';
|
||||
|
@ -29,12 +32,15 @@ export interface DataSetupDependencies {
|
|||
inspector: InspectorSetup;
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
fieldFormats: FieldFormatsSetup;
|
||||
management: ManagementSetup;
|
||||
}
|
||||
|
||||
export interface DataStartDependencies {
|
||||
uiActions: UiActionsStart;
|
||||
fieldFormats: FieldFormatsStart;
|
||||
dataViews: DataViewsPublicPluginStart;
|
||||
screenshotMode: ScreenshotModePluginStart;
|
||||
share: SharePluginStart;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,12 +11,12 @@ import { cloneDeep } from 'lodash';
|
|||
import { applyDeprecations, configDeprecationFactory } from '@kbn/config';
|
||||
import { configDeprecationsMock } from '@kbn/core/server/mocks';
|
||||
|
||||
import { autocompleteConfigDeprecationProvider } from './config_deprecations';
|
||||
import { configDeprecationProvider } from './config_deprecations';
|
||||
|
||||
const deprecationContext = configDeprecationsMock.createContext();
|
||||
|
||||
const applyConfigDeprecations = (settings: Record<string, any> = {}) => {
|
||||
const deprecations = autocompleteConfigDeprecationProvider(configDeprecationFactory);
|
||||
const deprecations = configDeprecationProvider(configDeprecationFactory);
|
||||
const deprecationMessages: string[] = [];
|
||||
const migrated = applyDeprecations(
|
||||
settings,
|
||||
|
@ -37,40 +37,30 @@ const applyConfigDeprecations = (settings: Record<string, any> = {}) => {
|
|||
|
||||
describe('Config Deprecations', () => {
|
||||
it('does not report deprecations for default configuration', () => {
|
||||
const defaultConfig = { data: { autocomplete: { valueSuggestions: {} } } };
|
||||
const defaultConfig = { data: { search: { sessions: {} } } };
|
||||
const { messages, migrated } = applyConfigDeprecations(cloneDeep(defaultConfig));
|
||||
expect(migrated).toEqual(defaultConfig);
|
||||
expect(messages).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('renames kibana.autocompleteTerminateAfter to data.autocomplete.valueSuggestions.terminateAfter', () => {
|
||||
it('renames xpack.data_enhanced.search.sessions.* to data.search.sessions.*', () => {
|
||||
const config = {
|
||||
kibana: {
|
||||
autocompleteTerminateAfter: 123,
|
||||
xpack: {
|
||||
data_enhanced: {
|
||||
search: {
|
||||
sessions: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const { messages, migrated } = applyConfigDeprecations(cloneDeep(config));
|
||||
expect(migrated.kibana?.autocompleteTerminateAfter).not.toBeDefined();
|
||||
expect(migrated.data.autocomplete.valueSuggestions.terminateAfter).toEqual(123);
|
||||
expect(migrated.xpack?.data_enhanced).not.toBeDefined();
|
||||
expect(migrated.data.search.sessions.enabled).toEqual(false);
|
||||
expect(messages).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"Setting \\"kibana.autocompleteTerminateAfter\\" has been replaced by \\"data.autocomplete.valueSuggestions.terminateAfter\\"",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('renames kibana.autocompleteTimeout to data.autocomplete.valueSuggestions.timeout', () => {
|
||||
const config = {
|
||||
kibana: {
|
||||
autocompleteTimeout: 123,
|
||||
},
|
||||
};
|
||||
const { messages, migrated } = applyConfigDeprecations(cloneDeep(config));
|
||||
expect(migrated.kibana?.autocompleteTimeout).not.toBeDefined();
|
||||
expect(migrated.data.autocomplete.valueSuggestions.timeout).toEqual(123);
|
||||
expect(messages).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"Setting \\"kibana.autocompleteTimeout\\" has been replaced by \\"data.autocomplete.valueSuggestions.timeout\\"",
|
||||
"Setting \\"xpack.data_enhanced.search.sessions\\" has been replaced by \\"data.search.sessions\\"",
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
|
|
@ -8,15 +8,8 @@
|
|||
|
||||
import type { ConfigDeprecationProvider } from '@kbn/core/server';
|
||||
|
||||
export const autocompleteConfigDeprecationProvider: ConfigDeprecationProvider = ({
|
||||
renameFromRoot,
|
||||
}) => [
|
||||
renameFromRoot(
|
||||
'kibana.autocompleteTerminateAfter',
|
||||
'data.autocomplete.valueSuggestions.terminateAfter',
|
||||
{ level: 'warning' }
|
||||
),
|
||||
renameFromRoot('kibana.autocompleteTimeout', 'data.autocomplete.valueSuggestions.timeout', {
|
||||
export const configDeprecationProvider: ConfigDeprecationProvider = ({ renameFromRoot }) => [
|
||||
renameFromRoot('xpack.data_enhanced.search.sessions', 'data.search.sessions', {
|
||||
level: 'warning',
|
||||
}),
|
||||
];
|
||||
|
|
|
@ -70,6 +70,7 @@ import {
|
|||
// tabify
|
||||
calcAutoIntervalLessThan,
|
||||
} from '../common';
|
||||
import { configDeprecationProvider } from './config_deprecations';
|
||||
|
||||
export type {
|
||||
ParsedInterval,
|
||||
|
@ -122,6 +123,7 @@ export type { DataPluginSetup as PluginSetup, DataPluginStart as PluginStart };
|
|||
export { DataServerPlugin as Plugin };
|
||||
|
||||
export const config: PluginConfigDescriptor<ConfigSchema> = {
|
||||
deprecations: configDeprecationProvider,
|
||||
exposeToBrowser: {
|
||||
search: true,
|
||||
},
|
||||
|
|
|
@ -12,9 +12,14 @@ import { BfetchServerSetup } from '@kbn/bfetch-plugin/server';
|
|||
import { PluginStart as DataViewsServerPluginStart } from '@kbn/data-views-plugin/server';
|
||||
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
|
||||
import { FieldFormatsSetup, FieldFormatsStart } from '@kbn/field-formats-plugin/server';
|
||||
import type {
|
||||
TaskManagerSetupContract,
|
||||
TaskManagerStartContract,
|
||||
} from '@kbn/task-manager-plugin/server';
|
||||
import type { SecurityPluginSetup } from '@kbn/security-plugin/server';
|
||||
import { ConfigSchema } from '../config';
|
||||
import type { ISearchSetup, ISearchStart } from './search';
|
||||
import { DatatableUtilitiesService } from './datatable_utilities';
|
||||
import type { ISearchSetup, ISearchStart, SearchEnhancements } from './search';
|
||||
import { SearchService } from './search/search_service';
|
||||
import { QueryService } from './query/query_service';
|
||||
import { ScriptsService } from './scripts';
|
||||
|
@ -22,10 +27,6 @@ import { KqlTelemetryService } from './kql_telemetry';
|
|||
import { getUiSettings } from './ui_settings';
|
||||
import { QuerySetup } from './query';
|
||||
|
||||
interface DataEnhancements {
|
||||
search: SearchEnhancements;
|
||||
}
|
||||
|
||||
export interface DataPluginSetup {
|
||||
search: ISearchSetup;
|
||||
query: QuerySetup;
|
||||
|
@ -33,10 +34,6 @@ export interface DataPluginSetup {
|
|||
* @deprecated - use "fieldFormats" plugin directly instead
|
||||
*/
|
||||
fieldFormats: FieldFormatsSetup;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
__enhance: (enhancements: DataEnhancements) => void;
|
||||
}
|
||||
|
||||
export interface DataPluginStart {
|
||||
|
@ -58,12 +55,15 @@ export interface DataPluginSetupDependencies {
|
|||
expressions: ExpressionsServerSetup;
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
fieldFormats: FieldFormatsSetup;
|
||||
taskManager?: TaskManagerSetupContract;
|
||||
security?: SecurityPluginSetup;
|
||||
}
|
||||
|
||||
export interface DataPluginStartDependencies {
|
||||
fieldFormats: FieldFormatsStart;
|
||||
logger: Logger;
|
||||
dataViews: DataViewsServerPluginStart;
|
||||
taskManager?: TaskManagerStartContract;
|
||||
}
|
||||
|
||||
export class DataServerPlugin
|
||||
|
@ -90,7 +90,14 @@ export class DataServerPlugin
|
|||
|
||||
public setup(
|
||||
core: CoreSetup<DataPluginStartDependencies, DataPluginStart>,
|
||||
{ bfetch, expressions, usageCollection, fieldFormats }: DataPluginSetupDependencies
|
||||
{
|
||||
bfetch,
|
||||
expressions,
|
||||
usageCollection,
|
||||
fieldFormats,
|
||||
taskManager,
|
||||
security,
|
||||
}: DataPluginSetupDependencies
|
||||
) {
|
||||
this.scriptsService.setup(core);
|
||||
const querySetup = this.queryService.setup(core);
|
||||
|
@ -102,20 +109,26 @@ export class DataServerPlugin
|
|||
bfetch,
|
||||
expressions,
|
||||
usageCollection,
|
||||
security,
|
||||
taskManager,
|
||||
});
|
||||
|
||||
return {
|
||||
__enhance: (enhancements: DataEnhancements) => {
|
||||
searchSetup.__enhance(enhancements.search);
|
||||
},
|
||||
search: searchSetup,
|
||||
query: querySetup,
|
||||
fieldFormats,
|
||||
};
|
||||
}
|
||||
|
||||
public start(core: CoreStart, { fieldFormats, dataViews }: DataPluginStartDependencies) {
|
||||
const search = this.searchService.start(core, { fieldFormats, indexPatterns: dataViews });
|
||||
public start(
|
||||
core: CoreStart,
|
||||
{ fieldFormats, dataViews, taskManager }: DataPluginStartDependencies
|
||||
) {
|
||||
const search = this.searchService.start(core, {
|
||||
fieldFormats,
|
||||
indexPatterns: dataViews,
|
||||
taskManager,
|
||||
});
|
||||
const datatableUtilities = new DatatableUtilitiesService(
|
||||
search.aggs,
|
||||
dataViews,
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
import { once, debounce } from 'lodash';
|
||||
import type { CoreSetup, Logger } from '@kbn/core/server';
|
||||
import type { IEsSearchResponse, ISearchOptions } from '../../../common';
|
||||
import { isCompleteResponse } from '../../../common';
|
||||
import type { IEsSearchResponse, ISearchOptions } from '../../../../common';
|
||||
import { isCompleteResponse } from '../../../../common';
|
||||
import { CollectedUsage } from './register';
|
||||
|
||||
const SAVED_OBJECT_ID = 'search-telemetry';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SavedObjectsErrorHelpers, Logger } from '@kbn/core/server';
|
|
@ -1,14 +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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { Logger } from '@kbn/core/server';
|
||||
import { CollectorFetchContext } from '@kbn/usage-collection-plugin/server';
|
||||
import { SEARCH_SESSION_TYPE } from '@kbn/data-plugin/common';
|
||||
import { ReportedUsage } from './register';
|
||||
import { SEARCH_SESSION_TYPE } from '../../../../common';
|
||||
|
||||
interface SessionPersistedTermsBucket {
|
||||
key_as_string: 'false' | 'true';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { registerUsageCollector } from './register';
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Logger } from '@kbn/core/server';
|
|
@ -10,8 +10,8 @@ export * from './types';
|
|||
export * from './strategies/es_search';
|
||||
export * from './strategies/ese_search';
|
||||
export * from './strategies/eql_search';
|
||||
export type { SearchUsage } from './collectors';
|
||||
export { usageProvider, searchUsageObserver } from './collectors';
|
||||
export type { SearchUsage } from './collectors/search';
|
||||
export { usageProvider, searchUsageObserver } from './collectors/search';
|
||||
export * from './aggs';
|
||||
export * from './session';
|
||||
export * from './errors/no_search_id_in_session';
|
||||
|
|
|
@ -16,7 +16,6 @@ export function createSearchSetupMock(): jest.Mocked<ISearchSetup> {
|
|||
return {
|
||||
aggs: searchAggsSetupMock(),
|
||||
registerSearchStrategy: jest.fn(),
|
||||
__enhance: jest.fn(),
|
||||
searchSource: searchSourceMock.createSetupContract(),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,3 +7,4 @@
|
|||
*/
|
||||
|
||||
export * from './search';
|
||||
export * from './session';
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { MockedKeys } from '@kbn/utility-types/jest';
|
||||
|
||||
import type { CoreSetup, Logger } from '@kbn/core/server';
|
||||
import { coreMock, httpServerMock } from '@kbn/core/server/mocks';
|
||||
import type { PluginStart as DataPluginStart } from '@kbn/data-plugin/server';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/server/mocks';
|
||||
import type { PluginStart as DataPluginStart } from '../..';
|
||||
import { dataPluginMock } from '../../mocks';
|
||||
|
||||
import { registerSessionRoutes } from './session';
|
||||
|
||||
enum PostHandlerIndex {
|
|
@ -1,18 +1,19 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { Logger } from '@kbn/core/server';
|
||||
import { reportServerError } from '@kbn/kibana-utils-plugin/server';
|
||||
import { DataEnhancedPluginRouter } from '../type';
|
||||
import { DataPluginRouter } from '../types';
|
||||
|
||||
const STORE_SEARCH_SESSIONS_ROLE_TAG = `access:store_search_session`;
|
||||
|
||||
export function registerSessionRoutes(router: DataEnhancedPluginRouter, logger: Logger): void {
|
||||
export function registerSessionRoutes(router: DataPluginRouter, logger: Logger): void {
|
||||
router.post(
|
||||
{
|
||||
path: '/internal/session',
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export * from './search_session';
|
|
@ -1,12 +1,13 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SavedObjectsType } from '@kbn/core/server';
|
||||
import { SEARCH_SESSION_TYPE } from '@kbn/data-plugin/common';
|
||||
import { SEARCH_SESSION_TYPE } from '../../../common';
|
||||
import { searchSessionSavedObjectMigrations } from './search_session_migration';
|
||||
|
||||
export const searchSessionSavedObjectType: SavedObjectsType = {
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
|
@ -12,7 +13,7 @@ import {
|
|||
SearchSessionSavedObjectAttributesPre$8$0$0,
|
||||
} from './search_session_migration';
|
||||
import { SavedObject } from '@kbn/core/types';
|
||||
import { SEARCH_SESSION_TYPE, SearchSessionStatus } from '@kbn/data-plugin/common';
|
||||
import { SEARCH_SESSION_TYPE, SearchSessionStatus } from '../../../common';
|
||||
import { SavedObjectMigrationContext } from '@kbn/core/server';
|
||||
|
||||
describe('7.12.0 -> 7.13.0', () => {
|
|
@ -1,15 +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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SavedObjectMigrationMap, SavedObjectUnsanitizedDoc } from '@kbn/core/server';
|
||||
import {
|
||||
SearchSessionSavedObjectAttributes as SearchSessionSavedObjectAttributesLatest,
|
||||
SearchSessionStatus,
|
||||
} from '@kbn/data-plugin/common';
|
||||
} from '../../../common';
|
||||
|
||||
/**
|
||||
* Search sessions were released in 7.12.0
|
|
@ -22,7 +22,6 @@ import type {
|
|||
IEsSearchResponse,
|
||||
IScopedSearchClient,
|
||||
IScopedSearchSessionsClient,
|
||||
ISearchSessionService,
|
||||
ISearchStart,
|
||||
ISearchStrategy,
|
||||
} from '.';
|
||||
|
@ -32,6 +31,16 @@ import { expressionsPluginMock } from '@kbn/expressions-plugin/public/mocks';
|
|||
import { createSearchSessionsClientMock } from './mocks';
|
||||
import { ENHANCED_ES_SEARCH_STRATEGY } from '../../common';
|
||||
|
||||
let mockSessionClient: jest.Mocked<IScopedSearchSessionsClient>;
|
||||
jest.mock('./session', () => {
|
||||
class SearchSessionService {
|
||||
asScopedProvider = () => (request: any) => mockSessionClient;
|
||||
}
|
||||
return {
|
||||
SearchSessionService,
|
||||
};
|
||||
});
|
||||
|
||||
describe('Search service', () => {
|
||||
let plugin: SearchService;
|
||||
let mockCoreSetup: MockedKeys<CoreSetup<DataPluginStartDependencies, DataPluginStart>>;
|
||||
|
@ -88,8 +97,7 @@ describe('Search service', () => {
|
|||
let searchPluginStart: ISearchStart<IEsSearchRequest, IEsSearchResponse<any>>;
|
||||
let mockStrategy: any;
|
||||
let mockStrategyNoCancel: jest.Mocked<ISearchStrategy>;
|
||||
let mockSessionService: ISearchSessionService<any>;
|
||||
let mockSessionClient: jest.Mocked<IScopedSearchSessionsClient>;
|
||||
|
||||
const sessionId = '1234';
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -104,9 +112,6 @@ describe('Search service', () => {
|
|||
};
|
||||
|
||||
mockSessionClient = createSearchSessionsClientMock();
|
||||
mockSessionService = {
|
||||
asScopedProvider: () => (request: any) => mockSessionClient,
|
||||
};
|
||||
|
||||
const pluginSetup = plugin.setup(mockCoreSetup, {
|
||||
bfetch: bfetchPluginMock.createSetupContract(),
|
||||
|
@ -114,9 +119,6 @@ describe('Search service', () => {
|
|||
});
|
||||
pluginSetup.registerSearchStrategy(ENHANCED_ES_SEARCH_STRATEGY, mockStrategy);
|
||||
pluginSetup.registerSearchStrategy('nocancel', mockStrategyNoCancel);
|
||||
pluginSetup.__enhance({
|
||||
sessionService: mockSessionService,
|
||||
});
|
||||
|
||||
searchPluginStart = plugin.start(mockCoreStart, {
|
||||
fieldFormats: createFieldFormatsStartMock(),
|
||||
|
|
|
@ -26,58 +26,63 @@ import { FieldFormatsStart } from '@kbn/field-formats-plugin/server';
|
|||
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
|
||||
import { KbnServerError } from '@kbn/kibana-utils-plugin/server';
|
||||
import type {
|
||||
TaskManagerSetupContract,
|
||||
TaskManagerStartContract,
|
||||
} from '@kbn/task-manager-plugin/server';
|
||||
import type { SecurityPluginSetup } from '@kbn/security-plugin/server';
|
||||
import type {
|
||||
DataRequestHandlerContext,
|
||||
IScopedSearchClient,
|
||||
ISearchSetup,
|
||||
ISearchStart,
|
||||
ISearchStrategy,
|
||||
SearchEnhancements,
|
||||
SearchStrategyDependencies,
|
||||
DataRequestHandlerContext,
|
||||
} from './types';
|
||||
|
||||
import { AggsService } from './aggs';
|
||||
|
||||
import { IndexPatternsServiceStart } from '../data_views';
|
||||
import { registerSearchRoute } from './routes';
|
||||
import { registerSearchRoute, registerSessionRoutes } from './routes';
|
||||
import { ES_SEARCH_STRATEGY, esSearchStrategyProvider } from './strategies/es_search';
|
||||
import { DataPluginStart, DataPluginStartDependencies } from '../plugin';
|
||||
import { registerUsageCollector } from './collectors/register';
|
||||
import { usageProvider } from './collectors/usage';
|
||||
import { usageProvider } from './collectors/search/usage';
|
||||
import { registerUsageCollector as registerSearchUsageCollector } from './collectors/search/register';
|
||||
import { registerUsageCollector as registerSearchSessionUsageCollector } from './collectors/search_session/register';
|
||||
import { searchTelemetry } from '../saved_objects';
|
||||
import {
|
||||
cidrFunction,
|
||||
dateRangeFunction,
|
||||
ENHANCED_ES_SEARCH_STRATEGY,
|
||||
EQL_SEARCH_STRATEGY,
|
||||
esRawResponse,
|
||||
existsFilterFunction,
|
||||
extendedBoundsFunction,
|
||||
fieldFunction,
|
||||
geoBoundingBoxFunction,
|
||||
geoPointFunction,
|
||||
IEsSearchRequest,
|
||||
IEsSearchResponse,
|
||||
IKibanaSearchRequest,
|
||||
IKibanaSearchResponse,
|
||||
ISearchOptions,
|
||||
cidrFunction,
|
||||
dateRangeFunction,
|
||||
extendedBoundsFunction,
|
||||
geoBoundingBoxFunction,
|
||||
geoPointFunction,
|
||||
ipRangeFunction,
|
||||
ISearchOptions,
|
||||
kibana,
|
||||
kibanaContext,
|
||||
kibanaTimerangeFunction,
|
||||
kibanaFilterFunction,
|
||||
kibanaTimerangeFunction,
|
||||
kqlFunction,
|
||||
luceneFunction,
|
||||
numericalRangeFunction,
|
||||
phraseFilterFunction,
|
||||
queryFilterFunction,
|
||||
rangeFilterFunction,
|
||||
removeFilterFunction,
|
||||
selectFilterFunction,
|
||||
rangeFunction,
|
||||
removeFilterFunction,
|
||||
SearchSourceDependencies,
|
||||
searchSourceRequiredUiSettings,
|
||||
SearchSourceService,
|
||||
phraseFilterFunction,
|
||||
esRawResponse,
|
||||
eqlRawResponse,
|
||||
ENHANCED_ES_SEARCH_STRATEGY,
|
||||
EQL_SEARCH_STRATEGY,
|
||||
SQL_SEARCH_STRATEGY,
|
||||
} from '../../common/search';
|
||||
import { getEsaggs, getEsdsl, getEql } from './expressions';
|
||||
|
@ -87,7 +92,7 @@ import {
|
|||
} from '../../common/search/aggs/buckets/shard_delay';
|
||||
import { aggShardDelay } from '../../common/search/aggs/buckets/shard_delay_fn';
|
||||
import { ConfigSchema } from '../../config';
|
||||
import { ISearchSessionService, SearchSessionService } from './session';
|
||||
import { SearchSessionService } from './session';
|
||||
import { registerBsearchRoute } from './routes/bsearch';
|
||||
import { getKibanaContext } from './expressions/kibana_context';
|
||||
import { enhancedEsSearchStrategyProvider } from './strategies/ese_search';
|
||||
|
@ -95,6 +100,7 @@ import { eqlSearchStrategyProvider } from './strategies/eql_search';
|
|||
import { NoSearchIdInSessionError } from './errors/no_search_id_in_session';
|
||||
import { CachedUiSettingsClient } from './services';
|
||||
import { sqlSearchStrategyProvider } from './strategies/sql_search';
|
||||
import { searchSessionSavedObjectType } from './saved_objects';
|
||||
|
||||
type StrategyMap = Record<string, ISearchStrategy<any, any>>;
|
||||
|
||||
|
@ -103,12 +109,15 @@ export interface SearchServiceSetupDependencies {
|
|||
bfetch: BfetchServerSetup;
|
||||
expressions: ExpressionsServerSetup;
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
taskManager?: TaskManagerSetupContract;
|
||||
security?: SecurityPluginSetup;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface SearchServiceStartDependencies {
|
||||
fieldFormats: FieldFormatsStart;
|
||||
indexPatterns: IndexPatternsServiceStart;
|
||||
taskManager?: TaskManagerStartContract;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
@ -121,7 +130,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
private readonly aggsService = new AggsService();
|
||||
private readonly searchSourceService = new SearchSourceService();
|
||||
private searchStrategies: StrategyMap = {};
|
||||
private sessionService: ISearchSessionService;
|
||||
private sessionService: SearchSessionService;
|
||||
private asScoped!: ISearchStart['asScoped'];
|
||||
private searchAsInternalUser!: ISearchStrategy;
|
||||
|
||||
|
@ -129,17 +138,31 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
private initializerContext: PluginInitializerContext<ConfigSchema>,
|
||||
private readonly logger: Logger
|
||||
) {
|
||||
this.sessionService = new SearchSessionService();
|
||||
this.sessionService = new SearchSessionService(
|
||||
logger,
|
||||
initializerContext.config.get(),
|
||||
initializerContext.env.packageInfo.version
|
||||
);
|
||||
}
|
||||
|
||||
public setup(
|
||||
core: CoreSetup<DataPluginStartDependencies, DataPluginStart>,
|
||||
{ bfetch, expressions, usageCollection }: SearchServiceSetupDependencies
|
||||
{ bfetch, expressions, usageCollection, taskManager, security }: SearchServiceSetupDependencies
|
||||
): ISearchSetup {
|
||||
core.savedObjects.registerType(searchSessionSavedObjectType);
|
||||
const usage = usageCollection ? usageProvider(core) : undefined;
|
||||
|
||||
const router = core.http.createRouter<DataRequestHandlerContext>();
|
||||
registerSearchRoute(router);
|
||||
registerSessionRoutes(router, this.logger);
|
||||
|
||||
if (taskManager) {
|
||||
this.sessionService.setup(core, { taskManager, security });
|
||||
} else {
|
||||
// this should never happen in real world, but
|
||||
// taskManager and security are optional deps because they are in x-pack
|
||||
this.logger.debug('Skipping sessionService setup because taskManager is not available');
|
||||
}
|
||||
|
||||
core.http.registerRouteHandlerContext<DataRequestHandlerContext, 'search'>(
|
||||
'search',
|
||||
|
@ -188,7 +211,12 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
|
||||
core.savedObjects.registerType(searchTelemetry);
|
||||
if (usageCollection) {
|
||||
registerUsageCollector(usageCollection, core.savedObjects.getKibanaIndex());
|
||||
registerSearchUsageCollector(usageCollection, core.savedObjects.getKibanaIndex());
|
||||
registerSearchSessionUsageCollector(
|
||||
usageCollection,
|
||||
core.savedObjects.getKibanaIndex(),
|
||||
this.logger
|
||||
);
|
||||
}
|
||||
|
||||
expressions.registerFunction(getEsaggs({ getStartServices: core.getStartServices }));
|
||||
|
@ -229,9 +257,6 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
});
|
||||
|
||||
return {
|
||||
__enhance: (enhancements: SearchEnhancements) => {
|
||||
this.sessionService = enhancements.sessionService;
|
||||
},
|
||||
aggs,
|
||||
registerSearchStrategy: this.registerSearchStrategy,
|
||||
usage,
|
||||
|
@ -241,9 +266,14 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
|
||||
public start(
|
||||
core: CoreStart,
|
||||
{ fieldFormats, indexPatterns }: SearchServiceStartDependencies
|
||||
{ fieldFormats, indexPatterns, taskManager }: SearchServiceStartDependencies
|
||||
): ISearchStart {
|
||||
const { elasticsearch, savedObjects, uiSettings } = core;
|
||||
|
||||
if (taskManager) {
|
||||
this.sessionService.start(core, { taskManager });
|
||||
}
|
||||
|
||||
this.asScoped = this.asScopedProvider(core);
|
||||
return {
|
||||
aggs: this.aggsService.start({
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { checkNonPersistedSessions as checkNonPersistedSessions$ } from './check_non_persisted_sessions';
|
||||
|
@ -11,25 +12,28 @@ import {
|
|||
SearchSessionSavedObjectAttributes,
|
||||
ENHANCED_ES_SEARCH_STRATEGY,
|
||||
EQL_SEARCH_STRATEGY,
|
||||
} from '@kbn/data-plugin/common';
|
||||
} from '../../../common';
|
||||
import { savedObjectsClientMock } from '@kbn/core/server/mocks';
|
||||
import { SearchSessionsConfig, CheckSearchSessionsDeps, SearchStatus } from './types';
|
||||
import { CheckSearchSessionsDeps, SearchStatus } from './types';
|
||||
import moment from 'moment';
|
||||
import {
|
||||
SavedObjectsBulkUpdateObject,
|
||||
SavedObjectsDeleteOptions,
|
||||
SavedObjectsClientContract,
|
||||
} from '@kbn/core/server';
|
||||
import { SearchSessionsConfigSchema } from '../../../config';
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
const checkNonPersistedSessions = (deps: CheckSearchSessionsDeps, config: SearchSessionsConfig) =>
|
||||
checkNonPersistedSessions$(deps, config).toPromise();
|
||||
const checkNonPersistedSessions = (
|
||||
deps: CheckSearchSessionsDeps,
|
||||
config: SearchSessionsConfigSchema
|
||||
) => checkNonPersistedSessions$(deps, config).toPromise();
|
||||
|
||||
describe('checkNonPersistedSessions', () => {
|
||||
let mockClient: any;
|
||||
let savedObjectsClient: jest.Mocked<SavedObjectsClientContract>;
|
||||
const config: SearchSessionsConfig = {
|
||||
const config: SearchSessionsConfigSchema = {
|
||||
enabled: true,
|
||||
pageSize: 5,
|
||||
notTouchedInProgressTimeout: moment.duration(1, 'm'),
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SavedObjectsFindResult } from '@kbn/core/server';
|
||||
|
@ -16,17 +17,18 @@ import {
|
|||
SearchSessionSavedObjectAttributes,
|
||||
SearchSessionStatus,
|
||||
KueryNode,
|
||||
} from '@kbn/data-plugin/common';
|
||||
} from '../../../common';
|
||||
import { checkSearchSessionsByPage, getSearchSessionsPage$ } from './get_search_session_page';
|
||||
import { SearchSessionsConfig, CheckSearchSessionsDeps, SearchStatus } from './types';
|
||||
import { CheckSearchSessionsDeps, SearchStatus } from './types';
|
||||
import { bulkUpdateSessions, getAllSessionsStatusUpdates } from './update_session_status';
|
||||
import { SearchSessionsConfigSchema } from '../../../config';
|
||||
|
||||
export const SEARCH_SESSIONS_CLEANUP_TASK_TYPE = 'search_sessions_cleanup';
|
||||
export const SEARCH_SESSIONS_CLEANUP_TASK_ID = `data_enhanced_${SEARCH_SESSIONS_CLEANUP_TASK_TYPE}`;
|
||||
|
||||
function isSessionStale(
|
||||
session: SavedObjectsFindResult<SearchSessionSavedObjectAttributes>,
|
||||
config: SearchSessionsConfig
|
||||
config: SearchSessionsConfigSchema
|
||||
) {
|
||||
const curTime = moment();
|
||||
// Delete cancelled sessions immediately
|
||||
|
@ -45,7 +47,7 @@ function isSessionStale(
|
|||
|
||||
function checkNonPersistedSessionsPage(
|
||||
deps: CheckSearchSessionsDeps,
|
||||
config: SearchSessionsConfig,
|
||||
config: SearchSessionsConfigSchema,
|
||||
filter: KueryNode,
|
||||
page: number
|
||||
) {
|
||||
|
@ -118,7 +120,7 @@ function checkNonPersistedSessionsPage(
|
|||
|
||||
export function checkNonPersistedSessions(
|
||||
deps: CheckSearchSessionsDeps,
|
||||
config: SearchSessionsConfig
|
||||
config: SearchSessionsConfigSchema
|
||||
) {
|
||||
const { logger } = deps;
|
||||
|
|
@ -1,20 +1,21 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { checkPersistedSessionsProgress } from './check_persisted_sessions';
|
||||
import { savedObjectsClientMock } from '@kbn/core/server/mocks';
|
||||
import { SearchSessionsConfig } from './types';
|
||||
import moment from 'moment';
|
||||
import { SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import { SearchSessionsConfigSchema } from '../../../config';
|
||||
|
||||
describe('checkPersistedSessionsProgress', () => {
|
||||
let mockClient: any;
|
||||
let savedObjectsClient: jest.Mocked<SavedObjectsClientContract>;
|
||||
const config: SearchSessionsConfig = {
|
||||
const config: SearchSessionsConfigSchema = {
|
||||
enabled: true,
|
||||
pageSize: 5,
|
||||
notTouchedInProgressTimeout: moment.duration(1, 'm'),
|
|
@ -1,28 +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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EMPTY, Observable } from 'rxjs';
|
||||
import { catchError, concatMap } from 'rxjs/operators';
|
||||
import {
|
||||
nodeBuilder,
|
||||
SEARCH_SESSION_TYPE,
|
||||
SearchSessionStatus,
|
||||
KueryNode,
|
||||
} from '@kbn/data-plugin/common';
|
||||
import { nodeBuilder, SEARCH_SESSION_TYPE, SearchSessionStatus, KueryNode } from '../../../common';
|
||||
import { checkSearchSessionsByPage, getSearchSessionsPage$ } from './get_search_session_page';
|
||||
import { SearchSessionsConfig, CheckSearchSessionsDeps, SearchSessionsResponse } from './types';
|
||||
import { CheckSearchSessionsDeps, SearchSessionsResponse } from './types';
|
||||
import { bulkUpdateSessions, getAllSessionsStatusUpdates } from './update_session_status';
|
||||
import { SearchSessionsConfigSchema } from '../../../config';
|
||||
|
||||
export const SEARCH_SESSIONS_TASK_TYPE = 'search_sessions_monitor';
|
||||
export const SEARCH_SESSIONS_TASK_ID = `data_enhanced_${SEARCH_SESSIONS_TASK_TYPE}`;
|
||||
|
||||
function checkPersistedSessionsPage(
|
||||
deps: CheckSearchSessionsDeps,
|
||||
config: SearchSessionsConfig,
|
||||
config: SearchSessionsConfigSchema,
|
||||
filter: KueryNode,
|
||||
page: number
|
||||
): Observable<SearchSessionsResponse> {
|
||||
|
@ -50,7 +47,7 @@ function checkPersistedSessionsPage(
|
|||
|
||||
export function checkPersistedSessionsProgress(
|
||||
deps: CheckSearchSessionsDeps,
|
||||
config: SearchSessionsConfig
|
||||
config: SearchSessionsConfigSchema
|
||||
) {
|
||||
const { logger } = deps;
|
||||
|
|
@ -1,28 +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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EMPTY, Observable } from 'rxjs';
|
||||
import { catchError, concatMap } from 'rxjs/operators';
|
||||
import {
|
||||
nodeBuilder,
|
||||
SEARCH_SESSION_TYPE,
|
||||
SearchSessionStatus,
|
||||
KueryNode,
|
||||
} from '@kbn/data-plugin/common';
|
||||
import { nodeBuilder, SEARCH_SESSION_TYPE, SearchSessionStatus, KueryNode } from '../../../common';
|
||||
import { checkSearchSessionsByPage, getSearchSessionsPage$ } from './get_search_session_page';
|
||||
import { SearchSessionsConfig, CheckSearchSessionsDeps, SearchSessionsResponse } from './types';
|
||||
import { CheckSearchSessionsDeps, SearchSessionsResponse } from './types';
|
||||
import { bulkUpdateSessions, getAllSessionsStatusUpdates } from './update_session_status';
|
||||
import { SearchSessionsConfigSchema } from '../../../config';
|
||||
|
||||
export const SEARCH_SESSIONS_EXPIRE_TASK_TYPE = 'search_sessions_expire';
|
||||
export const SEARCH_SESSIONS_EXPIRE_TASK_ID = `data_enhanced_${SEARCH_SESSIONS_EXPIRE_TASK_TYPE}`;
|
||||
|
||||
function checkSessionExpirationPage(
|
||||
deps: CheckSearchSessionsDeps,
|
||||
config: SearchSessionsConfig,
|
||||
config: SearchSessionsConfigSchema,
|
||||
filter: KueryNode,
|
||||
page: number
|
||||
): Observable<SearchSessionsResponse> {
|
||||
|
@ -46,7 +43,7 @@ function checkSessionExpirationPage(
|
|||
|
||||
export function checkPersistedCompletedSessionExpiration(
|
||||
deps: CheckSearchSessionsDeps,
|
||||
config: SearchSessionsConfig
|
||||
config: SearchSessionsConfigSchema
|
||||
) {
|
||||
const { logger } = deps;
|
||||
|
|
@ -1,24 +1,27 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { checkSearchSessionsByPage, getSearchSessionsPage$ } from './get_search_session_page';
|
||||
import { SearchSessionStatus, ENHANCED_ES_SEARCH_STRATEGY } from '@kbn/data-plugin/common';
|
||||
import { ENHANCED_ES_SEARCH_STRATEGY, SearchSessionStatus } from '../../../common';
|
||||
import { savedObjectsClientMock } from '@kbn/core/server/mocks';
|
||||
import { SearchSessionsConfig, SearchStatus } from './types';
|
||||
import { SearchStatus } from './types';
|
||||
import moment from 'moment';
|
||||
import { SavedObjectsClientContract } from '@kbn/core/server';
|
||||
import { of, Subject, throwError } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { SearchSessionsConfigSchema } from '../../../config';
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
describe('checkSearchSessionsByPage', () => {
|
||||
const mockClient = {} as any;
|
||||
let savedObjectsClient: jest.Mocked<SavedObjectsClientContract>;
|
||||
const config: SearchSessionsConfig = {
|
||||
const config: SearchSessionsConfigSchema = {
|
||||
enabled: true,
|
||||
pageSize: 5,
|
||||
management: {} as any,
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SavedObjectsClientContract, Logger } from '@kbn/core/server';
|
||||
|
@ -12,8 +13,9 @@ import {
|
|||
SearchSessionSavedObjectAttributes,
|
||||
SEARCH_SESSION_TYPE,
|
||||
KueryNode,
|
||||
} from '@kbn/data-plugin/common';
|
||||
import { CheckSearchSessionsDeps, CheckSearchSessionsFn, SearchSessionsConfig } from './types';
|
||||
} from '../../../common';
|
||||
import { CheckSearchSessionsDeps, CheckSearchSessionsFn } from './types';
|
||||
import { SearchSessionsConfigSchema } from '../../../config';
|
||||
|
||||
export interface GetSessionsDeps {
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
|
@ -43,7 +45,7 @@ export function getSearchSessionsPage$(
|
|||
export const checkSearchSessionsByPage = (
|
||||
checkFn: CheckSearchSessionsFn,
|
||||
deps: CheckSearchSessionsDeps,
|
||||
config: SearchSessionsConfig,
|
||||
config: SearchSessionsConfigSchema,
|
||||
filters: any,
|
||||
nextPage = 1
|
||||
): Observable<void> =>
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SearchStatus } from './types';
|
|
@ -1,15 +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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { TransportResult } from '@elastic/elasticsearch';
|
||||
import { ElasticsearchClient } from '@kbn/core/server';
|
||||
import { SearchSessionRequestInfo } from '@kbn/data-plugin/common';
|
||||
import { AsyncSearchStatusResponse } from '@kbn/data-plugin/server';
|
||||
import { SearchSessionRequestInfo } from '../../../common';
|
||||
import { AsyncSearchStatusResponse } from '../..';
|
||||
import { SearchStatus } from './types';
|
||||
|
||||
export async function getSearchStatus(
|
||||
|
@ -30,7 +31,7 @@ export async function getSearchStatus(
|
|||
if ((response.is_partial && !response.is_running) || response.completion_status >= 400) {
|
||||
return {
|
||||
status: SearchStatus.ERROR,
|
||||
error: i18n.translate('xpack.data.search.statusError', {
|
||||
error: i18n.translate('data.search.statusError', {
|
||||
defaultMessage: `Search completed with a {errorCode} status`,
|
||||
values: { errorCode: response.completion_status },
|
||||
}),
|
||||
|
@ -49,7 +50,7 @@ export async function getSearchStatus(
|
|||
} catch (e) {
|
||||
return {
|
||||
status: SearchStatus.ERROR,
|
||||
error: i18n.translate('xpack.data.search.statusThrow', {
|
||||
error: i18n.translate('data.search.statusThrow', {
|
||||
defaultMessage: `Search status threw an error {message} ({errorCode}) status`,
|
||||
values: {
|
||||
message: e.message,
|
|
@ -1,19 +1,21 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SearchSessionsConfig, SearchStatus } from './types';
|
||||
import { SearchStatus } from './types';
|
||||
import { getSessionStatus } from './get_session_status';
|
||||
import { SearchSessionStatus } from '@kbn/data-plugin/common';
|
||||
import { SearchSessionStatus } from '../../../common';
|
||||
import moment from 'moment';
|
||||
import { SearchSessionsConfigSchema } from '../../../config';
|
||||
|
||||
describe('getSessionStatus', () => {
|
||||
const mockConfig = {
|
||||
notTouchedInProgressTimeout: moment.duration(1, 'm'),
|
||||
} as unknown as SearchSessionsConfig;
|
||||
} as unknown as SearchSessionsConfigSchema;
|
||||
test("returns an in_progress status if there's nothing inside the session", () => {
|
||||
const session: any = {
|
||||
idMapping: {},
|
|
@ -1,17 +1,19 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import moment from 'moment';
|
||||
import { SearchSessionSavedObjectAttributes, SearchSessionStatus } from '@kbn/data-plugin/common';
|
||||
import { SearchSessionsConfig, SearchStatus } from './types';
|
||||
import { SearchSessionSavedObjectAttributes, SearchSessionStatus } from '../../../common';
|
||||
import { SearchStatus } from './types';
|
||||
import { SearchSessionsConfigSchema } from '../../../config';
|
||||
|
||||
export function getSessionStatus(
|
||||
session: SearchSessionSavedObjectAttributes,
|
||||
config: SearchSessionsConfig
|
||||
config: SearchSessionsConfigSchema
|
||||
): SearchSessionStatus {
|
||||
const searchStatuses = Object.values(session.idMapping);
|
||||
const curTime = moment();
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
|
@ -17,9 +18,9 @@ import moment from 'moment';
|
|||
import { coreMock } from '@kbn/core/server/mocks';
|
||||
import { ConfigSchema } from '../../../config';
|
||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||
import { AuthenticatedUser } from '@kbn/security-plugin/common/model';
|
||||
import { nodeBuilder, SEARCH_SESSION_TYPE, SearchSessionStatus } from '@kbn/data-plugin/common';
|
||||
import { TaskManagerStartContract } from '@kbn/task-manager-plugin/server';
|
||||
import type { AuthenticatedUser } from '@kbn/security-plugin/common/model';
|
||||
import { nodeBuilder, SEARCH_SESSION_TYPE, SearchSessionStatus } from '../../../common';
|
||||
import type { TaskManagerStartContract } from '@kbn/task-manager-plugin/server';
|
||||
|
||||
const MAX_UPDATE_RETRIES = 3;
|
||||
|
||||
|
@ -81,13 +82,14 @@ describe('SearchSessionService', () => {
|
|||
management: {} as any,
|
||||
},
|
||||
},
|
||||
};
|
||||
} as unknown as ConfigSchema;
|
||||
const mockLogger: any = {
|
||||
debug: jest.fn(),
|
||||
warn: jest.fn(),
|
||||
error: jest.fn(),
|
||||
};
|
||||
service = new SearchSessionService(mockLogger, config, '8.0.0');
|
||||
service.setup(coreMock.createSetup(), { taskManager: taskManagerMock.createSetup() });
|
||||
const coreStart = coreMock.createStart();
|
||||
mockTaskManager = taskManagerMock.createStart();
|
||||
await flushPromises();
|
||||
|
@ -161,13 +163,14 @@ describe('SearchSessionService', () => {
|
|||
management: {} as any,
|
||||
},
|
||||
},
|
||||
};
|
||||
} as unknown as ConfigSchema;
|
||||
const mockLogger: any = {
|
||||
debug: jest.fn(),
|
||||
warn: jest.fn(),
|
||||
error: jest.fn(),
|
||||
};
|
||||
service = new SearchSessionService(mockLogger, config, '8.0.0');
|
||||
service.setup(coreMock.createSetup(), { taskManager: taskManagerMock.createSetup() });
|
||||
const coreStart = coreMock.createStart();
|
||||
mockTaskManager = taskManagerMock.createStart();
|
||||
await flushPromises();
|
|
@ -6,47 +6,549 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { ISearchSessionService } from './types';
|
||||
import { notFound } from '@hapi/boom';
|
||||
import { debounce } from 'lodash';
|
||||
import { nodeBuilder, fromKueryExpression } from '@kbn/es-query';
|
||||
import {
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
KibanaRequest,
|
||||
SavedObjectsClientContract,
|
||||
Logger,
|
||||
SavedObject,
|
||||
SavedObjectsFindOptions,
|
||||
SavedObjectsErrorHelpers,
|
||||
} from '@kbn/core/server';
|
||||
import type { AuthenticatedUser, SecurityPluginSetup } from '@kbn/security-plugin/server';
|
||||
import type {
|
||||
TaskManagerSetupContract,
|
||||
TaskManagerStartContract,
|
||||
} from '@kbn/task-manager-plugin/server';
|
||||
import {
|
||||
IKibanaSearchRequest,
|
||||
ISearchOptions,
|
||||
ENHANCED_ES_SEARCH_STRATEGY,
|
||||
SEARCH_SESSION_TYPE,
|
||||
SearchSessionRequestInfo,
|
||||
SearchSessionSavedObjectAttributes,
|
||||
SearchSessionStatus,
|
||||
} from '../../../common';
|
||||
import { ISearchSessionService, NoSearchIdInSessionError } from '../..';
|
||||
import { createRequestHash } from './utils';
|
||||
import { ConfigSchema, SearchSessionsConfigSchema } from '../../../config';
|
||||
import {
|
||||
registerSearchSessionsTask,
|
||||
scheduleSearchSessionsTask,
|
||||
unscheduleSearchSessionsTask,
|
||||
} from './setup_task';
|
||||
import { SearchStatus } from './types';
|
||||
import {
|
||||
checkPersistedSessionsProgress,
|
||||
SEARCH_SESSIONS_TASK_ID,
|
||||
SEARCH_SESSIONS_TASK_TYPE,
|
||||
} from './check_persisted_sessions';
|
||||
import {
|
||||
SEARCH_SESSIONS_CLEANUP_TASK_TYPE,
|
||||
checkNonPersistedSessions,
|
||||
SEARCH_SESSIONS_CLEANUP_TASK_ID,
|
||||
} from './check_non_persisted_sessions';
|
||||
import {
|
||||
SEARCH_SESSIONS_EXPIRE_TASK_TYPE,
|
||||
SEARCH_SESSIONS_EXPIRE_TASK_ID,
|
||||
checkPersistedCompletedSessionExpiration,
|
||||
} from './expire_persisted_sessions';
|
||||
|
||||
/**
|
||||
* The OSS session service, which leaves most search session-related logic unimplemented.
|
||||
* @see x-pack/plugins/data_enhanced/server/search/session/session_service.ts
|
||||
* @internal
|
||||
*/
|
||||
export class SearchSessionService implements ISearchSessionService {
|
||||
constructor() {}
|
||||
|
||||
public asScopedProvider() {
|
||||
return () => ({
|
||||
getId: () => {
|
||||
throw new Error('getId not implemented in OSS search session service');
|
||||
},
|
||||
trackId: async () => {},
|
||||
getSearchIdMapping: async () => new Map<string, string>(),
|
||||
save: async () => {
|
||||
throw new Error('save not implemented in OSS search session service');
|
||||
},
|
||||
get: async () => {
|
||||
throw new Error('get not implemented in OSS search session service');
|
||||
},
|
||||
find: async () => {
|
||||
throw new Error('find not implemented in OSS search session service');
|
||||
},
|
||||
update: async () => {
|
||||
throw new Error('update not implemented in OSS search session service');
|
||||
},
|
||||
extend: async () => {
|
||||
throw new Error('extend not implemented in OSS search session service');
|
||||
},
|
||||
cancel: async () => {
|
||||
throw new Error('cancel not implemented in OSS search session service');
|
||||
},
|
||||
delete: async () => {
|
||||
throw new Error('delete not implemented in OSS search session service');
|
||||
},
|
||||
getConfig: () => {
|
||||
return null;
|
||||
},
|
||||
});
|
||||
}
|
||||
export interface SearchSessionDependencies {
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
}
|
||||
interface SetupDependencies {
|
||||
taskManager: TaskManagerSetupContract;
|
||||
security?: SecurityPluginSetup;
|
||||
}
|
||||
|
||||
interface StartDependencies {
|
||||
taskManager: TaskManagerStartContract;
|
||||
}
|
||||
|
||||
const DEBOUNCE_UPDATE_OR_CREATE_WAIT = 1000;
|
||||
const DEBOUNCE_UPDATE_OR_CREATE_MAX_WAIT = 5000;
|
||||
|
||||
interface UpdateOrCreateQueueEntry {
|
||||
deps: SearchSessionDependencies;
|
||||
user: AuthenticatedUser | null;
|
||||
sessionId: string;
|
||||
attributes: Partial<SearchSessionSavedObjectAttributes>;
|
||||
resolve: () => void;
|
||||
reject: (reason?: unknown) => void;
|
||||
}
|
||||
|
||||
function sleep(ms: number) {
|
||||
return new Promise((r) => setTimeout(r, ms));
|
||||
}
|
||||
export class SearchSessionService
|
||||
implements ISearchSessionService<SearchSessionSavedObjectAttributes>
|
||||
{
|
||||
private sessionConfig: SearchSessionsConfigSchema;
|
||||
private readonly updateOrCreateBatchQueue: UpdateOrCreateQueueEntry[] = [];
|
||||
private security?: SecurityPluginSetup;
|
||||
private setupCompleted = false;
|
||||
|
||||
constructor(
|
||||
private readonly logger: Logger,
|
||||
private readonly config: ConfigSchema,
|
||||
private readonly version: string
|
||||
) {
|
||||
this.sessionConfig = this.config.search.sessions;
|
||||
}
|
||||
|
||||
public setup(core: CoreSetup, deps: SetupDependencies) {
|
||||
this.security = deps.security;
|
||||
const taskDeps = {
|
||||
config: this.config,
|
||||
taskManager: deps.taskManager,
|
||||
logger: this.logger,
|
||||
};
|
||||
|
||||
registerSearchSessionsTask(
|
||||
core,
|
||||
taskDeps,
|
||||
SEARCH_SESSIONS_TASK_TYPE,
|
||||
'persisted session progress',
|
||||
checkPersistedSessionsProgress
|
||||
);
|
||||
|
||||
registerSearchSessionsTask(
|
||||
core,
|
||||
taskDeps,
|
||||
SEARCH_SESSIONS_CLEANUP_TASK_TYPE,
|
||||
'non persisted session cleanup',
|
||||
checkNonPersistedSessions
|
||||
);
|
||||
|
||||
registerSearchSessionsTask(
|
||||
core,
|
||||
taskDeps,
|
||||
SEARCH_SESSIONS_EXPIRE_TASK_TYPE,
|
||||
'complete session expiration',
|
||||
checkPersistedCompletedSessionExpiration
|
||||
);
|
||||
|
||||
this.setupCompleted = true;
|
||||
}
|
||||
|
||||
public async start(core: CoreStart, deps: StartDependencies) {
|
||||
if (!this.setupCompleted)
|
||||
throw new Error('SearchSessionService setup() must be called before start()');
|
||||
|
||||
return this.setupMonitoring(core, deps);
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
|
||||
private setupMonitoring = async (core: CoreStart, deps: StartDependencies) => {
|
||||
const taskDeps = {
|
||||
config: this.config,
|
||||
taskManager: deps.taskManager,
|
||||
logger: this.logger,
|
||||
};
|
||||
|
||||
if (this.sessionConfig.enabled) {
|
||||
scheduleSearchSessionsTask(
|
||||
taskDeps,
|
||||
SEARCH_SESSIONS_TASK_ID,
|
||||
SEARCH_SESSIONS_TASK_TYPE,
|
||||
this.sessionConfig.trackingInterval
|
||||
);
|
||||
|
||||
scheduleSearchSessionsTask(
|
||||
taskDeps,
|
||||
SEARCH_SESSIONS_CLEANUP_TASK_ID,
|
||||
SEARCH_SESSIONS_CLEANUP_TASK_TYPE,
|
||||
this.sessionConfig.cleanupInterval
|
||||
);
|
||||
|
||||
scheduleSearchSessionsTask(
|
||||
taskDeps,
|
||||
SEARCH_SESSIONS_EXPIRE_TASK_ID,
|
||||
SEARCH_SESSIONS_EXPIRE_TASK_TYPE,
|
||||
this.sessionConfig.expireInterval
|
||||
);
|
||||
} else {
|
||||
unscheduleSearchSessionsTask(taskDeps, SEARCH_SESSIONS_TASK_ID);
|
||||
unscheduleSearchSessionsTask(taskDeps, SEARCH_SESSIONS_CLEANUP_TASK_ID);
|
||||
unscheduleSearchSessionsTask(taskDeps, SEARCH_SESSIONS_EXPIRE_TASK_ID);
|
||||
}
|
||||
};
|
||||
|
||||
private processUpdateOrCreateBatchQueue = debounce(
|
||||
() => {
|
||||
const queue = [...this.updateOrCreateBatchQueue];
|
||||
if (queue.length === 0) return;
|
||||
this.updateOrCreateBatchQueue.length = 0;
|
||||
const batchedSessionAttributes = queue.reduce((res, next) => {
|
||||
if (!res[next.sessionId]) {
|
||||
res[next.sessionId] = next.attributes;
|
||||
} else {
|
||||
res[next.sessionId] = {
|
||||
...res[next.sessionId],
|
||||
...next.attributes,
|
||||
idMapping: {
|
||||
...res[next.sessionId].idMapping,
|
||||
...next.attributes.idMapping,
|
||||
},
|
||||
};
|
||||
}
|
||||
return res;
|
||||
}, {} as { [sessionId: string]: Partial<SearchSessionSavedObjectAttributes> });
|
||||
|
||||
Object.keys(batchedSessionAttributes).forEach((sessionId) => {
|
||||
const thisSession = queue.filter((s) => s.sessionId === sessionId);
|
||||
this.updateOrCreate(
|
||||
thisSession[0].deps,
|
||||
thisSession[0].user,
|
||||
sessionId,
|
||||
batchedSessionAttributes[sessionId]
|
||||
)
|
||||
.then(() => {
|
||||
thisSession.forEach((s) => s.resolve());
|
||||
})
|
||||
.catch((e) => {
|
||||
thisSession.forEach((s) => s.reject(e));
|
||||
});
|
||||
});
|
||||
},
|
||||
DEBOUNCE_UPDATE_OR_CREATE_WAIT,
|
||||
{ maxWait: DEBOUNCE_UPDATE_OR_CREATE_MAX_WAIT }
|
||||
);
|
||||
private scheduleUpdateOrCreate = (
|
||||
deps: SearchSessionDependencies,
|
||||
user: AuthenticatedUser | null,
|
||||
sessionId: string,
|
||||
attributes: Partial<SearchSessionSavedObjectAttributes>
|
||||
): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.updateOrCreateBatchQueue.push({ deps, user, sessionId, attributes, resolve, reject });
|
||||
// TODO: this would be better if we'd debounce per sessionId
|
||||
this.processUpdateOrCreateBatchQueue();
|
||||
});
|
||||
};
|
||||
|
||||
private updateOrCreate = async (
|
||||
deps: SearchSessionDependencies,
|
||||
user: AuthenticatedUser | null,
|
||||
sessionId: string,
|
||||
attributes: Partial<SearchSessionSavedObjectAttributes>,
|
||||
retry: number = 1
|
||||
): Promise<SavedObject<SearchSessionSavedObjectAttributes> | undefined> => {
|
||||
const retryOnConflict = async (e: any) => {
|
||||
this.logger.debug(`Conflict error | ${sessionId}`);
|
||||
// Randomize sleep to spread updates out in case of conflicts
|
||||
await sleep(100 + Math.random() * 50);
|
||||
return await this.updateOrCreate(deps, user, sessionId, attributes, retry + 1);
|
||||
};
|
||||
|
||||
this.logger.debug(`updateOrCreate | ${sessionId} | ${retry}`);
|
||||
try {
|
||||
return (await this.update(
|
||||
deps,
|
||||
user,
|
||||
sessionId,
|
||||
attributes
|
||||
)) as SavedObject<SearchSessionSavedObjectAttributes>;
|
||||
} catch (e) {
|
||||
if (SavedObjectsErrorHelpers.isNotFoundError(e)) {
|
||||
try {
|
||||
this.logger.debug(`Object not found | ${sessionId}`);
|
||||
return await this.create(deps, user, sessionId, attributes);
|
||||
} catch (createError) {
|
||||
if (
|
||||
SavedObjectsErrorHelpers.isConflictError(createError) &&
|
||||
retry < this.sessionConfig.maxUpdateRetries
|
||||
) {
|
||||
return await retryOnConflict(createError);
|
||||
} else {
|
||||
this.logger.error(createError);
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
SavedObjectsErrorHelpers.isConflictError(e) &&
|
||||
retry < this.sessionConfig.maxUpdateRetries
|
||||
) {
|
||||
return await retryOnConflict(e);
|
||||
} else {
|
||||
this.logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
public save = async (
|
||||
deps: SearchSessionDependencies,
|
||||
user: AuthenticatedUser | null,
|
||||
sessionId: string,
|
||||
{
|
||||
name,
|
||||
appId,
|
||||
locatorId,
|
||||
initialState = {},
|
||||
restoreState = {},
|
||||
}: Partial<SearchSessionSavedObjectAttributes>
|
||||
) => {
|
||||
if (!this.sessionConfig.enabled) throw new Error('Search sessions are disabled');
|
||||
if (!name) throw new Error('Name is required');
|
||||
if (!appId) throw new Error('AppId is required');
|
||||
if (!locatorId) throw new Error('locatorId is required');
|
||||
|
||||
return this.updateOrCreate(deps, user, sessionId, {
|
||||
name,
|
||||
appId,
|
||||
locatorId,
|
||||
initialState,
|
||||
restoreState,
|
||||
persisted: true,
|
||||
});
|
||||
};
|
||||
|
||||
private create = (
|
||||
{ savedObjectsClient }: SearchSessionDependencies,
|
||||
user: AuthenticatedUser | null,
|
||||
sessionId: string,
|
||||
attributes: Partial<SearchSessionSavedObjectAttributes>
|
||||
) => {
|
||||
this.logger.debug(`create | ${sessionId}`);
|
||||
|
||||
const realmType = user?.authentication_realm.type;
|
||||
const realmName = user?.authentication_realm.name;
|
||||
const username = user?.username;
|
||||
|
||||
return savedObjectsClient.create<SearchSessionSavedObjectAttributes>(
|
||||
SEARCH_SESSION_TYPE,
|
||||
{
|
||||
sessionId,
|
||||
status: SearchSessionStatus.IN_PROGRESS,
|
||||
expires: new Date(
|
||||
Date.now() + this.sessionConfig.defaultExpiration.asMilliseconds()
|
||||
).toISOString(),
|
||||
created: new Date().toISOString(),
|
||||
touched: new Date().toISOString(),
|
||||
idMapping: {},
|
||||
persisted: false,
|
||||
version: this.version,
|
||||
realmType,
|
||||
realmName,
|
||||
username,
|
||||
...attributes,
|
||||
},
|
||||
{ id: sessionId }
|
||||
);
|
||||
};
|
||||
|
||||
public get = async (
|
||||
{ savedObjectsClient }: SearchSessionDependencies,
|
||||
user: AuthenticatedUser | null,
|
||||
sessionId: string
|
||||
) => {
|
||||
this.logger.debug(`get | ${sessionId}`);
|
||||
const session = await savedObjectsClient.get<SearchSessionSavedObjectAttributes>(
|
||||
SEARCH_SESSION_TYPE,
|
||||
sessionId
|
||||
);
|
||||
this.throwOnUserConflict(user, session);
|
||||
return session;
|
||||
};
|
||||
|
||||
public find = (
|
||||
{ savedObjectsClient }: SearchSessionDependencies,
|
||||
user: AuthenticatedUser | null,
|
||||
options: Omit<SavedObjectsFindOptions, 'type'>
|
||||
) => {
|
||||
const userFilters =
|
||||
user === null
|
||||
? []
|
||||
: [
|
||||
nodeBuilder.is(
|
||||
`${SEARCH_SESSION_TYPE}.attributes.realmType`,
|
||||
`${user.authentication_realm.type}`
|
||||
),
|
||||
nodeBuilder.is(
|
||||
`${SEARCH_SESSION_TYPE}.attributes.realmName`,
|
||||
`${user.authentication_realm.name}`
|
||||
),
|
||||
nodeBuilder.is(`${SEARCH_SESSION_TYPE}.attributes.username`, `${user.username}`),
|
||||
];
|
||||
const filterKueryNode =
|
||||
typeof options.filter === 'string' ? fromKueryExpression(options.filter) : options.filter;
|
||||
const filter = nodeBuilder.and(userFilters.concat(filterKueryNode ?? []));
|
||||
return savedObjectsClient.find<SearchSessionSavedObjectAttributes>({
|
||||
...options,
|
||||
filter,
|
||||
type: SEARCH_SESSION_TYPE,
|
||||
});
|
||||
};
|
||||
|
||||
public update = async (
|
||||
deps: SearchSessionDependencies,
|
||||
user: AuthenticatedUser | null,
|
||||
sessionId: string,
|
||||
attributes: Partial<SearchSessionSavedObjectAttributes>
|
||||
) => {
|
||||
this.logger.debug(`update | ${sessionId}`);
|
||||
if (!this.sessionConfig.enabled) throw new Error('Search sessions are disabled');
|
||||
await this.get(deps, user, sessionId); // Verify correct user
|
||||
return deps.savedObjectsClient.update<SearchSessionSavedObjectAttributes>(
|
||||
SEARCH_SESSION_TYPE,
|
||||
sessionId,
|
||||
{
|
||||
...attributes,
|
||||
touched: new Date().toISOString(),
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
public async extend(
|
||||
deps: SearchSessionDependencies,
|
||||
user: AuthenticatedUser | null,
|
||||
sessionId: string,
|
||||
expires: Date
|
||||
) {
|
||||
this.logger.debug(`extend | ${sessionId}`);
|
||||
return this.update(deps, user, sessionId, { expires: expires.toISOString() });
|
||||
}
|
||||
|
||||
public cancel = async (
|
||||
deps: SearchSessionDependencies,
|
||||
user: AuthenticatedUser | null,
|
||||
sessionId: string
|
||||
) => {
|
||||
this.logger.debug(`delete | ${sessionId}`);
|
||||
return this.update(deps, user, sessionId, {
|
||||
status: SearchSessionStatus.CANCELLED,
|
||||
});
|
||||
};
|
||||
|
||||
public delete = async (
|
||||
deps: SearchSessionDependencies,
|
||||
user: AuthenticatedUser | null,
|
||||
sessionId: string
|
||||
) => {
|
||||
if (!this.sessionConfig.enabled) throw new Error('Search sessions are disabled');
|
||||
this.logger.debug(`delete | ${sessionId}`);
|
||||
await this.get(deps, user, sessionId); // Verify correct user
|
||||
return deps.savedObjectsClient.delete(SEARCH_SESSION_TYPE, sessionId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Tracks the given search request/search ID in the saved session.
|
||||
* @internal
|
||||
*/
|
||||
public trackId = async (
|
||||
deps: SearchSessionDependencies,
|
||||
user: AuthenticatedUser | null,
|
||||
searchRequest: IKibanaSearchRequest,
|
||||
searchId: string,
|
||||
{ sessionId, strategy = ENHANCED_ES_SEARCH_STRATEGY }: ISearchOptions
|
||||
) => {
|
||||
if (!this.sessionConfig.enabled || !sessionId || !searchId) return;
|
||||
this.logger.debug(`trackId | ${sessionId} | ${searchId}`);
|
||||
|
||||
let idMapping: Record<string, SearchSessionRequestInfo> = {};
|
||||
|
||||
if (searchRequest.params) {
|
||||
const requestHash = createRequestHash(searchRequest.params);
|
||||
const searchInfo = {
|
||||
id: searchId,
|
||||
strategy,
|
||||
status: SearchStatus.IN_PROGRESS,
|
||||
};
|
||||
idMapping = { [requestHash]: searchInfo };
|
||||
}
|
||||
|
||||
await this.scheduleUpdateOrCreate(deps, user, sessionId, { idMapping });
|
||||
};
|
||||
|
||||
public async getSearchIdMapping(
|
||||
deps: SearchSessionDependencies,
|
||||
user: AuthenticatedUser | null,
|
||||
sessionId: string
|
||||
) {
|
||||
const searchSession = await this.get(deps, user, sessionId);
|
||||
const searchIdMapping = new Map<string, string>();
|
||||
Object.values(searchSession.attributes.idMapping).forEach((requestInfo) => {
|
||||
searchIdMapping.set(requestInfo.id, requestInfo.strategy);
|
||||
});
|
||||
return searchIdMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up an existing search ID that matches the given request in the given session so that the
|
||||
* request can continue rather than restart.
|
||||
* @internal
|
||||
*/
|
||||
public getId = async (
|
||||
deps: SearchSessionDependencies,
|
||||
user: AuthenticatedUser | null,
|
||||
searchRequest: IKibanaSearchRequest,
|
||||
{ sessionId, isStored, isRestore }: ISearchOptions
|
||||
) => {
|
||||
if (!this.sessionConfig.enabled) {
|
||||
throw new Error('Search sessions are disabled');
|
||||
} else if (!sessionId) {
|
||||
throw new Error('Session ID is required');
|
||||
} else if (!isStored) {
|
||||
throw new Error('Cannot get search ID from a session that is not stored');
|
||||
} else if (!isRestore) {
|
||||
throw new Error('Get search ID is only supported when restoring a session');
|
||||
}
|
||||
|
||||
const session = await this.get(deps, user, sessionId);
|
||||
const requestHash = createRequestHash(searchRequest.params);
|
||||
if (!session.attributes.idMapping.hasOwnProperty(requestHash)) {
|
||||
this.logger.error(`getId | ${sessionId} | ${requestHash} not found`);
|
||||
throw new NoSearchIdInSessionError();
|
||||
}
|
||||
this.logger.debug(`getId | ${sessionId} | ${requestHash}`);
|
||||
|
||||
return session.attributes.idMapping[requestHash].id;
|
||||
};
|
||||
|
||||
public asScopedProvider = ({ savedObjects }: CoreStart) => {
|
||||
return (request: KibanaRequest) => {
|
||||
const user = this.security?.authc.getCurrentUser(request) ?? null;
|
||||
const savedObjectsClient = savedObjects.getScopedClient(request, {
|
||||
includedHiddenTypes: [SEARCH_SESSION_TYPE],
|
||||
});
|
||||
const deps = { savedObjectsClient };
|
||||
return {
|
||||
getId: this.getId.bind(this, deps, user),
|
||||
trackId: this.trackId.bind(this, deps, user),
|
||||
getSearchIdMapping: this.getSearchIdMapping.bind(this, deps, user),
|
||||
save: this.save.bind(this, deps, user),
|
||||
get: this.get.bind(this, deps, user),
|
||||
find: this.find.bind(this, deps, user),
|
||||
update: this.update.bind(this, deps, user),
|
||||
extend: this.extend.bind(this, deps, user),
|
||||
cancel: this.cancel.bind(this, deps, user),
|
||||
delete: this.delete.bind(this, deps, user),
|
||||
getConfig: () => this.config.search.sessions,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
private throwOnUserConflict = (
|
||||
user: AuthenticatedUser | null,
|
||||
session?: SavedObject<SearchSessionSavedObjectAttributes>
|
||||
) => {
|
||||
if (user === null || !session) return;
|
||||
if (
|
||||
user.authentication_realm.type !== session.attributes.realmType ||
|
||||
user.authentication_realm.name !== session.attributes.realmName ||
|
||||
user.username !== session.attributes.username
|
||||
) {
|
||||
this.logger.debug(
|
||||
`User ${user.username} has no access to search session ${session.attributes.sessionId}`
|
||||
);
|
||||
throw notFound();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Duration } from 'moment';
|
||||
import { filter, takeUntil } from 'rxjs/operators';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { RunContext, TaskRunCreatorFunction } from '@kbn/task-manager-plugin/server';
|
||||
import type { RunContext, TaskRunCreatorFunction } from '@kbn/task-manager-plugin/server';
|
||||
import { CoreSetup, SavedObjectsClient } from '@kbn/core/server';
|
||||
import { SEARCH_SESSION_TYPE } from '@kbn/data-plugin/common';
|
||||
import { DataEnhancedStartDependencies } from '../../type';
|
||||
import { SEARCH_SESSION_TYPE } from '../../../common';
|
||||
import {
|
||||
SearchSessionTaskSetupDeps,
|
||||
SearchSessionTaskStartDeps,
|
||||
|
@ -19,7 +19,7 @@ import {
|
|||
} from './types';
|
||||
|
||||
export function searchSessionTaskRunner(
|
||||
core: CoreSetup<DataEnhancedStartDependencies>,
|
||||
core: CoreSetup,
|
||||
deps: SearchSessionTaskSetupDeps,
|
||||
title: string,
|
||||
checkFn: SearchSessionTaskFn
|
||||
|
@ -68,7 +68,7 @@ export function searchSessionTaskRunner(
|
|||
}
|
||||
|
||||
export function registerSearchSessionsTask(
|
||||
core: CoreSetup<DataEnhancedStartDependencies>,
|
||||
core: CoreSetup,
|
||||
deps: SearchSessionTaskSetupDeps,
|
||||
taskType: string,
|
||||
title: string,
|
|
@ -6,6 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import {
|
||||
CoreStart,
|
||||
KibanaRequest,
|
||||
|
@ -13,9 +14,17 @@ import {
|
|||
SavedObjectsFindOptions,
|
||||
SavedObjectsFindResponse,
|
||||
SavedObjectsUpdateResponse,
|
||||
ElasticsearchClient,
|
||||
Logger,
|
||||
SavedObjectsClientContract,
|
||||
} from '@kbn/core/server';
|
||||
import type {
|
||||
TaskManagerSetupContract,
|
||||
TaskManagerStartContract,
|
||||
} from '@kbn/task-manager-plugin/server';
|
||||
import { KueryNode, SearchSessionSavedObjectAttributes } from '../../../common';
|
||||
import { IKibanaSearchRequest, ISearchOptions } from '../../../common/search';
|
||||
import { SearchSessionsConfigSchema } from '../../../config';
|
||||
import { SearchSessionsConfigSchema, ConfigSchema } from '../../../config';
|
||||
|
||||
export interface IScopedSearchSessionsClient<T = unknown> {
|
||||
getId: (request: IKibanaSearchRequest, options: ISearchOptions) => Promise<string>;
|
||||
|
@ -38,3 +47,44 @@ export interface IScopedSearchSessionsClient<T = unknown> {
|
|||
export interface ISearchSessionService<T = unknown> {
|
||||
asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSearchSessionsClient<T>;
|
||||
}
|
||||
|
||||
export enum SearchStatus {
|
||||
IN_PROGRESS = 'in_progress',
|
||||
ERROR = 'error',
|
||||
COMPLETE = 'complete',
|
||||
}
|
||||
|
||||
export interface CheckSearchSessionsDeps {
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
client: ElasticsearchClient;
|
||||
logger: Logger;
|
||||
}
|
||||
|
||||
export interface SearchSessionTaskSetupDeps {
|
||||
taskManager: TaskManagerSetupContract;
|
||||
logger: Logger;
|
||||
config: ConfigSchema;
|
||||
}
|
||||
|
||||
export interface SearchSessionTaskStartDeps {
|
||||
taskManager: TaskManagerStartContract;
|
||||
logger: Logger;
|
||||
config: ConfigSchema;
|
||||
}
|
||||
|
||||
export type SearchSessionTaskFn = (
|
||||
deps: CheckSearchSessionsDeps,
|
||||
config: SearchSessionsConfigSchema
|
||||
) => Observable<void>;
|
||||
|
||||
export type SearchSessionsResponse = SavedObjectsFindResponse<
|
||||
SearchSessionSavedObjectAttributes,
|
||||
unknown
|
||||
>;
|
||||
|
||||
export type CheckSearchSessionsFn = (
|
||||
deps: CheckSearchSessionsDeps,
|
||||
config: SearchSessionsConfigSchema,
|
||||
filter: KueryNode,
|
||||
page: number
|
||||
) => Observable<SearchSessionsResponse>;
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { bulkUpdateSessions, updateSessionStatus } from './update_session_status';
|
||||
import { SearchSessionStatus, SearchSessionSavedObjectAttributes } from '@kbn/data-plugin/common';
|
||||
import { SearchSessionStatus, SearchSessionSavedObjectAttributes } from '../../../common';
|
||||
import { savedObjectsClientMock } from '@kbn/core/server/mocks';
|
||||
import { SearchStatus } from './types';
|
||||
import moment from 'moment';
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue