From 5480c4d0f4a6ecb04a0ba0e55b9370b850a29cf5 Mon Sep 17 00:00:00 2001 From: Mikhail Shustov Date: Tue, 10 Aug 2021 09:53:40 +0300 Subject: [PATCH] [Execution context] Add nested context support (#107523) * Add nested context support * remove execution context service on the client side ExecutionContextContaier is not compatible with SerializableState, so I had to fall back to passing context as POJO. With this change, using a service looks like overhead. * update docs * fix test * address comments from Josh * put export back * update docs * remove outdated export * use input.title for unsaved vis Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- ...-core-public.corestart.executioncontext.md | 13 - .../kibana-plugin-core-public.corestart.md | 1 - ...lic.executioncontextservicestart.create.md | 19 - ...ore-public.executioncontextservicestart.md | 25 - ...in-core-public.httpfetchoptions.context.md | 2 +- ...ana-plugin-core-public.httpfetchoptions.md | 2 +- ...-core-public.iexecutioncontextcontainer.md | 20 - ...lic.iexecutioncontextcontainer.toheader.md | 11 - ...ublic.iexecutioncontextcontainer.tojson.md | 11 - ...blic.kibanaexecutioncontext.description.md | 13 - ...n-core-public.kibanaexecutioncontext.id.md | 13 - ...ugin-core-public.kibanaexecutioncontext.md | 23 +- ...core-public.kibanaexecutioncontext.name.md | 13 - ...core-public.kibanaexecutioncontext.type.md | 13 - ...-core-public.kibanaexecutioncontext.url.md | 13 - .../core/public/kibana-plugin-core-public.md | 4 +- ...n-core-server.executioncontextsetup.get.md | 17 - ...lugin-core-server.executioncontextsetup.md | 3 +- ...n-core-server.executioncontextsetup.set.md | 24 - ...erver.executioncontextsetup.withcontext.md | 25 + ...erver.iexecutioncontextcontainer.tojson.md | 4 +- ...rver.kibanaexecutioncontext.description.md | 13 - ...n-core-server.kibanaexecutioncontext.id.md | 13 - ...ugin-core-server.kibanaexecutioncontext.md | 23 +- ...core-server.kibanaexecutioncontext.name.md | 13 - ...core-server.kibanaexecutioncontext.type.md | 13 - ...-core-server.kibanaexecutioncontext.url.md | 13 - ...ore-server.kibanaserverexecutioncontext.md | 19 - ....kibanaserverexecutioncontext.requestid.md | 11 - .../core/server/kibana-plugin-core-server.md | 3 +- ...ugins-embeddable-public.embeddableinput.md | 1 + ...ic.executioncontext.getexecutioncontext.md | 2 +- ...ins-expressions-public.executioncontext.md | 2 +- ...expressionloaderparams.executioncontext.md | 2 +- ...ressions-public.iexpressionloaderparams.md | 2 +- ...er.executioncontext.getexecutioncontext.md | 2 +- ...ins-expressions-server.executioncontext.md | 2 +- src/core/public/core_system.test.mocks.ts | 9 - src/core/public/core_system.test.ts | 19 - src/core/public/core_system.ts | 7 - .../execution_context_container.test.ts | 71 +++ .../execution_context_service.mock.ts | 37 -- .../execution_context_service.ts | 39 -- src/core/public/execution_context/index.ts | 4 +- src/core/public/http/fetch.test.ts | 14 +- src/core/public/http/fetch.ts | 3 +- src/core/public/http/types.ts | 4 +- src/core/public/index.ts | 5 - src/core/public/mocks.ts | 3 - src/core/public/plugins/plugin_context.ts | 1 - .../public/plugins/plugins_service.test.ts | 2 - src/core/public/public.api.md | 32 +- .../elasticsearch/client/cluster_client.ts | 3 +- .../elasticsearch/client/configure_client.ts | 5 +- .../elasticsearch/elasticsearch_service.ts | 2 +- .../execution_context_container.test.ts | 101 ++-- .../execution_context_container.ts | 27 +- .../execution_context_service.mock.ts | 7 +- .../execution_context_service.test.ts | 446 +++++++++++++++--- .../execution_context_service.ts | 85 ++-- src/core/server/execution_context/index.ts | 1 - .../integration_tests/tracing.test.ts | 138 ++++-- src/core/server/http/http_server.ts | 7 +- src/core/server/index.ts | 6 +- src/core/server/plugins/plugin_context.ts | 4 +- src/core/server/server.api.md | 24 +- src/core/types/execution_context.ts | 14 +- .../embeddable/dashboard_container.tsx | 5 +- .../hooks/use_dashboard_app_state.ts | 7 + .../lib/build_dashboard_container.ts | 4 + .../lib/convert_dashboard_state.ts | 4 + .../application/lib/diff_dashboard_state.ts | 2 +- src/plugins/dashboard/public/types.ts | 6 +- .../data/public/search/expressions/esaggs.ts | 2 +- .../data/server/search/routes/bsearch.ts | 33 +- src/plugins/embeddable/common/types.ts | 4 +- src/plugins/embeddable/public/public.api.md | 2 + src/plugins/embeddable/server/server.api.md | 1 + .../expressions/common/execution/types.ts | 4 +- .../common/service/expressions_services.ts | 4 +- src/plugins/expressions/public/public.api.md | 6 +- src/plugins/expressions/public/types/index.ts | 4 +- src/plugins/expressions/server/server.api.md | 4 +- .../public/request_handler.ts | 4 +- .../public/embeddable/visualize_embeddable.ts | 17 +- .../visualize_embeddable_factory.tsx | 5 +- src/plugins/visualizations/public/mocks.ts | 1 - src/plugins/visualizations/public/plugin.ts | 2 - .../core_plugins/execution_context.ts | 4 +- .../public/embeddable/embeddable.test.tsx | 18 - .../lens/public/embeddable/embeddable.tsx | 11 +- .../public/embeddable/embeddable_factory.ts | 10 +- .../public/embeddable/expression_wrapper.tsx | 4 +- x-pack/plugins/lens/public/plugin.ts | 1 - 94 files changed, 887 insertions(+), 805 deletions(-) delete mode 100644 docs/development/core/public/kibana-plugin-core-public.corestart.executioncontext.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.executioncontextservicestart.create.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.executioncontextservicestart.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.iexecutioncontextcontainer.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.iexecutioncontextcontainer.toheader.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.iexecutioncontextcontainer.tojson.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.description.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.id.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.name.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.type.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.url.md delete mode 100644 docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.get.md delete mode 100644 docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.set.md create mode 100644 docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.withcontext.md delete mode 100644 docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.description.md delete mode 100644 docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.id.md delete mode 100644 docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.name.md delete mode 100644 docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.type.md delete mode 100644 docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.url.md delete mode 100644 docs/development/core/server/kibana-plugin-core-server.kibanaserverexecutioncontext.md delete mode 100644 docs/development/core/server/kibana-plugin-core-server.kibanaserverexecutioncontext.requestid.md delete mode 100644 src/core/public/execution_context/execution_context_service.mock.ts delete mode 100644 src/core/public/execution_context/execution_context_service.ts diff --git a/docs/development/core/public/kibana-plugin-core-public.corestart.executioncontext.md b/docs/development/core/public/kibana-plugin-core-public.corestart.executioncontext.md deleted file mode 100644 index 66c5f3efa2d847..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.corestart.executioncontext.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [CoreStart](./kibana-plugin-core-public.corestart.md) > [executionContext](./kibana-plugin-core-public.corestart.executioncontext.md) - -## CoreStart.executionContext property - -[ExecutionContextServiceStart](./kibana-plugin-core-public.executioncontextservicestart.md) - -Signature: - -```typescript -executionContext: ExecutionContextServiceStart; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.corestart.md b/docs/development/core/public/kibana-plugin-core-public.corestart.md index df1929b1f20abe..6ad9adca53ef5c 100644 --- a/docs/development/core/public/kibana-plugin-core-public.corestart.md +++ b/docs/development/core/public/kibana-plugin-core-public.corestart.md @@ -20,7 +20,6 @@ export interface CoreStart | [chrome](./kibana-plugin-core-public.corestart.chrome.md) | ChromeStart | [ChromeStart](./kibana-plugin-core-public.chromestart.md) | | [deprecations](./kibana-plugin-core-public.corestart.deprecations.md) | DeprecationsServiceStart | [DeprecationsServiceStart](./kibana-plugin-core-public.deprecationsservicestart.md) | | [docLinks](./kibana-plugin-core-public.corestart.doclinks.md) | DocLinksStart | [DocLinksStart](./kibana-plugin-core-public.doclinksstart.md) | -| [executionContext](./kibana-plugin-core-public.corestart.executioncontext.md) | ExecutionContextServiceStart | [ExecutionContextServiceStart](./kibana-plugin-core-public.executioncontextservicestart.md) | | [fatalErrors](./kibana-plugin-core-public.corestart.fatalerrors.md) | FatalErrorsStart | [FatalErrorsStart](./kibana-plugin-core-public.fatalerrorsstart.md) | | [http](./kibana-plugin-core-public.corestart.http.md) | HttpStart | [HttpStart](./kibana-plugin-core-public.httpstart.md) | | [i18n](./kibana-plugin-core-public.corestart.i18n.md) | I18nStart | [I18nStart](./kibana-plugin-core-public.i18nstart.md) | diff --git a/docs/development/core/public/kibana-plugin-core-public.executioncontextservicestart.create.md b/docs/development/core/public/kibana-plugin-core-public.executioncontextservicestart.create.md deleted file mode 100644 index b36f8ade848e5b..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.executioncontextservicestart.create.md +++ /dev/null @@ -1,19 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ExecutionContextServiceStart](./kibana-plugin-core-public.executioncontextservicestart.md) > [create](./kibana-plugin-core-public.executioncontextservicestart.create.md) - -## ExecutionContextServiceStart.create property - -Creates a context container carrying the meta-data of a runtime operation. Provided meta-data will be propagated to Kibana and Elasticsearch servers. - -```js -const context = executionContext.create(...); -http.fetch('/endpoint/', { context }); - -``` - -Signature: - -```typescript -create: (context: KibanaExecutionContext) => IExecutionContextContainer; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.executioncontextservicestart.md b/docs/development/core/public/kibana-plugin-core-public.executioncontextservicestart.md deleted file mode 100644 index d3eecf601ba9c5..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.executioncontextservicestart.md +++ /dev/null @@ -1,25 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ExecutionContextServiceStart](./kibana-plugin-core-public.executioncontextservicestart.md) - -## ExecutionContextServiceStart interface - - -Signature: - -```typescript -export interface ExecutionContextServiceStart -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [create](./kibana-plugin-core-public.executioncontextservicestart.create.md) | (context: KibanaExecutionContext) => IExecutionContextContainer | Creates a context container carrying the meta-data of a runtime operation. Provided meta-data will be propagated to Kibana and Elasticsearch servers. -```js -const context = executionContext.create(...); -http.fetch('/endpoint/', { context }); - -``` - | - diff --git a/docs/development/core/public/kibana-plugin-core-public.httpfetchoptions.context.md b/docs/development/core/public/kibana-plugin-core-public.httpfetchoptions.context.md index 6c6ce3171aaeb3..09ab95a5135f62 100644 --- a/docs/development/core/public/kibana-plugin-core-public.httpfetchoptions.context.md +++ b/docs/development/core/public/kibana-plugin-core-public.httpfetchoptions.context.md @@ -7,5 +7,5 @@ Signature: ```typescript -context?: IExecutionContextContainer; +context?: KibanaExecutionContext; ``` diff --git a/docs/development/core/public/kibana-plugin-core-public.httpfetchoptions.md b/docs/development/core/public/kibana-plugin-core-public.httpfetchoptions.md index 020a941189013a..45a48372b45125 100644 --- a/docs/development/core/public/kibana-plugin-core-public.httpfetchoptions.md +++ b/docs/development/core/public/kibana-plugin-core-public.httpfetchoptions.md @@ -18,7 +18,7 @@ export interface HttpFetchOptions extends HttpRequestInit | --- | --- | --- | | [asResponse](./kibana-plugin-core-public.httpfetchoptions.asresponse.md) | boolean | When true the return type of [HttpHandler](./kibana-plugin-core-public.httphandler.md) will be an [HttpResponse](./kibana-plugin-core-public.httpresponse.md) with detailed request and response information. When false, the return type will just be the parsed response body. Defaults to false. | | [asSystemRequest](./kibana-plugin-core-public.httpfetchoptions.assystemrequest.md) | boolean | Whether or not the request should include the "system request" header to differentiate an end user request from Kibana internal request. Can be read on the server-side using KibanaRequest\#isSystemRequest. Defaults to false. | -| [context](./kibana-plugin-core-public.httpfetchoptions.context.md) | IExecutionContextContainer | | +| [context](./kibana-plugin-core-public.httpfetchoptions.context.md) | KibanaExecutionContext | | | [headers](./kibana-plugin-core-public.httpfetchoptions.headers.md) | HttpHeadersInit | Headers to send with the request. See [HttpHeadersInit](./kibana-plugin-core-public.httpheadersinit.md). | | [prependBasePath](./kibana-plugin-core-public.httpfetchoptions.prependbasepath.md) | boolean | Whether or not the request should automatically prepend the basePath. Defaults to true. | | [query](./kibana-plugin-core-public.httpfetchoptions.query.md) | HttpFetchQuery | The query string for an HTTP request. See [HttpFetchQuery](./kibana-plugin-core-public.httpfetchquery.md). | diff --git a/docs/development/core/public/kibana-plugin-core-public.iexecutioncontextcontainer.md b/docs/development/core/public/kibana-plugin-core-public.iexecutioncontextcontainer.md deleted file mode 100644 index 96ca86cffbc5f0..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.iexecutioncontextcontainer.md +++ /dev/null @@ -1,20 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [IExecutionContextContainer](./kibana-plugin-core-public.iexecutioncontextcontainer.md) - -## IExecutionContextContainer interface - - -Signature: - -```typescript -export interface IExecutionContextContainer -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [toHeader](./kibana-plugin-core-public.iexecutioncontextcontainer.toheader.md) | () => Record<string, string> | | -| [toJSON](./kibana-plugin-core-public.iexecutioncontextcontainer.tojson.md) | () => Readonly<KibanaExecutionContext> | | - diff --git a/docs/development/core/public/kibana-plugin-core-public.iexecutioncontextcontainer.toheader.md b/docs/development/core/public/kibana-plugin-core-public.iexecutioncontextcontainer.toheader.md deleted file mode 100644 index 03132d24bcca5e..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.iexecutioncontextcontainer.toheader.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [IExecutionContextContainer](./kibana-plugin-core-public.iexecutioncontextcontainer.md) > [toHeader](./kibana-plugin-core-public.iexecutioncontextcontainer.toheader.md) - -## IExecutionContextContainer.toHeader property - -Signature: - -```typescript -toHeader: () => Record; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.iexecutioncontextcontainer.tojson.md b/docs/development/core/public/kibana-plugin-core-public.iexecutioncontextcontainer.tojson.md deleted file mode 100644 index 916148141c8f32..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.iexecutioncontextcontainer.tojson.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [IExecutionContextContainer](./kibana-plugin-core-public.iexecutioncontextcontainer.md) > [toJSON](./kibana-plugin-core-public.iexecutioncontextcontainer.tojson.md) - -## IExecutionContextContainer.toJSON property - -Signature: - -```typescript -toJSON: () => Readonly; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.description.md b/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.description.md deleted file mode 100644 index ea8c543c6789e6..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.description.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [KibanaExecutionContext](./kibana-plugin-core-public.kibanaexecutioncontext.md) > [description](./kibana-plugin-core-public.kibanaexecutioncontext.description.md) - -## KibanaExecutionContext.description property - -human readable description. For example, a vis title, action name - -Signature: - -```typescript -readonly description: string; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.id.md b/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.id.md deleted file mode 100644 index d17f9cb8a7ff37..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.id.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [KibanaExecutionContext](./kibana-plugin-core-public.kibanaexecutioncontext.md) > [id](./kibana-plugin-core-public.kibanaexecutioncontext.id.md) - -## KibanaExecutionContext.id property - -unique value to identify the source - -Signature: - -```typescript -readonly id: string; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.md b/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.md index 06154c814c4e7e..8b758715a19752 100644 --- a/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.md +++ b/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.md @@ -2,22 +2,19 @@ [Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [KibanaExecutionContext](./kibana-plugin-core-public.kibanaexecutioncontext.md) -## KibanaExecutionContext interface +## KibanaExecutionContext type +Represents a meta-information about a Kibana entity initiating a search request. Signature: ```typescript -export interface KibanaExecutionContext +export declare type KibanaExecutionContext = { + readonly type: string; + readonly name: string; + readonly id: string; + readonly description: string; + readonly url?: string; + parent?: KibanaExecutionContext; +}; ``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [description](./kibana-plugin-core-public.kibanaexecutioncontext.description.md) | string | human readable description. For example, a vis title, action name | -| [id](./kibana-plugin-core-public.kibanaexecutioncontext.id.md) | string | unique value to identify the source | -| [name](./kibana-plugin-core-public.kibanaexecutioncontext.name.md) | string | public name of a user-facing feature | -| [type](./kibana-plugin-core-public.kibanaexecutioncontext.type.md) | string | Kibana application initated an operation. | -| [url](./kibana-plugin-core-public.kibanaexecutioncontext.url.md) | string | in browser - url to navigate to a current page, on server - endpoint path, for task: task SO url | - diff --git a/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.name.md b/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.name.md deleted file mode 100644 index 21dde32e21ce71..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.name.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [KibanaExecutionContext](./kibana-plugin-core-public.kibanaexecutioncontext.md) > [name](./kibana-plugin-core-public.kibanaexecutioncontext.name.md) - -## KibanaExecutionContext.name property - -public name of a user-facing feature - -Signature: - -```typescript -readonly name: string; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.type.md b/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.type.md deleted file mode 100644 index 48009ebaaeaa51..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.type.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [KibanaExecutionContext](./kibana-plugin-core-public.kibanaexecutioncontext.md) > [type](./kibana-plugin-core-public.kibanaexecutioncontext.type.md) - -## KibanaExecutionContext.type property - -Kibana application initated an operation. - -Signature: - -```typescript -readonly type: string; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.url.md b/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.url.md deleted file mode 100644 index 47ad7604b473d6..00000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.kibanaexecutioncontext.url.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [KibanaExecutionContext](./kibana-plugin-core-public.kibanaexecutioncontext.md) > [url](./kibana-plugin-core-public.kibanaexecutioncontext.url.md) - -## KibanaExecutionContext.url property - -in browser - url to navigate to a current page, on server - endpoint path, for task: task SO url - -Signature: - -```typescript -readonly url?: string; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.md b/docs/development/core/public/kibana-plugin-core-public.md index d743508e046ea8..e984fbb675e6dc 100644 --- a/docs/development/core/public/kibana-plugin-core-public.md +++ b/docs/development/core/public/kibana-plugin-core-public.md @@ -63,7 +63,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [DocLinksStart](./kibana-plugin-core-public.doclinksstart.md) | | | [DomainDeprecationDetails](./kibana-plugin-core-public.domaindeprecationdetails.md) | | | [ErrorToastOptions](./kibana-plugin-core-public.errortoastoptions.md) | Options available for [IToasts](./kibana-plugin-core-public.itoasts.md) error APIs. | -| [ExecutionContextServiceStart](./kibana-plugin-core-public.executioncontextservicestart.md) | | | [FatalErrorInfo](./kibana-plugin-core-public.fatalerrorinfo.md) | Represents the message and stack of a fatal Error | | [FatalErrorsSetup](./kibana-plugin-core-public.fatalerrorssetup.md) | FatalErrors stop the Kibana Public Core and displays a fatal error screen with details about the Kibana build and the error. | | [HttpFetchOptions](./kibana-plugin-core-public.httpfetchoptions.md) | All options that may be used with a [HttpHandler](./kibana-plugin-core-public.httphandler.md). | @@ -80,14 +79,12 @@ The plugin integrates with the core system via lifecycle events: `setup` | [I18nStart](./kibana-plugin-core-public.i18nstart.md) | I18nStart.Context is required by any localizable React component from @kbn/i18n and @elastic/eui packages and is supposed to be used as the topmost component for any i18n-compatible React tree. | | [IAnonymousPaths](./kibana-plugin-core-public.ianonymouspaths.md) | APIs for denoting paths as not requiring authentication | | [IBasePath](./kibana-plugin-core-public.ibasepath.md) | APIs for manipulating the basePath on URL segments. | -| [IExecutionContextContainer](./kibana-plugin-core-public.iexecutioncontextcontainer.md) | | | [IExternalUrl](./kibana-plugin-core-public.iexternalurl.md) | APIs for working with external URLs. | | [IExternalUrlPolicy](./kibana-plugin-core-public.iexternalurlpolicy.md) | A policy describing whether access to an external destination is allowed. | | [IHttpFetchError](./kibana-plugin-core-public.ihttpfetcherror.md) | | | [IHttpInterceptController](./kibana-plugin-core-public.ihttpinterceptcontroller.md) | Used to halt a request Promise chain in a [HttpInterceptor](./kibana-plugin-core-public.httpinterceptor.md). | | [IHttpResponseInterceptorOverrides](./kibana-plugin-core-public.ihttpresponseinterceptoroverrides.md) | Properties that can be returned by HttpInterceptor.request to override the response. | | [IUiSettingsClient](./kibana-plugin-core-public.iuisettingsclient.md) | Client-side client that provides access to the advanced settings stored in elasticsearch. The settings provide control over the behavior of the Kibana application. For example, a user can specify how to display numeric or date fields. Users can adjust the settings via Management UI. [IUiSettingsClient](./kibana-plugin-core-public.iuisettingsclient.md) | -| [KibanaExecutionContext](./kibana-plugin-core-public.kibanaexecutioncontext.md) | | | [NavigateToAppOptions](./kibana-plugin-core-public.navigatetoappoptions.md) | Options for the [navigateToApp API](./kibana-plugin-core-public.applicationstart.navigatetoapp.md) | | [NotificationsSetup](./kibana-plugin-core-public.notificationssetup.md) | | | [NotificationsStart](./kibana-plugin-core-public.notificationsstart.md) | | @@ -162,6 +159,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [FatalErrorsStart](./kibana-plugin-core-public.fatalerrorsstart.md) | FatalErrors stop the Kibana Public Core and displays a fatal error screen with details about the Kibana build and the error. | | [HttpStart](./kibana-plugin-core-public.httpstart.md) | See [HttpSetup](./kibana-plugin-core-public.httpsetup.md) | | [IToasts](./kibana-plugin-core-public.itoasts.md) | Methods for adding and removing global toast messages. See [ToastsApi](./kibana-plugin-core-public.toastsapi.md). | +| [KibanaExecutionContext](./kibana-plugin-core-public.kibanaexecutioncontext.md) | Represents a meta-information about a Kibana entity initiating a search request. | | [MountPoint](./kibana-plugin-core-public.mountpoint.md) | A function that should mount DOM content inside the provided container element and return a handler to unmount it. | | [NavType](./kibana-plugin-core-public.navtype.md) | | | [PluginInitializer](./kibana-plugin-core-public.plugininitializer.md) | The plugin export at the root of a plugin's public directory should conform to this interface. | diff --git a/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.get.md b/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.get.md deleted file mode 100644 index d152b9a0c5df29..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.get.md +++ /dev/null @@ -1,17 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ExecutionContextSetup](./kibana-plugin-core-server.executioncontextsetup.md) > [get](./kibana-plugin-core-server.executioncontextsetup.get.md) - -## ExecutionContextSetup.get() method - -Retrieves an opearation meta-data for the current async context. - -Signature: - -```typescript -get(): IExecutionContextContainer | undefined; -``` -Returns: - -`IExecutionContextContainer | undefined` - diff --git a/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.md b/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.md index 137df77769c8dc..24591648ad953b 100644 --- a/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.md +++ b/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.md @@ -15,6 +15,5 @@ export interface ExecutionContextSetup | Method | Description | | --- | --- | -| [get()](./kibana-plugin-core-server.executioncontextsetup.get.md) | Retrieves an opearation meta-data for the current async context. | -| [set(context)](./kibana-plugin-core-server.executioncontextsetup.set.md) | Stores the meta-data of a runtime operation. Data are carried over all async operations automatically. The sequential calls merge provided "context" object shallowly. | +| [withContext(context, fn)](./kibana-plugin-core-server.executioncontextsetup.withcontext.md) | Keeps track of execution context while the passed function is executed. Data are carried over all async operations spawned by the passed function. The nested calls stack the registered context on top of each other. | diff --git a/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.set.md b/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.set.md deleted file mode 100644 index 4c8ba4d21b8c43..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.set.md +++ /dev/null @@ -1,24 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ExecutionContextSetup](./kibana-plugin-core-server.executioncontextsetup.md) > [set](./kibana-plugin-core-server.executioncontextsetup.set.md) - -## ExecutionContextSetup.set() method - -Stores the meta-data of a runtime operation. Data are carried over all async operations automatically. The sequential calls merge provided "context" object shallowly. - -Signature: - -```typescript -set(context: Partial): void; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| context | Partial<KibanaServerExecutionContext> | | - -Returns: - -`void` - diff --git a/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.withcontext.md b/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.withcontext.md new file mode 100644 index 00000000000000..87da0712030185 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.executioncontextsetup.withcontext.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ExecutionContextSetup](./kibana-plugin-core-server.executioncontextsetup.md) > [withContext](./kibana-plugin-core-server.executioncontextsetup.withcontext.md) + +## ExecutionContextSetup.withContext() method + +Keeps track of execution context while the passed function is executed. Data are carried over all async operations spawned by the passed function. The nested calls stack the registered context on top of each other. + +Signature: + +```typescript +withContext(context: KibanaExecutionContext | undefined, fn: (...args: any[]) => R): R; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| context | KibanaExecutionContext | undefined | | +| fn | (...args: any[]) => R | | + +Returns: + +`R` + diff --git a/docs/development/core/server/kibana-plugin-core-server.iexecutioncontextcontainer.tojson.md b/docs/development/core/server/kibana-plugin-core-server.iexecutioncontextcontainer.tojson.md index f67aa88862fee2..6b643f7f72c957 100644 --- a/docs/development/core/server/kibana-plugin-core-server.iexecutioncontextcontainer.tojson.md +++ b/docs/development/core/server/kibana-plugin-core-server.iexecutioncontextcontainer.tojson.md @@ -7,9 +7,9 @@ Signature: ```typescript -toJSON(): Readonly; +toJSON(): Readonly; ``` Returns: -`Readonly` +`Readonly` diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.description.md b/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.description.md deleted file mode 100644 index 00c907b578cf34..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.description.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [KibanaExecutionContext](./kibana-plugin-core-server.kibanaexecutioncontext.md) > [description](./kibana-plugin-core-server.kibanaexecutioncontext.description.md) - -## KibanaExecutionContext.description property - -human readable description. For example, a vis title, action name - -Signature: - -```typescript -readonly description: string; -``` diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.id.md b/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.id.md deleted file mode 100644 index 4ade96691fb146..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.id.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [KibanaExecutionContext](./kibana-plugin-core-server.kibanaexecutioncontext.md) > [id](./kibana-plugin-core-server.kibanaexecutioncontext.id.md) - -## KibanaExecutionContext.id property - -unique value to identify the source - -Signature: - -```typescript -readonly id: string; -``` diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.md b/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.md index c21eb1110ed8e8..db06f9b13f9f60 100644 --- a/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.md +++ b/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.md @@ -2,22 +2,19 @@ [Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [KibanaExecutionContext](./kibana-plugin-core-server.kibanaexecutioncontext.md) -## KibanaExecutionContext interface +## KibanaExecutionContext type +Represents a meta-information about a Kibana entity initiating a search request. Signature: ```typescript -export interface KibanaExecutionContext +export declare type KibanaExecutionContext = { + readonly type: string; + readonly name: string; + readonly id: string; + readonly description: string; + readonly url?: string; + parent?: KibanaExecutionContext; +}; ``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [description](./kibana-plugin-core-server.kibanaexecutioncontext.description.md) | string | human readable description. For example, a vis title, action name | -| [id](./kibana-plugin-core-server.kibanaexecutioncontext.id.md) | string | unique value to identify the source | -| [name](./kibana-plugin-core-server.kibanaexecutioncontext.name.md) | string | public name of a user-facing feature | -| [type](./kibana-plugin-core-server.kibanaexecutioncontext.type.md) | string | Kibana application initated an operation. | -| [url](./kibana-plugin-core-server.kibanaexecutioncontext.url.md) | string | in browser - url to navigate to a current page, on server - endpoint path, for task: task SO url | - diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.name.md b/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.name.md deleted file mode 100644 index 92f58c01bcc112..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.name.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [KibanaExecutionContext](./kibana-plugin-core-server.kibanaexecutioncontext.md) > [name](./kibana-plugin-core-server.kibanaexecutioncontext.name.md) - -## KibanaExecutionContext.name property - -public name of a user-facing feature - -Signature: - -```typescript -readonly name: string; -``` diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.type.md b/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.type.md deleted file mode 100644 index 6941bb150efdd4..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.type.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [KibanaExecutionContext](./kibana-plugin-core-server.kibanaexecutioncontext.md) > [type](./kibana-plugin-core-server.kibanaexecutioncontext.type.md) - -## KibanaExecutionContext.type property - -Kibana application initated an operation. - -Signature: - -```typescript -readonly type: string; -``` diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.url.md b/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.url.md deleted file mode 100644 index dee241cd793986..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.kibanaexecutioncontext.url.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [KibanaExecutionContext](./kibana-plugin-core-server.kibanaexecutioncontext.md) > [url](./kibana-plugin-core-server.kibanaexecutioncontext.url.md) - -## KibanaExecutionContext.url property - -in browser - url to navigate to a current page, on server - endpoint path, for task: task SO url - -Signature: - -```typescript -readonly url?: string; -``` diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanaserverexecutioncontext.md b/docs/development/core/server/kibana-plugin-core-server.kibanaserverexecutioncontext.md deleted file mode 100644 index f309e4fd0006c3..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.kibanaserverexecutioncontext.md +++ /dev/null @@ -1,19 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [KibanaServerExecutionContext](./kibana-plugin-core-server.kibanaserverexecutioncontext.md) - -## KibanaServerExecutionContext interface - - -Signature: - -```typescript -export interface KibanaServerExecutionContext extends Partial -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [requestId](./kibana-plugin-core-server.kibanaserverexecutioncontext.requestid.md) | string | | - diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanaserverexecutioncontext.requestid.md b/docs/development/core/server/kibana-plugin-core-server.kibanaserverexecutioncontext.requestid.md deleted file mode 100644 index dff3fd7f2e9ff9..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.kibanaserverexecutioncontext.requestid.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [KibanaServerExecutionContext](./kibana-plugin-core-server.kibanaserverexecutioncontext.md) > [requestId](./kibana-plugin-core-server.kibanaserverexecutioncontext.requestid.md) - -## KibanaServerExecutionContext.requestId property - -Signature: - -```typescript -requestId: string; -``` diff --git a/docs/development/core/server/kibana-plugin-core-server.md b/docs/development/core/server/kibana-plugin-core-server.md index a3f925151af61a..c459a48c1ca420 100644 --- a/docs/development/core/server/kibana-plugin-core-server.md +++ b/docs/development/core/server/kibana-plugin-core-server.md @@ -110,10 +110,8 @@ The plugin integrates with the core system via lifecycle events: `setup` | [ISavedObjectsPointInTimeFinder](./kibana-plugin-core-server.isavedobjectspointintimefinder.md) | | | [IScopedClusterClient](./kibana-plugin-core-server.iscopedclusterclient.md) | Serves the same purpose as the normal [cluster client](./kibana-plugin-core-server.iclusterclient.md) but exposes an additional asCurrentUser method that doesn't use credentials of the Kibana internal user (as asInternalUser does) to request Elasticsearch API, but rather passes HTTP headers extracted from the current user request to the API instead. | | [IUiSettingsClient](./kibana-plugin-core-server.iuisettingsclient.md) | Server-side client that provides access to the advanced settings stored in elasticsearch. The settings provide control over the behavior of the Kibana application. For example, a user can specify how to display numeric or date fields. Users can adjust the settings via Management UI. | -| [KibanaExecutionContext](./kibana-plugin-core-server.kibanaexecutioncontext.md) | | | [KibanaRequestEvents](./kibana-plugin-core-server.kibanarequestevents.md) | Request events. | | [KibanaRequestRoute](./kibana-plugin-core-server.kibanarequestroute.md) | Request specific route information exposed to a handler. | -| [KibanaServerExecutionContext](./kibana-plugin-core-server.kibanaserverexecutioncontext.md) | | | [LegacyAPICaller](./kibana-plugin-core-server.legacyapicaller.md) | | | [LegacyCallAPIOptions](./kibana-plugin-core-server.legacycallapioptions.md) | The set of options that defines how API call should be made and result be processed. | | [LegacyElasticsearchError](./kibana-plugin-core-server.legacyelasticsearcherror.md) | @deprecated. The new elasticsearch client doesn't wrap errors anymore. 7.16 | @@ -279,6 +277,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [ISavedObjectsImporter](./kibana-plugin-core-server.isavedobjectsimporter.md) | | | [ISavedObjectsRepository](./kibana-plugin-core-server.isavedobjectsrepository.md) | See [SavedObjectsRepository](./kibana-plugin-core-server.savedobjectsrepository.md) | | [ISavedObjectTypeRegistry](./kibana-plugin-core-server.isavedobjecttyperegistry.md) | See [SavedObjectTypeRegistry](./kibana-plugin-core-server.savedobjecttyperegistry.md) for documentation. | +| [KibanaExecutionContext](./kibana-plugin-core-server.kibanaexecutioncontext.md) | Represents a meta-information about a Kibana entity initiating a search request. | | [KibanaRequestRouteOptions](./kibana-plugin-core-server.kibanarequestrouteoptions.md) | Route options: If 'GET' or 'OPTIONS' method, body options won't be returned. | | [KibanaResponseFactory](./kibana-plugin-core-server.kibanaresponsefactory.md) | Creates an object containing request response payload, HTTP headers, error details, and other data transmitted to the client. | | [KnownHeaders](./kibana-plugin-core-server.knownheaders.md) | Set of well-known HTTP headers. | diff --git a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddableinput.md b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddableinput.md index 07ede291e33d2b..729cc23dac5017 100644 --- a/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddableinput.md +++ b/docs/development/plugins/embeddable/public/kibana-plugin-plugins-embeddable-public.embeddableinput.md @@ -18,5 +18,6 @@ export declare type EmbeddableInput = { disableTriggers?: boolean; searchSessionId?: string; syncColors?: boolean; + executionContext?: KibanaExecutionContext; }; ``` diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.executioncontext.getexecutioncontext.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.executioncontext.getexecutioncontext.md index bfe1925a21f68a..bc27adbed1d9a7 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.executioncontext.getexecutioncontext.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.executioncontext.getexecutioncontext.md @@ -9,5 +9,5 @@ Contains the meta-data about the source of the expression. Signature: ```typescript -getExecutionContext: () => IExecutionContextContainer | undefined; +getExecutionContext: () => KibanaExecutionContext | undefined; ``` diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.executioncontext.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.executioncontext.md index 38165a16833169..1fd926f1a0c074 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.executioncontext.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.executioncontext.md @@ -17,7 +17,7 @@ export interface ExecutionContextAbortSignal | Adds ability to abort current execution. | -| [getExecutionContext](./kibana-plugin-plugins-expressions-public.executioncontext.getexecutioncontext.md) | () => IExecutionContextContainer | undefined | Contains the meta-data about the source of the expression. | +| [getExecutionContext](./kibana-plugin-plugins-expressions-public.executioncontext.getexecutioncontext.md) | () => KibanaExecutionContext | undefined | Contains the meta-data about the source of the expression. | | [getKibanaRequest](./kibana-plugin-plugins-expressions-public.executioncontext.getkibanarequest.md) | () => KibanaRequest | Getter to retrieve the KibanaRequest object inside an expression function. Useful for functions which are running on the server and need to perform operations that are scoped to a specific user. | | [getSearchContext](./kibana-plugin-plugins-expressions-public.executioncontext.getsearchcontext.md) | () => ExecutionContextSearch | Get search context of the expression. | | [getSearchSessionId](./kibana-plugin-plugins-expressions-public.executioncontext.getsearchsessionid.md) | () => string | undefined | Search context in which expression should operate. | diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.executioncontext.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.executioncontext.md index 504f5e2df7d6ec..c133621424b5fc 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.executioncontext.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.executioncontext.md @@ -7,5 +7,5 @@ Signature: ```typescript -executionContext?: IExecutionContextContainer; +executionContext?: KibanaExecutionContext; ``` diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.md index a228628fece0fd..69ecd229b5aa60 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.md @@ -19,7 +19,7 @@ export interface IExpressionLoaderParams | [customRenderers](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.customrenderers.md) | [] | | | [debug](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.debug.md) | boolean | | | [disableCaching](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.disablecaching.md) | boolean | | -| [executionContext](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.executioncontext.md) | IExecutionContextContainer | | +| [executionContext](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.executioncontext.md) | KibanaExecutionContext | | | [hasCompatibleActions](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.hascompatibleactions.md) | ExpressionRenderHandlerParams['hasCompatibleActions'] | | | [inspectorAdapters](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.inspectoradapters.md) | Adapters | | | [onRenderError](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.onrendererror.md) | RenderErrorHandlerFnType | | diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.executioncontext.getexecutioncontext.md b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.executioncontext.getexecutioncontext.md index b4ceb8f96d698b..b692ee1611f970 100644 --- a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.executioncontext.getexecutioncontext.md +++ b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.executioncontext.getexecutioncontext.md @@ -9,5 +9,5 @@ Contains the meta-data about the source of the expression. Signature: ```typescript -getExecutionContext: () => IExecutionContextContainer | undefined; +getExecutionContext: () => KibanaExecutionContext | undefined; ``` diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.executioncontext.md b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.executioncontext.md index 3b308ca46ab0ae..5958853d10903e 100644 --- a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.executioncontext.md +++ b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.executioncontext.md @@ -17,7 +17,7 @@ export interface ExecutionContextAbortSignal | Adds ability to abort current execution. | -| [getExecutionContext](./kibana-plugin-plugins-expressions-server.executioncontext.getexecutioncontext.md) | () => IExecutionContextContainer | undefined | Contains the meta-data about the source of the expression. | +| [getExecutionContext](./kibana-plugin-plugins-expressions-server.executioncontext.getexecutioncontext.md) | () => KibanaExecutionContext | undefined | Contains the meta-data about the source of the expression. | | [getKibanaRequest](./kibana-plugin-plugins-expressions-server.executioncontext.getkibanarequest.md) | () => KibanaRequest | Getter to retrieve the KibanaRequest object inside an expression function. Useful for functions which are running on the server and need to perform operations that are scoped to a specific user. | | [getSearchContext](./kibana-plugin-plugins-expressions-server.executioncontext.getsearchcontext.md) | () => ExecutionContextSearch | Get search context of the expression. | | [getSearchSessionId](./kibana-plugin-plugins-expressions-server.executioncontext.getsearchsessionid.md) | () => string | undefined | Search context in which expression should operate. | diff --git a/src/core/public/core_system.test.mocks.ts b/src/core/public/core_system.test.mocks.ts index c80c2e3f497750..afb8aec31cccd8 100644 --- a/src/core/public/core_system.test.mocks.ts +++ b/src/core/public/core_system.test.mocks.ts @@ -19,7 +19,6 @@ import { uiSettingsServiceMock } from './ui_settings/ui_settings_service.mock'; import { docLinksServiceMock } from './doc_links/doc_links_service.mock'; import { renderingServiceMock } from './rendering/rendering_service.mock'; import { integrationsServiceMock } from './integrations/integrations_service.mock'; -import { executionContextServiceMock } from './execution_context/execution_context_service.mock'; import { coreAppMock } from './core_app/core_app.mock'; export const MockInjectedMetadataService = injectedMetadataServiceMock.create(); @@ -112,14 +111,6 @@ jest.doMock('./integrations', () => ({ IntegrationsService: IntegrationsServiceConstructor, })); -export const MockExecutionContextService = executionContextServiceMock.create(); -export const ExecutionContextServiceConstructor = jest - .fn() - .mockImplementation(() => MockExecutionContextService); -jest.doMock('./execution_context', () => ({ - ExecutionContextService: ExecutionContextServiceConstructor, -})); - export const MockCoreApp = coreAppMock.create(); export const CoreAppConstructor = jest.fn().mockImplementation(() => MockCoreApp); jest.doMock('./core_app', () => ({ diff --git a/src/core/public/core_system.test.ts b/src/core/public/core_system.test.ts index efafb25da27ee1..8ead0f50785bdc 100644 --- a/src/core/public/core_system.test.ts +++ b/src/core/public/core_system.test.ts @@ -30,7 +30,6 @@ import { RenderingServiceConstructor, IntegrationsServiceConstructor, MockIntegrationsService, - MockExecutionContextService, CoreAppConstructor, MockCoreApp, } from './core_system.test.mocks'; @@ -183,11 +182,6 @@ describe('#setup()', () => { await setupCore(); expect(MockCoreApp.setup).toHaveBeenCalledTimes(1); }); - - it('calls executionContext.setup()', async () => { - await setupCore(); - expect(MockExecutionContextService.setup).toHaveBeenCalledTimes(1); - }); }); describe('#start()', () => { @@ -275,11 +269,6 @@ describe('#start()', () => { await startCore(); expect(MockCoreApp.start).toHaveBeenCalledTimes(1); }); - - it('calls executionContext.start()', async () => { - await startCore(); - expect(MockExecutionContextService.start).toHaveBeenCalledTimes(1); - }); }); describe('#stop()', () => { @@ -338,14 +327,6 @@ describe('#stop()', () => { expect(MockCoreApp.stop).toHaveBeenCalled(); }); - it('calls executionContext.stop()', () => { - const coreSystem = createCoreSystem(); - - expect(MockExecutionContextService.stop).not.toHaveBeenCalled(); - coreSystem.stop(); - expect(MockExecutionContextService.stop).toHaveBeenCalled(); - }); - it('clears the rootDomElement', async () => { const rootDomElement = document.createElement('div'); const coreSystem = createCoreSystem({ diff --git a/src/core/public/core_system.ts b/src/core/public/core_system.ts index 43e7d443f5c00e..e5dcd8f817a0a9 100644 --- a/src/core/public/core_system.ts +++ b/src/core/public/core_system.ts @@ -29,7 +29,6 @@ import { SavedObjectsService } from './saved_objects'; import { IntegrationsService } from './integrations'; import { DeprecationsService } from './deprecations'; import { CoreApp } from './core_app'; -import { ExecutionContextService } from './execution_context'; import type { InternalApplicationSetup, InternalApplicationStart } from './application/types'; interface Params { @@ -84,7 +83,6 @@ export class CoreSystem { private readonly integrations: IntegrationsService; private readonly coreApp: CoreApp; private readonly deprecations: DeprecationsService; - private readonly executionContext: ExecutionContextService; private readonly rootDomElement: HTMLElement; private readonly coreContext: CoreContext; private fatalErrorsSetup: FatalErrorsSetup | null = null; @@ -120,7 +118,6 @@ export class CoreSystem { this.application = new ApplicationService(); this.integrations = new IntegrationsService(); this.deprecations = new DeprecationsService(); - this.executionContext = new ExecutionContextService(); this.plugins = new PluginsService(this.coreContext, injectedMetadata.uiPlugins); this.coreApp = new CoreApp(this.coreContext); @@ -140,7 +137,6 @@ export class CoreSystem { const http = this.http.setup({ injectedMetadata, fatalErrors: this.fatalErrorsSetup }); const uiSettings = this.uiSettings.setup({ http, injectedMetadata }); const notifications = this.notifications.setup({ uiSettings }); - this.executionContext.setup(); const application = this.application.setup({ http }); this.coreApp.setup({ application, http, injectedMetadata, notifications }); @@ -205,7 +201,6 @@ export class CoreSystem { notifications, }); const deprecations = this.deprecations.start({ http }); - const executionContext = this.executionContext.start(); this.coreApp.start({ application, docLinks, http, notifications, uiSettings }); @@ -222,7 +217,6 @@ export class CoreSystem { uiSettings, fatalErrors, deprecations, - executionContext, }; await this.plugins.start(core); @@ -266,7 +260,6 @@ export class CoreSystem { this.i18n.stop(); this.application.stop(); this.deprecations.stop(); - this.executionContext.stop(); this.rootDomElement.textContent = ''; } } diff --git a/src/core/public/execution_context/execution_context_container.test.ts b/src/core/public/execution_context/execution_context_container.test.ts index a4ee355ab40a4c..5e4e34d102e5b5 100644 --- a/src/core/public/execution_context/execution_context_container.test.ts +++ b/src/core/public/execution_context/execution_context_container.test.ts @@ -29,6 +29,30 @@ describe('KibanaExecutionContext', () => { `); }); + it('includes a parent context to string representation', () => { + const parentContext: KibanaExecutionContext = { + type: 'parent-type', + name: 'parent-name', + id: '41', + description: 'parent-descripton', + }; + + const context: KibanaExecutionContext = { + type: 'test-type', + name: 'test-name', + id: '42', + description: 'test-descripton', + parent: parentContext, + }; + + const value = new ExecutionContextContainer(context).toHeader(); + expect(value).toMatchInlineSnapshot(` + Object { + "x-kbn-context": "%7B%22type%22%3A%22test-type%22%2C%22name%22%3A%22test-name%22%2C%22id%22%3A%2242%22%2C%22description%22%3A%22test-descripton%22%2C%22parent%22%3A%7B%22type%22%3A%22parent-type%22%2C%22name%22%3A%22parent-name%22%2C%22id%22%3A%2241%22%2C%22description%22%3A%22parent-descripton%22%7D%7D", + } + `); + }); + it('trims a string representation of provided execution context if it is bigger max allowed size', () => { const context: KibanaExecutionContext = { type: 'test-type', @@ -65,4 +89,51 @@ describe('KibanaExecutionContext', () => { `); }); }); + describe('toJSON', () => { + it('returns JSON representation of the context', () => { + const context: KibanaExecutionContext = { + type: 'test-type', + name: 'test-name', + id: '42', + description: 'test-descripton', + }; + + const value = new ExecutionContextContainer(context).toJSON(); + expect(value).toEqual(context); + }); + + it('returns JSON representation when the parent context if provided', () => { + const parentAContext: KibanaExecutionContext = { + type: 'parent-a-type', + name: 'parent-a-name', + id: '40', + description: 'parent-a-descripton', + }; + + const parentBContext: KibanaExecutionContext = { + type: 'parent-b-type', + name: 'parent-b-name', + id: '41', + description: 'parent-b-descripton', + parent: parentAContext, + }; + + const context: KibanaExecutionContext = { + type: 'test-type', + name: 'test-name', + id: '42', + description: 'test-descripton', + parent: parentBContext, + }; + + const value = new ExecutionContextContainer(context).toJSON(); + expect(value).toEqual({ + ...context, + parent: { + ...parentBContext, + parent: parentAContext, + }, + }); + }); + }); }); diff --git a/src/core/public/execution_context/execution_context_service.mock.ts b/src/core/public/execution_context/execution_context_service.mock.ts deleted file mode 100644 index 071e61f17c25cb..00000000000000 --- a/src/core/public/execution_context/execution_context_service.mock.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { PublicMethodsOf } from '@kbn/utility-types'; -import type { Plugin } from 'src/core/public'; -import type { ExecutionContextServiceStart } from './execution_context_service'; -import type { ExecutionContextContainer } from './execution_context_container'; - -const createContainerMock = () => { - const mock: jest.Mocked> = { - toHeader: jest.fn(), - toJSON: jest.fn(), - }; - return mock; -}; -const createStartContractMock = () => { - const mock: jest.Mocked = { - create: jest.fn().mockReturnValue(createContainerMock()), - }; - return mock; -}; - -const createMock = (): jest.Mocked => ({ - setup: jest.fn(), - start: jest.fn(), - stop: jest.fn(), -}); - -export const executionContextServiceMock = { - create: createMock, - createStartContract: createStartContractMock, - createContainer: createContainerMock, -}; diff --git a/src/core/public/execution_context/execution_context_service.ts b/src/core/public/execution_context/execution_context_service.ts deleted file mode 100644 index 934e68d15be04d..00000000000000 --- a/src/core/public/execution_context/execution_context_service.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 { CoreService, KibanaExecutionContext } from '../../types'; -import { - ExecutionContextContainer, - IExecutionContextContainer, -} from './execution_context_container'; - -/** - * @public - */ -export interface ExecutionContextServiceStart { - /** - * Creates a context container carrying the meta-data of a runtime operation. - * Provided meta-data will be propagated to Kibana and Elasticsearch servers. - * ```js - * const context = executionContext.create(...); - * http.fetch('/endpoint/', { context }); - * ``` - */ - create: (context: KibanaExecutionContext) => IExecutionContextContainer; -} - -export class ExecutionContextService implements CoreService { - setup() {} - start(): ExecutionContextServiceStart { - return { - create(context: KibanaExecutionContext) { - return new ExecutionContextContainer(context); - }, - }; - } - stop() {} -} diff --git a/src/core/public/execution_context/index.ts b/src/core/public/execution_context/index.ts index d0c8348d864e79..b15a967ac714aa 100644 --- a/src/core/public/execution_context/index.ts +++ b/src/core/public/execution_context/index.ts @@ -7,6 +7,4 @@ */ export type { KibanaExecutionContext } from '../../types'; -export { ExecutionContextService } from './execution_context_service'; -export type { ExecutionContextServiceStart } from './execution_context_service'; -export type { IExecutionContextContainer } from './execution_context_container'; +export { ExecutionContextContainer } from './execution_context_container'; diff --git a/src/core/public/http/fetch.test.ts b/src/core/public/http/fetch.test.ts index 67ec816d084307..7e3cd9019b08d4 100644 --- a/src/core/public/http/fetch.test.ts +++ b/src/core/public/http/fetch.test.ts @@ -15,7 +15,6 @@ import { first } from 'rxjs/operators'; import { Fetch } from './fetch'; import { BasePath } from './base_path'; import { HttpResponse, HttpFetchOptionsWithPath } from './types'; -import { executionContextServiceMock } from '../execution_context/execution_context_service.mock'; function delay(duration: number) { return new Promise((r) => setTimeout(r, duration)); @@ -230,14 +229,19 @@ describe('Fetch', () => { it('should inject context headers if provided', async () => { fetchMock.get('*', {}); - const executionContainerMock = executionContextServiceMock.createContainer(); - executionContainerMock.toHeader.mockReturnValueOnce({ 'x-kbn-context': 'value' }); + await fetchInstance.fetch('/my/path', { - context: executionContainerMock, + context: { + type: 'test-type', + name: 'test-name', + description: 'test-description', + id: '42', + }, }); expect(fetchMock.lastOptions()!.headers).toMatchObject({ - 'x-kbn-context': 'value', + 'x-kbn-context': + '%7B%22type%22%3A%22test-type%22%2C%22name%22%3A%22test-name%22%2C%22description%22%3A%22test-description%22%2C%22id%22%3A%2242%22%7D', }); }); diff --git a/src/core/public/http/fetch.ts b/src/core/public/http/fetch.ts index fb178a937e18ab..372445b2b09028 100644 --- a/src/core/public/http/fetch.ts +++ b/src/core/public/http/fetch.ts @@ -22,6 +22,7 @@ import { HttpFetchError } from './http_fetch_error'; import { HttpInterceptController } from './http_intercept_controller'; import { interceptRequest, interceptResponse } from './intercept'; import { HttpInterceptHaltError } from './http_intercept_halt_error'; +import { ExecutionContextContainer } from '../execution_context'; interface Params { basePath: IBasePath; @@ -124,7 +125,7 @@ export class Fetch { 'Content-Type': 'application/json', ...options.headers, 'kbn-version': this.params.kibanaVersion, - ...options.context?.toHeader(), + ...(options.context ? new ExecutionContextContainer(options.context).toHeader() : {}), }), }; diff --git a/src/core/public/http/types.ts b/src/core/public/http/types.ts index ccf68201bc207a..3eb718b318f86d 100644 --- a/src/core/public/http/types.ts +++ b/src/core/public/http/types.ts @@ -8,7 +8,7 @@ import { Observable } from 'rxjs'; import { MaybePromise } from '@kbn/utility-types'; -import type { IExecutionContextContainer } from '../execution_context'; +import type { KibanaExecutionContext } from '../execution_context'; /** @public */ export interface HttpSetup { @@ -272,7 +272,7 @@ export interface HttpFetchOptions extends HttpRequestInit { */ asResponse?: boolean; - context?: IExecutionContextContainer; + context?: KibanaExecutionContext; } /** diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 40304d27580ca8..e6e64332918733 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -65,7 +65,6 @@ import { ApplicationSetup, Capabilities, ApplicationStart } from './application' import { DocLinksStart } from './doc_links'; import { SavedObjectsStart } from './saved_objects'; import { DeprecationsServiceStart } from './deprecations'; -import type { ExecutionContextServiceStart } from './execution_context'; export type { PackageInfo, @@ -186,8 +185,6 @@ export type { export type { DeprecationsServiceStart, ResolveDeprecationResponse } from './deprecations'; -export type { IExecutionContextContainer, ExecutionContextServiceStart } from './execution_context'; - export type { MountPoint, UnmountCallback, PublicUiSettingsParams } from './types'; export { URL_MAX_LENGTH } from './core_app'; @@ -276,8 +273,6 @@ export interface CoreStart { fatalErrors: FatalErrorsStart; /** {@link DeprecationsServiceStart} */ deprecations: DeprecationsServiceStart; - /** {@link ExecutionContextServiceStart} */ - executionContext: ExecutionContextServiceStart; /** * exposed temporarily until https://github.com/elastic/kibana/issues/41990 done * use *only* to retrieve config values. There is no way to set injected values diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts index 63b94ea4ac4e35..bd7623beba651e 100644 --- a/src/core/public/mocks.ts +++ b/src/core/public/mocks.ts @@ -25,7 +25,6 @@ import { uiSettingsServiceMock } from './ui_settings/ui_settings_service.mock'; import { savedObjectsServiceMock } from './saved_objects/saved_objects_service.mock'; import { injectedMetadataServiceMock } from './injected_metadata/injected_metadata_service.mock'; import { deprecationsServiceMock } from './deprecations/deprecations_service.mock'; -import { executionContextServiceMock } from './execution_context/execution_context_service.mock'; export { chromeServiceMock } from './chrome/chrome_service.mock'; export { docLinksServiceMock } from './doc_links/doc_links_service.mock'; @@ -40,7 +39,6 @@ export { savedObjectsServiceMock } from './saved_objects/saved_objects_service.m export { scopedHistoryMock } from './application/scoped_history.mock'; export { applicationServiceMock } from './application/application_service.mock'; export { deprecationsServiceMock } from './deprecations/deprecations_service.mock'; -export { executionContextServiceMock } from './execution_context/execution_context_service.mock'; function createCoreSetupMock({ basePath = '', @@ -86,7 +84,6 @@ function createCoreStartMock({ basePath = '' } = {}) { getInjectedVar: injectedMetadataServiceMock.createStartContract().getInjectedVar, }, fatalErrors: fatalErrorsServiceMock.createStartContract(), - executionContext: executionContextServiceMock.createStartContract(), }; return mock; diff --git a/src/core/public/plugins/plugin_context.ts b/src/core/public/plugins/plugin_context.ts index be3cff54aca8e9..49c895aa80fc40 100644 --- a/src/core/public/plugins/plugin_context.ts +++ b/src/core/public/plugins/plugin_context.ts @@ -140,6 +140,5 @@ export function createPluginStartContext< }, fatalErrors: deps.fatalErrors, deprecations: deps.deprecations, - executionContext: deps.executionContext, }; } diff --git a/src/core/public/plugins/plugins_service.test.ts b/src/core/public/plugins/plugins_service.test.ts index 3f23889c57de6f..06c72823c7752d 100644 --- a/src/core/public/plugins/plugins_service.test.ts +++ b/src/core/public/plugins/plugins_service.test.ts @@ -35,7 +35,6 @@ import { CoreSetup, CoreStart, PluginInitializerContext } from '..'; import { docLinksServiceMock } from '../doc_links/doc_links_service.mock'; import { savedObjectsServiceMock } from '../saved_objects/saved_objects_service.mock'; import { deprecationsServiceMock } from '../deprecations/deprecations_service.mock'; -import { executionContextServiceMock } from '../execution_context/execution_context_service.mock'; export let mockPluginInitializers: Map; @@ -105,7 +104,6 @@ describe('PluginsService', () => { savedObjects: savedObjectsServiceMock.createStartContract(), fatalErrors: fatalErrorsServiceMock.createStartContract(), deprecations: deprecationsServiceMock.createStartContract(), - executionContext: executionContextServiceMock.createStartContract(), }; mockStartContext = { ...mockStartDeps, diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 80fd3927e05a36..9de10c3c885347 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -433,8 +433,6 @@ export interface CoreStart { // (undocumented) docLinks: DocLinksStart; // (undocumented) - executionContext: ExecutionContextServiceStart; - // (undocumented) fatalErrors: FatalErrorsStart; // (undocumented) http: HttpStart; @@ -717,11 +715,6 @@ export interface ErrorToastOptions extends ToastOptions { toastMessage?: string; } -// @public (undocumented) -export interface ExecutionContextServiceStart { - create: (context: KibanaExecutionContext) => IExecutionContextContainer; -} - // @public export interface FatalErrorInfo { // (undocumented) @@ -761,7 +754,7 @@ export interface HttpFetchOptions extends HttpRequestInit { asResponse?: boolean; asSystemRequest?: boolean; // (undocumented) - context?: IExecutionContextContainer; + context?: KibanaExecutionContext; headers?: HttpHeadersInit; prependBasePath?: boolean; query?: HttpFetchQuery; @@ -897,14 +890,6 @@ export interface IBasePath { readonly serverBasePath: string; } -// @public (undocumented) -export interface IExecutionContextContainer { - // (undocumented) - toHeader: () => Record; - // (undocumented) - toJSON: () => Readonly; -} - // @public export interface IExternalUrl { validateUrl(relativeOrAbsoluteUrl: string): URL | null; @@ -967,14 +952,15 @@ export interface IUiSettingsClient { set: (key: string, value: any) => Promise; } -// @public (undocumented) -export interface KibanaExecutionContext { - readonly description: string; - readonly id: string; - readonly name: string; +// @public +export type KibanaExecutionContext = { readonly type: string; + readonly name: string; + readonly id: string; + readonly description: string; readonly url?: string; -} + parent?: KibanaExecutionContext; +}; // @public export type MountPoint = (element: T) => UnmountCallback; @@ -1692,6 +1678,6 @@ export interface UserProvidedValues { // Warnings were encountered during analysis: // -// src/core/public/core_system.ts:172:21 - (ae-forgotten-export) The symbol "InternalApplicationStart" needs to be exported by the entry point index.d.ts +// src/core/public/core_system.ts:168:21 - (ae-forgotten-export) The symbol "InternalApplicationStart" needs to be exported by the entry point index.d.ts ``` diff --git a/src/core/server/elasticsearch/client/cluster_client.ts b/src/core/server/elasticsearch/client/cluster_client.ts index d164736cead071..f81b6518430138 100644 --- a/src/core/server/elasticsearch/client/cluster_client.ts +++ b/src/core/server/elasticsearch/client/cluster_client.ts @@ -10,7 +10,6 @@ import { Client } from '@elastic/elasticsearch'; import { Logger } from '../../logging'; import { GetAuthHeaders, Headers, isKibanaRequest, isRealRequest } from '../../http'; import { ensureRawRequest, filterHeaders } from '../../http/router'; -import type { IExecutionContextContainer } from '../../execution_context'; import { ScopeableRequest } from '../types'; import { ElasticsearchClient } from './types'; import { configureClient } from './configure_client'; @@ -64,7 +63,7 @@ export class ClusterClient implements ICustomClusterClient { logger: Logger, type: string, private readonly getAuthHeaders: GetAuthHeaders = noop, - getExecutionContext: () => IExecutionContextContainer | undefined = noop + getExecutionContext: () => string | undefined = noop ) { this.asInternalUser = configureClient(config, { logger, type, getExecutionContext }); this.rootScopedClient = configureClient(config, { diff --git a/src/core/server/elasticsearch/client/configure_client.ts b/src/core/server/elasticsearch/client/configure_client.ts index f2953862c25e0f..3c32dd2cfd4f4f 100644 --- a/src/core/server/elasticsearch/client/configure_client.ts +++ b/src/core/server/elasticsearch/client/configure_client.ts @@ -14,7 +14,6 @@ import type { TransportRequestParams, TransportRequestOptions, } from '@elastic/elasticsearch/lib/Transport'; -import type { IExecutionContextContainer } from '../../execution_context'; import { Logger } from '../../logging'; import { parseClientOptions, ElasticsearchClientConfig } from './client_config'; @@ -31,14 +30,14 @@ export const configureClient = ( logger: Logger; type: string; scoped?: boolean; - getExecutionContext?: () => IExecutionContextContainer | undefined; + getExecutionContext?: () => string | undefined; } ): Client => { const clientOptions = parseClientOptions(config, scoped); class KibanaTransport extends Transport { request(params: TransportRequestParams, options?: TransportRequestOptions) { const opts = options || {}; - const opaqueId = getExecutionContext()?.toString(); + const opaqueId = getExecutionContext(); if (opaqueId && !opts.opaqueId) { // rewrites headers['x-opaque-id'] if it presents opts.opaqueId = opaqueId; diff --git a/src/core/server/elasticsearch/elasticsearch_service.ts b/src/core/server/elasticsearch/elasticsearch_service.ts index f983a8b77fe085..acd2204334c0e9 100644 --- a/src/core/server/elasticsearch/elasticsearch_service.ts +++ b/src/core/server/elasticsearch/elasticsearch_service.ts @@ -149,7 +149,7 @@ export class ElasticsearchService this.coreContext.logger.get('elasticsearch'), type, this.getAuthHeaders, - () => this.executionContextClient?.get() + () => this.executionContextClient?.getAsHeader() ); } diff --git a/src/core/server/execution_context/execution_context_container.test.ts b/src/core/server/execution_context/execution_context_container.test.ts index e8408d37f40f43..41095815a6b44b 100644 --- a/src/core/server/execution_context/execution_context_container.test.ts +++ b/src/core/server/execution_context/execution_context_container.test.ts @@ -5,7 +5,8 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { KibanaServerExecutionContext } from './execution_context_service'; +import type { KibanaExecutionContext } from '../../types'; + import { ExecutionContextContainer, getParentContextFrom, @@ -14,52 +15,80 @@ import { } from './execution_context_container'; describe('KibanaExecutionContext', () => { + describe('constructor', () => { + it('allows context to define parent explicitly', () => { + const parentContext: KibanaExecutionContext = { + type: 'parent-type', + name: 'parent-name', + id: '44', + description: 'parent-descripton', + }; + const parentContainer = new ExecutionContextContainer(parentContext); + + const context: KibanaExecutionContext = { + type: 'test-type', + name: 'test-name', + id: '42', + description: 'test-descripton', + parent: { + type: 'custom-parent-type', + name: 'custom-parent-name', + id: '41', + description: 'custom-parent-descripton', + }, + }; + + const value = new ExecutionContextContainer(context, parentContainer).toJSON(); + expect(value).toEqual(context); + }); + }); + describe('toString', () => { it('returns a string representation of provided execution context', () => { - const context: KibanaServerExecutionContext = { + const context: KibanaExecutionContext = { type: 'test-type', name: 'test-name', id: '42', description: 'test-descripton', - requestId: '1234-5678', }; const value = new ExecutionContextContainer(context).toString(); - expect(value).toMatchInlineSnapshot(`"1234-5678;kibana:test-type:test-name:42"`); + expect(value).toBe('test-type:test-name:42'); }); - it('returns a limited representation if optional properties are omitted', () => { - const context: KibanaServerExecutionContext = { - requestId: '1234-5678', + it('includes a parent context to string representation', () => { + const parentContext: KibanaExecutionContext = { + type: 'parent-type', + name: 'parent-name', + id: '41', + description: 'parent-descripton', }; + const parentContainer = new ExecutionContextContainer(parentContext); - const value = new ExecutionContextContainer(context).toString(); - expect(value).toMatchInlineSnapshot(`"1234-5678"`); + const context: KibanaExecutionContext = { + type: 'test-type', + name: 'test-name', + id: '42', + description: 'test-descripton', + }; + + const value = new ExecutionContextContainer(context, parentContainer).toString(); + expect(value).toBe('parent-type:parent-name:41;test-type:test-name:42'); }); it('returns an escaped string representation of provided execution contextStringified', () => { - const context: KibanaServerExecutionContext = { + const context: KibanaExecutionContext = { id: 'Visualization☺漢字', type: 'test-type', name: 'test-name', - requestId: '1234-5678', + description: 'test-description', }; const value = new ExecutionContextContainer(context).toString(); - expect(value).toMatchInlineSnapshot( - `"1234-5678;kibana:test-type:test-name:Visualization%E2%98%BA%E6%BC%A2%E5%AD%97"` - ); + expect(value).toBe('test-type:test-name:Visualization%E2%98%BA%E6%BC%A2%E5%AD%97'); }); it('trims a string representation of provided execution context if it is bigger max allowed size', () => { - expect( - new Blob([ - new ExecutionContextContainer({ - requestId: '1234-5678'.repeat(1000), - }).toString(), - ]).size - ).toBeLessThanOrEqual(BAGGAGE_MAX_PER_NAME_VALUE_PAIRS); - expect( new Blob([ new ExecutionContextContainer({ @@ -67,7 +96,6 @@ describe('KibanaExecutionContext', () => { name: 'test-name', id: '42'.repeat(1000), description: 'test-descripton', - requestId: '1234-5678', }).toString(), ]).size ).toBeLessThanOrEqual(BAGGAGE_MAX_PER_NAME_VALUE_PAIRS); @@ -76,16 +104,35 @@ describe('KibanaExecutionContext', () => { describe('toJSON', () => { it('returns a context object', () => { - const context: KibanaServerExecutionContext = { + const context: KibanaExecutionContext = { type: 'test-type', name: 'test-name', id: '42', description: 'test-descripton', - requestId: '1234-5678', }; const value = new ExecutionContextContainer(context).toJSON(); - expect(value).toBe(context); + expect(value).toEqual(context); + }); + + it('returns a context object with registed parent object', () => { + const parentContext: KibanaExecutionContext = { + type: 'parent-type', + name: 'parent-name', + id: '41', + description: 'parent-descripton', + }; + const parentContainer = new ExecutionContextContainer(parentContext); + + const context: KibanaExecutionContext = { + type: 'test-type', + name: 'test-name', + id: '42', + description: 'test-descripton', + }; + + const value = new ExecutionContextContainer(context, parentContainer).toJSON(); + expect(value).toEqual({ ...context, parent: parentContext }); }); }); }); @@ -97,7 +144,7 @@ describe('getParentContextFrom', () => { expect(getParentContextFrom({ [BAGGAGE_HEADER]: header })).toEqual(ctx); }); - it('does not throw an exception if given not a valid value', () => { + it('does not throw an exception if given not a valid JSON object', () => { expect(getParentContextFrom({ [BAGGAGE_HEADER]: 'value' })).toBeUndefined(); expect(getParentContextFrom({ [BAGGAGE_HEADER]: '' })).toBeUndefined(); expect(getParentContextFrom({})).toBeUndefined(); diff --git a/src/core/server/execution_context/execution_context_container.ts b/src/core/server/execution_context/execution_context_container.ts index 6c4a5606df152b..a81c409ab3e9e6 100644 --- a/src/core/server/execution_context/execution_context_container.ts +++ b/src/core/server/execution_context/execution_context_container.ts @@ -5,7 +5,6 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { KibanaServerExecutionContext } from './execution_context_service'; import type { KibanaExecutionContext } from '../../types'; // Switch to the standard Baggage header. blocked by @@ -47,27 +46,23 @@ function enforceMaxLength(header: string): string { */ export interface IExecutionContextContainer { toString(): string; - toJSON(): Readonly; + toJSON(): Readonly; +} + +function stringify(ctx: KibanaExecutionContext): string { + const stringifiedCtx = `${ctx.type}:${ctx.name}:${encodeURIComponent(ctx.id)}`; + return ctx.parent ? `${stringify(ctx.parent)};${stringifiedCtx}` : stringifiedCtx; } export class ExecutionContextContainer implements IExecutionContextContainer { - readonly #context: Readonly; - constructor(context: Readonly) { - this.#context = context; + readonly #context: Readonly; + constructor(context: KibanaExecutionContext, parent?: IExecutionContextContainer) { + this.#context = { parent: parent?.toJSON(), ...context }; } toString(): string { - const ctx = this.#context; - const contextStringified = - ctx.type && ctx.id && ctx.name - ? // id may contain non-ASCII symbols - `kibana:${encodeURIComponent(ctx.type)}:${encodeURIComponent( - ctx.name - )}:${encodeURIComponent(ctx.id)}` - : ''; - const result = contextStringified ? `${ctx.requestId};${contextStringified}` : ctx.requestId; - return enforceMaxLength(result); + return enforceMaxLength(stringify(this.#context)); } - toJSON(): Readonly { + toJSON() { return this.#context; } } diff --git a/src/core/server/execution_context/execution_context_service.mock.ts b/src/core/server/execution_context/execution_context_service.mock.ts index 657805df273caa..2e31145f6c0ee9 100644 --- a/src/core/server/execution_context/execution_context_service.mock.ts +++ b/src/core/server/execution_context/execution_context_service.mock.ts @@ -15,9 +15,11 @@ import type { const createExecutionContextMock = () => { const mock: jest.Mocked = { set: jest.fn(), - reset: jest.fn(), + setRequestId: jest.fn(), + withContext: jest.fn(), get: jest.fn(), getParentContextFrom: jest.fn(), + getAsHeader: jest.fn(), }; return mock; }; @@ -28,8 +30,7 @@ const createInternalSetupContractMock = () => { const createSetupContractMock = () => { const mock: jest.Mocked = { - set: jest.fn(), - get: jest.fn(), + withContext: jest.fn(), }; return mock; }; diff --git a/src/core/server/execution_context/execution_context_service.test.ts b/src/core/server/execution_context/execution_context_service.test.ts index 0c213429e1951c..3abaa13d11103c 100644 --- a/src/core/server/execution_context/execution_context_service.test.ts +++ b/src/core/server/execution_context/execution_context_service.test.ts @@ -25,97 +25,400 @@ describe('ExecutionContextService', () => { service = new ExecutionContextService(core).setup(); }); - it('sets and gets a value in async context', async () => { - const chainA = Promise.resolve().then(async () => { - service.set({ - requestId: '0000', + describe('set', () => { + it('sets and gets a value in async context', async () => { + const chainA = Promise.resolve().then(async () => { + service.set({ + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + }); + await delay(500); + return service.get(); + }); + + const chainB = Promise.resolve().then(async () => { + service.set({ + type: 'type-b', + name: 'name-b', + id: 'id-b', + description: 'description-b', + }); + await delay(100); + return service.get(); + }); + + expect( + await Promise.all([chainA, chainB]).then((results) => + results.map((result) => result?.toJSON()) + ) + ).toEqual([ + { + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + parent: undefined, + }, + + { + type: 'type-b', + name: 'name-b', + id: 'id-b', + description: 'description-b', + parent: undefined, + }, + ]); + }); + + it('a sequentual call rewrites the context', async () => { + const result = await Promise.resolve().then(async () => { + service.set({ + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + }); + service.set({ + type: 'type-b', + name: 'name-b', + id: 'id-b', + description: 'description-b', + }); + + return service.get(); + }); + + expect(result?.toJSON()).toEqual({ + type: 'type-b', + name: 'name-b', + id: 'id-b', + description: 'description-b', + parent: undefined, }); - await delay(500); - return service.get(); }); - const chainB = Promise.resolve().then(async () => { + it('emits context to the logs when "set" is called', async () => { service.set({ - requestId: '1111', + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', }); - await delay(100); - return service.get(); - }); - - expect( - await Promise.all([chainA, chainB]).then((results) => - results.map((result) => result?.toJSON()) - ) - ).toEqual([ - { - requestId: '0000', - }, - { - requestId: '1111', - }, - ]); + expect(loggingSystemMock.collect(core.logger).debug).toMatchInlineSnapshot(` + Array [ + Array [ + "set the execution context: {\\"type\\":\\"type-a\\",\\"name\\":\\"name-a\\",\\"id\\":\\"id-a\\",\\"description\\":\\"description-a\\"}", + ], + ] + `); + }); + + it('can be disabled', async () => { + const coreWithDisabledService = mockCoreContext.create(); + coreWithDisabledService.configService.atPath.mockReturnValue( + new BehaviorSubject({ enabled: false }) + ); + const disabledService = new ExecutionContextService(coreWithDisabledService).setup(); + const chainA = await Promise.resolve().then(async () => { + disabledService.set({ + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + }); + await delay(100); + return disabledService.get(); + }); + + expect(chainA).toBeUndefined(); + }); }); - it('sets and resets a value in async context', async () => { - const chainA = Promise.resolve().then(async () => { - service.set({ - requestId: '0000', + describe('withContext', () => { + it('sets and gets a value in async context', async () => { + const chainA = service.withContext( + { + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + }, + async () => { + await delay(10); + return service.get(); + } + ); + + const chainB = service.withContext( + { + type: 'type-b', + name: 'name-b', + id: 'id-b', + description: 'description-b', + }, + async () => { + await delay(50); + return service.get(); + } + ); + + expect( + await Promise.all([chainA, chainB]).then((results) => + results.map((result) => result?.toJSON()) + ) + ).toEqual([ + { + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + parent: undefined, + }, + { + type: 'type-b', + name: 'name-b', + id: 'id-b', + description: 'description-b', + parent: undefined, + }, + ]); + }); + + it('sets the context for a wrapped function only', () => { + service.withContext( + { + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + }, + async () => { + await delay(10); + return service.get(); + } + ); + + expect(service.get()).toBe(undefined); + }); + + it('a sequentual call does not affect orhers contexts', async () => { + const chainA = service.withContext( + { + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + }, + async () => { + await delay(50); + return service.get(); + } + ); + + const chainB = service.withContext( + { + type: 'type-b', + name: 'name-b', + id: 'id-b', + description: 'description-b', + }, + async () => { + await delay(10); + return service.get(); + } + ); + const result = await Promise.all([chainA, chainB]); + expect(result.map((r) => r?.toJSON())).toEqual([ + { + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + parent: undefined, + }, + { + type: 'type-b', + name: 'name-b', + id: 'id-b', + description: 'description-b', + parent: undefined, + }, + ]); + }); + + it('supports nested contexts', async () => { + const result = await service.withContext( + { + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + }, + async () => { + await delay(10); + return service.withContext( + { + type: 'type-b', + name: 'name-b', + id: 'id-b', + description: 'description-b', + }, + () => service.get() + ); + } + ); + + expect(result?.toJSON()).toEqual({ + type: 'type-b', + name: 'name-b', + id: 'id-b', + description: 'description-b', + parent: { + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + parent: undefined, + }, }); - await delay(500); - service.reset(); - return service.get(); }); - const chainB = Promise.resolve().then(async () => { + it('inherits a nested context configured by "set"', async () => { service.set({ - requestId: '1111', + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', }); - await delay(100); - return service.get(); - }); - - expect( - await Promise.all([chainA, chainB]).then((results) => - results.map((result) => result?.toJSON()) - ) - ).toEqual([ - undefined, - { - requestId: '1111', - }, - ]); - }); + const result = await service.withContext( + { + type: 'type-b', + name: 'name-b', + id: 'id-b', + description: 'description-b', + }, + async () => { + await delay(10); + return service.get(); + } + ); - it('emits context to the logs when "set" is called', async () => { - service.set({ - requestId: '0000', + expect(result?.toJSON()).toEqual({ + type: 'type-b', + name: 'name-b', + id: 'id-b', + description: 'description-b', + parent: { + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + parent: undefined, + }, + }); + }); + + it('do not swallow errors', () => { + const error = new Error('oops'); + const promise = service.withContext( + { + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + }, + async () => { + await delay(10); + throw error; + } + ); + + expect(promise).rejects.toBe(error); + }); + + it('emits context to the logs when "withContext" is called', async () => { + service.withContext( + { + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + }, + (i) => i + ); + expect(loggingSystemMock.collect(core.logger).debug).toMatchInlineSnapshot(` + Array [ + Array [ + "stored the execution context: {\\"type\\":\\"type-a\\",\\"name\\":\\"name-a\\",\\"id\\":\\"id-a\\",\\"description\\":\\"description-a\\"}", + ], + ] + `); + }); + + it('can be disabled', async () => { + const coreWithDisabledService = mockCoreContext.create(); + coreWithDisabledService.configService.atPath.mockReturnValue( + new BehaviorSubject({ enabled: false }) + ); + const disabledService = new ExecutionContextService(coreWithDisabledService).setup(); + const result = await disabledService.withContext( + { + type: 'type-b', + name: 'name-b', + id: 'id-b', + description: 'description-b', + }, + async () => { + await delay(10); + return service.get(); + } + ); + + expect(result).toBeUndefined(); }); - expect(loggingSystemMock.collect(core.logger).debug).toMatchInlineSnapshot(` - Array [ - Array [ - "stored the execution context: {\\"requestId\\":\\"0000\\"}", - ], - ] - `); }); - }); - describe('config', () => { - it('can be disabled', async () => { - const core = mockCoreContext.create(); - core.configService.atPath.mockReturnValue(new BehaviorSubject({ enabled: false })); - const service = new ExecutionContextService(core).setup(); - const chainA = await Promise.resolve().then(async () => { + describe('getAsHeader', () => { + it('returns request id if no context provided', async () => { + service.setRequestId('1234'); + + expect(service.getAsHeader()).toBe('1234'); + }); + + it('returns request id and registered context', async () => { + service.setRequestId('1234'); service.set({ - requestId: '0000', + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', }); - await delay(100); - return service.get(); + + expect(service.getAsHeader()).toBe('1234;kibana:type-a:name-a:id-a'); }); - expect(chainA).toBeUndefined(); + it('can be disabled', async () => { + const coreWithDisabledService = mockCoreContext.create(); + coreWithDisabledService.configService.atPath.mockReturnValue( + new BehaviorSubject({ enabled: false }) + ); + const disabledService = new ExecutionContextService(coreWithDisabledService).setup(); + disabledService.setRequestId('1234'); + disabledService.set({ + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', + }); + + expect(disabledService.getAsHeader()).toBeUndefined(); + }); }); + }); + describe('config', () => { it('reacts to config changes', async () => { const core = mockCoreContext.create(); const config$ = new BehaviorSubject({ enabled: false }); @@ -124,7 +427,10 @@ describe('ExecutionContextService', () => { function exec() { return Promise.resolve().then(async () => { service.set({ - requestId: '0000', + type: 'type-a', + name: 'name-a', + id: 'id-a', + description: 'description-a', }); await delay(100); return service.get(); diff --git a/src/core/server/execution_context/execution_context_service.ts b/src/core/server/execution_context/execution_context_service.ts index b187283e27e34a..5a8d104cebcd98 100644 --- a/src/core/server/execution_context/execution_context_service.ts +++ b/src/core/server/execution_context/execution_context_service.ts @@ -19,21 +19,26 @@ import { getParentContextFrom, } from './execution_context_container'; -/** - * @public - */ -export interface KibanaServerExecutionContext extends Partial { - requestId: string; -} - /** * @internal */ export interface IExecutionContext { getParentContextFrom(headers: Record): KibanaExecutionContext | undefined; - set(context: Partial): void; - reset(): void; + setRequestId(requestId: string): void; + set(context: KibanaExecutionContext): void; + /** + * The sole purpose of this imperative internal API is to be used by the http service. + * The event-based nature of Hapi server doesn't allow us to wrap a request handler with "withContext". + * Since all the Hapi event lifecycle will lose the execution context. + * Nodejs docs also recommend using AsyncLocalStorage.run() over AsyncLocalStorage.enterWith(). + * https://nodejs.org/api/async_context.html#async_context_asynclocalstorage_enterwith_store + */ get(): IExecutionContextContainer | undefined; + withContext(context: KibanaExecutionContext | undefined, fn: (...args: any[]) => R): R; + /** + * returns serialized representation to send as a header + **/ + getAsHeader(): string | undefined; } /** @@ -51,15 +56,11 @@ export type InternalExecutionContextStart = IExecutionContext; */ export interface ExecutionContextSetup { /** - * Stores the meta-data of a runtime operation. - * Data are carried over all async operations automatically. - * The sequential calls merge provided "context" object shallowly. - **/ - set(context: Partial): void; - /** - * Retrieves an opearation meta-data for the current async context. + * Keeps track of execution context while the passed function is executed. + * Data are carried over all async operations spawned by the passed function. + * The nested calls stack the registered context on top of each other. **/ - get(): IExecutionContextContainer | undefined; + withContext(context: KibanaExecutionContext | undefined, fn: (...args: any[]) => R): R; } /** @@ -70,13 +71,15 @@ export type ExecutionContextStart = ExecutionContextSetup; export class ExecutionContextService implements CoreService { private readonly log: Logger; - private readonly asyncLocalStorage: AsyncLocalStorage; + private readonly contextStore: AsyncLocalStorage; + private readonly requestIdStore: AsyncLocalStorage<{ requestId: string }>; private enabled = false; private configSubscription?: Subscription; constructor(private readonly coreContext: CoreContext) { this.log = coreContext.logger.get('execution_context'); - this.asyncLocalStorage = new AsyncLocalStorage(); + this.contextStore = new AsyncLocalStorage(); + this.requestIdStore = new AsyncLocalStorage<{ requestId: string }>(); } setup(): InternalExecutionContextSetup { @@ -89,8 +92,10 @@ export class ExecutionContextService return { getParentContextFrom, set: this.set.bind(this), - reset: this.reset.bind(this), + withContext: this.withContext.bind(this), + setRequestId: this.setRequestId.bind(this), get: this.get.bind(this), + getAsHeader: this.getAsHeader.bind(this), }; } @@ -98,8 +103,10 @@ export class ExecutionContextService return { getParentContextFrom, set: this.set.bind(this), - reset: this.reset.bind(this), + setRequestId: this.setRequestId.bind(this), + withContext: this.withContext.bind(this), get: this.get.bind(this), + getAsHeader: this.getAsHeader.bind(this), }; } @@ -111,25 +118,43 @@ export class ExecutionContextService } } - private set(context: KibanaServerExecutionContext) { + private set(context: KibanaExecutionContext) { if (!this.enabled) return; - const prevValue = this.asyncLocalStorage.getStore(); - // merges context objects shallowly. repeats the deafult logic of apm.setCustomContext(ctx) - const contextContainer = new ExecutionContextContainer({ ...prevValue?.toJSON(), ...context }); + const contextContainer = new ExecutionContextContainer(context); // we have to use enterWith since Hapi lifecycle model is built on event emitters. // therefore if we wrapped request handler in asyncLocalStorage.run(), we would lose context in other lifecycles. - this.asyncLocalStorage.enterWith(contextContainer); + this.contextStore.enterWith(contextContainer); + this.log.debug(`set the execution context: ${JSON.stringify(contextContainer)}`); + } + + private withContext( + context: KibanaExecutionContext | undefined, + fn: (...args: any[]) => R + ): R { + if (!this.enabled || !context) { + return fn(); + } + const parent = this.contextStore.getStore(); + const contextContainer = new ExecutionContextContainer(context, parent); this.log.debug(`stored the execution context: ${JSON.stringify(contextContainer)}`); + + return this.contextStore.run(contextContainer, fn); } - private reset() { + private setRequestId(requestId: string) { if (!this.enabled) return; - // @ts-expect-error "undefined" is not supported in type definitions, which is wrong - this.asyncLocalStorage.enterWith(undefined); + this.requestIdStore.enterWith({ requestId }); } private get(): IExecutionContextContainer | undefined { if (!this.enabled) return; - return this.asyncLocalStorage.getStore(); + return this.contextStore.getStore(); + } + + private getAsHeader(): string | undefined { + if (!this.enabled) return; + const stringifiedCtx = this.contextStore.getStore()?.toString(); + const requestId = this.requestIdStore.getStore()?.requestId; + return stringifiedCtx ? `${requestId};kibana:${stringifiedCtx}` : requestId; } } diff --git a/src/core/server/execution_context/index.ts b/src/core/server/execution_context/index.ts index f8018c75995e7f..d34eed5cc34f15 100644 --- a/src/core/server/execution_context/index.ts +++ b/src/core/server/execution_context/index.ts @@ -14,7 +14,6 @@ export type { ExecutionContextSetup, ExecutionContextStart, IExecutionContext, - KibanaServerExecutionContext, } from './execution_context_service'; export type { IExecutionContextContainer } from './execution_context_container'; export { config } from './execution_context_config'; diff --git a/src/core/server/execution_context/integration_tests/tracing.test.ts b/src/core/server/execution_context/integration_tests/tracing.test.ts index ade67d0dd2605e..5451ee222d7764 100644 --- a/src/core/server/execution_context/integration_tests/tracing.test.ts +++ b/src/core/server/execution_context/integration_tests/tracing.test.ts @@ -205,7 +205,10 @@ describe('trace', () => { executionContext.set(parentContext); const { headers } = await context.core.elasticsearch.client.asCurrentUser.ping(); return res.ok({ - body: { context: executionContext.get()?.toJSON(), header: headers?.['x-opaque-id'] }, + body: { + context: executionContext.get()?.toJSON(), + header: headers?.['x-opaque-id'], + }, }); }); @@ -237,7 +240,7 @@ describe('trace', () => { await root.start(); const response = await kbnTestServer.request.get(root, '/execution-context').expect(200); - expect(response.body).toEqual({ ...parentContext, requestId: expect.any(String) }); + expect(response.body).toEqual(parentContext); }); it('sets execution context for an async request handler', async () => { @@ -253,7 +256,7 @@ describe('trace', () => { await root.start(); const response = await kbnTestServer.request.get(root, '/execution-context').expect(200); - expect(response.body).toEqual({ ...parentContext, requestId: expect.any(String) }); + expect(response.body).toEqual(parentContext); }); it('execution context is uniq for sequential requests', async () => { @@ -261,8 +264,9 @@ describe('trace', () => { const { createRouter } = http; const router = createRouter(''); + let id = 42; router.get({ path: '/execution-context', validate: false }, async (context, req, res) => { - executionContext.set(parentContext); + executionContext.set({ ...parentContext, id: String(id++) }); await delay(100); return res.ok({ body: executionContext.get() }); }); @@ -271,9 +275,8 @@ describe('trace', () => { const responseA = await kbnTestServer.request.get(root, '/execution-context').expect(200); const responseB = await kbnTestServer.request.get(root, '/execution-context').expect(200); - expect(responseA.body).toEqual({ ...parentContext, requestId: expect.any(String) }); - expect(responseB.body).toEqual({ ...parentContext, requestId: expect.any(String) }); - expect(responseA.body.requestId).not.toBe(responseB.body.requestId); + expect(responseA.body).toEqual({ ...parentContext, id: '42' }); + expect(responseB.body).toEqual({ ...parentContext, id: '43' }); }); it('execution context is uniq for concurrent requests', async () => { @@ -283,7 +286,7 @@ describe('trace', () => { const router = createRouter(''); let id = 2; router.get({ path: '/execution-context', validate: false }, async (context, req, res) => { - executionContext.set(parentContext); + executionContext.set({ ...parentContext, id: String(id) }); await delay(id-- * 100); return res.ok({ body: executionContext.get() }); }); @@ -298,13 +301,10 @@ describe('trace', () => { responseB, responseC, ]); - expect(bodyA.requestId).toBeDefined(); - expect(bodyB.requestId).toBeDefined(); - expect(bodyC.requestId).toBeDefined(); - expect(bodyA.requestId).not.toBe(bodyB.requestId); - expect(bodyB.requestId).not.toBe(bodyC.requestId); - expect(bodyA.requestId).not.toBe(bodyC.requestId); + expect(bodyA.id).toBe('2'); + expect(bodyB.id).toBe('1'); + expect(bodyC.id).toBe('0'); }); it('execution context is uniq for concurrent requests when "x-opaque-id" provided', async () => { @@ -316,7 +316,8 @@ describe('trace', () => { router.get({ path: '/execution-context', validate: false }, async (context, req, res) => { executionContext.set(parentContext); await delay(id-- * 100); - return res.ok({ body: executionContext.get() }); + const { headers } = await context.core.elasticsearch.client.asCurrentUser.ping(); + return res.ok({ body: headers || {} }); }); await root.start(); @@ -335,9 +336,9 @@ describe('trace', () => { responseB, responseC, ]); - expect(bodyA.requestId).toBe('req-1'); - expect(bodyB.requestId).toBe('req-2'); - expect(bodyC.requestId).toBe('req-3'); + expect(bodyA['x-opaque-id']).toContain('req-1'); + expect(bodyB['x-opaque-id']).toContain('req-2'); + expect(bodyC['x-opaque-id']).toContain('req-3'); }); it('parses the parent context if present', async () => { @@ -355,7 +356,7 @@ describe('trace', () => { .set(new ExecutionContextContainer(parentContext).toHeader()) .expect(200); - expect(response.body).toEqual({ ...parentContext, requestId: expect.any(String) }); + expect(response.body).toEqual(parentContext); }); it('execution context is the same for all the lifecycle events', async () => { @@ -410,7 +411,7 @@ describe('trace', () => { .set(new ExecutionContextContainer(parentContext).toHeader()) .expect(200); - expect(response.body).toEqual({ ...parentContext, requestId: expect.any(String) }); + expect(response.body).toEqual(parentContext); expect(response.body).toEqual(onPreRoutingContext); expect(response.body).toEqual(onPreAuthContext); @@ -461,32 +462,26 @@ describe('trace', () => { expect(header).toContain('kibana:test-type:test-name:42'); }); - it('a repeat call overwrites the old context', async () => { - const { http, executionContext } = await root.setup(); + it('passes "x-opaque-id" if no execution context is registered', async () => { + const { http } = await root.setup(); const { createRouter } = http; const router = createRouter(''); - const newContext = { - type: 'new-type', - name: 'new-name', - id: '41', - description: 'new-description', - }; router.get({ path: '/execution-context', validate: false }, async (context, req, res) => { - executionContext.set(newContext); const { headers } = await context.core.elasticsearch.client.asCurrentUser.ping(); return res.ok({ body: headers || {} }); }); await root.start(); + const myOpaqueId = 'my-opaque-id'; const response = await kbnTestServer.request .get(root, '/execution-context') - .set(new ExecutionContextContainer(parentContext).toHeader()) + .set('x-opaque-id', myOpaqueId) .expect(200); const header = response.body['x-opaque-id']; - expect(header).toContain('kibana:new-type:new-name:41'); + expect(header).toBe(myOpaqueId); }); it('does not affect "x-opaque-id" set by user', async () => { @@ -531,14 +526,83 @@ describe('trace', () => { await root.start(); - const myOpaqueId = 'my-opaque-id'; - const response = await kbnTestServer.request - .get(root, '/execution-context') - .set('x-opaque-id', myOpaqueId) - .expect(200); + const response = await kbnTestServer.request.get(root, '/execution-context').expect(200); const header = response.body['x-opaque-id']; - expect(header).toBe('my-opaque-id;kibana:test-type:test-name:42'); + expect(header).toContain('kibana:test-type:test-name:42'); + }); + + describe('withContext', () => { + it('sets execution context for a nested function', async () => { + const { executionContext, http } = await root.setup(); + const { createRouter } = http; + + const router = createRouter(''); + router.get({ path: '/execution-context', validate: false }, async (context, req, res) => { + return executionContext.withContext(parentContext, () => + res.ok({ body: executionContext.get() }) + ); + }); + + await root.start(); + const response = await kbnTestServer.request.get(root, '/execution-context').expect(200); + expect(response.body).toEqual(parentContext); + }); + + it('set execution context inerits a parent if presented', async () => { + const { executionContext, http } = await root.setup(); + const { createRouter } = http; + + const router = createRouter(''); + const nestedContext = { + type: 'nested-type', + name: 'nested-name', + id: '43', + description: 'nested-description', + }; + router.get({ path: '/execution-context', validate: false }, async (context, req, res) => { + return executionContext.withContext(parentContext, async () => { + await delay(100); + return executionContext.withContext(nestedContext, async () => { + await delay(100); + return res.ok({ body: executionContext.get() }); + }); + }); + }); + + await root.start(); + const response = await kbnTestServer.request.get(root, '/execution-context').expect(200); + expect(response.body).toEqual({ ...nestedContext, parent: parentContext }); + }); + + it('extends the execution context passed from the client-side', async () => { + const { http, executionContext } = await root.setup(); + const { createRouter } = http; + + const router = createRouter(''); + const newContext = { + type: 'new-type', + name: 'new-name', + id: '41', + description: 'new-description', + }; + router.get({ path: '/execution-context', validate: false }, async (context, req, res) => { + const { headers } = await executionContext.withContext(newContext, () => + context.core.elasticsearch.client.asCurrentUser.ping() + ); + return res.ok({ body: headers || {} }); + }); + + await root.start(); + + const response = await kbnTestServer.request + .get(root, '/execution-context') + .set(new ExecutionContextContainer(parentContext).toHeader()) + .expect(200); + + const header = response.body['x-opaque-id']; + expect(header).toContain('kibana:test-type:test-name:42;new-type:new-name:41'); + }); }); }); }); diff --git a/src/core/server/http/http_server.ts b/src/core/server/http/http_server.ts index 85c035154a7a73..26725aff71b6c4 100644 --- a/src/core/server/http/http_server.ts +++ b/src/core/server/http/http_server.ts @@ -337,10 +337,9 @@ export class HttpServer { const requestId = getRequestId(request, config.requestId); const parentContext = executionContext?.getParentContextFrom(request.headers); - executionContext?.set({ - ...parentContext, - requestId, - }); + if (parentContext) executionContext?.set(parentContext); + + executionContext?.setRequestId(requestId); request.app = { ...(request.app ?? {}), diff --git a/src/core/server/index.ts b/src/core/server/index.ts index 191a3bd972f15c..6ee95a09de3033 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -84,11 +84,7 @@ export type { import type { ExecutionContextSetup, ExecutionContextStart } from './execution_context'; -export type { - IExecutionContextContainer, - KibanaServerExecutionContext, - KibanaExecutionContext, -} from './execution_context'; +export type { IExecutionContextContainer, KibanaExecutionContext } from './execution_context'; export { bootstrap } from './bootstrap'; export type { diff --git a/src/core/server/plugins/plugin_context.ts b/src/core/server/plugins/plugin_context.ts index 29194b1e8fc62b..b972c6078ca2bf 100644 --- a/src/core/server/plugins/plugin_context.ts +++ b/src/core/server/plugins/plugin_context.ts @@ -156,7 +156,9 @@ export function createPluginSetupContext( elasticsearch: { legacy: deps.elasticsearch.legacy, }, - executionContext: deps.executionContext, + executionContext: { + withContext: deps.executionContext.withContext, + }, http: { createCookieSessionStorageFactory: deps.http.createCookieSessionStorageFactory, registerRouteHandlerContext: < diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 7f2ce38a5bdd49..50cb98939ec579 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -1048,8 +1048,7 @@ export interface ErrorHttpResponseOptions { // @public (undocumented) export interface ExecutionContextSetup { - get(): IExecutionContextContainer | undefined; - set(context: Partial): void; + withContext(context: KibanaExecutionContext | undefined, fn: (...args: any[]) => R): R; } // @public (undocumented) @@ -1236,7 +1235,7 @@ export interface ICustomClusterClient extends IClusterClient { // @public (undocumented) export interface IExecutionContextContainer { // (undocumented) - toJSON(): Readonly; + toJSON(): Readonly; // (undocumented) toString(): string; } @@ -1357,14 +1356,15 @@ export interface IUiSettingsClient { setMany: (changes: Record) => Promise; } -// @public (undocumented) -export interface KibanaExecutionContext { - readonly description: string; - readonly id: string; - readonly name: string; +// @public +export type KibanaExecutionContext = { readonly type: string; + readonly name: string; + readonly id: string; + readonly description: string; readonly url?: string; -} + parent?: KibanaExecutionContext; +}; // @public export class KibanaRequest { @@ -1437,12 +1437,6 @@ export const kibanaResponseFactory: { noContent: (options?: HttpResponseOptions) => KibanaResponse; }; -// @public (undocumented) -export interface KibanaServerExecutionContext extends Partial { - // (undocumented) - requestId: string; -} - // Warning: (ae-forgotten-export) The symbol "KnownKeys" needs to be exported by the entry point index.d.ts // // @public diff --git a/src/core/types/execution_context.ts b/src/core/types/execution_context.ts index df17195d84a9ab..8a2d657812da8e 100644 --- a/src/core/types/execution_context.ts +++ b/src/core/types/execution_context.ts @@ -6,9 +6,13 @@ * Side Public License, v 1. */ -/** @public */ - -export interface KibanaExecutionContext { +/** + * @public + * Represents a meta-information about a Kibana entity initiating a search request. + */ +// use type to make it compatible with SerializableState +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +export type KibanaExecutionContext = { /** * Kibana application initated an operation. * */ @@ -21,4 +25,6 @@ export interface KibanaExecutionContext { readonly description: string; /** in browser - url to navigate to a current page, on server - endpoint path, for task: task SO url */ readonly url?: string; -} + /** a context that spawned the current context. */ + parent?: KibanaExecutionContext; +}; diff --git a/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx b/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx index b6e2a7c4b8f021..953bd619c444b9 100644 --- a/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx +++ b/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx @@ -11,7 +11,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { I18nProvider } from '@kbn/i18n/react'; import uuid from 'uuid'; -import { CoreStart, IUiSettingsClient } from 'src/core/public'; +import { CoreStart, IUiSettingsClient, KibanaExecutionContext } from 'src/core/public'; import { Start as InspectorStartContract } from 'src/plugins/inspector/public'; import { UiActionsStart } from '../../services/ui_actions'; @@ -68,6 +68,7 @@ export interface InheritedChildInput extends IndexSignature { id: string; searchSessionId?: string; syncColors?: boolean; + executionContext?: KibanaExecutionContext; } export type DashboardReactContextValue = KibanaReactContextValue; @@ -249,6 +250,7 @@ export class DashboardContainer extends Container { const { search: { session }, @@ -102,6 +105,7 @@ export const buildDashboardContainer = async ({ query: data.query, searchSessionId, savedDashboard, + executionContext, }); /** diff --git a/src/plugins/dashboard/public/application/lib/convert_dashboard_state.ts b/src/plugins/dashboard/public/application/lib/convert_dashboard_state.ts index ee2ec2bb14fe47..2e6290ec920c03 100644 --- a/src/plugins/dashboard/public/application/lib/convert_dashboard_state.ts +++ b/src/plugins/dashboard/public/application/lib/convert_dashboard_state.ts @@ -7,6 +7,7 @@ */ import _ from 'lodash'; +import type { KibanaExecutionContext } from 'src/core/public'; import { DashboardSavedObject } from '../../saved_dashboards'; import { getTagsFromSavedDashboard, migrateAppState } from '.'; import { EmbeddablePackageState, ViewMode } from '../../services/embeddable'; @@ -40,6 +41,7 @@ interface StateToDashboardContainerInputProps { query: DashboardBuildContext['query']; incomingEmbeddable?: EmbeddablePackageState; dashboardCapabilities: DashboardBuildContext['dashboardCapabilities']; + executionContext?: KibanaExecutionContext; } interface StateToRawDashboardStateProps { @@ -92,6 +94,7 @@ export const stateToDashboardContainerInput = ({ searchSessionId, savedDashboard, dashboardState, + executionContext, }: StateToDashboardContainerInputProps): DashboardContainerInput => { const { filterManager, timefilter: timefilterService } = queryService; const { timefilter } = timefilterService; @@ -125,6 +128,7 @@ export const stateToDashboardContainerInput = ({ timeRange: { ..._.cloneDeep(timefilter.getTime()), }, + executionContext, }; }; diff --git a/src/plugins/dashboard/public/application/lib/diff_dashboard_state.ts b/src/plugins/dashboard/public/application/lib/diff_dashboard_state.ts index b1abba44891fcf..8f0c8acf810226 100644 --- a/src/plugins/dashboard/public/application/lib/diff_dashboard_state.ts +++ b/src/plugins/dashboard/public/application/lib/diff_dashboard_state.ts @@ -29,7 +29,7 @@ export const diffDashboardContainerInput = ( return commonDiffFilters( (originalInput as unknown) as DashboardDiffCommonFilters, (newInput as unknown) as DashboardDiffCommonFilters, - ['searchSessionId', 'lastReloadRequestTime'] + ['searchSessionId', 'lastReloadRequestTime', 'executionContext'] ); }; diff --git a/src/plugins/dashboard/public/types.ts b/src/plugins/dashboard/public/types.ts index 89c9adb5721426..6dc068cf55f4df 100644 --- a/src/plugins/dashboard/public/types.ts +++ b/src/plugins/dashboard/public/types.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { +import type { AppMountParameters, CoreStart, SavedObjectsClientContract, @@ -14,8 +14,8 @@ import { ChromeStart, IUiSettingsClient, PluginInitializerContext, + KibanaExecutionContext, } from 'kibana/public'; - import { History } from 'history'; import { AnyAction, Dispatch } from 'redux'; import { BehaviorSubject, Subject } from 'rxjs'; @@ -86,6 +86,7 @@ export interface DashboardContainerInput extends ContainerInput { panels: { [panelId: string]: DashboardPanelState; }; + executionContext?: KibanaExecutionContext; } /** @@ -131,6 +132,7 @@ export type DashboardBuildContext = Pick< dispatchDashboardStateChange: Dispatch; $triggerDashboardRefresh: Subject<{ force?: boolean }>; $onDashboardStateChange: BehaviorSubject; + executionContext?: KibanaExecutionContext; }; export interface DashboardOptions { diff --git a/src/plugins/data/public/search/expressions/esaggs.ts b/src/plugins/data/public/search/expressions/esaggs.ts index c4a6ae3a516df5..cf3de20fea50e5 100644 --- a/src/plugins/data/public/search/expressions/esaggs.ts +++ b/src/plugins/data/public/search/expressions/esaggs.ts @@ -64,7 +64,7 @@ export function getFunctionDefinition({ timeFields: args.timeFields, timeRange: get(input, 'timeRange', undefined), getNow, - executionContext: getExecutionContext()?.toJSON(), + executionContext: getExecutionContext(), }) ) ); diff --git a/src/plugins/data/server/search/routes/bsearch.ts b/src/plugins/data/server/search/routes/bsearch.ts index e655a19e46f801..43853aa0ea939b 100644 --- a/src/plugins/data/server/search/routes/bsearch.ts +++ b/src/plugins/data/server/search/routes/bsearch.ts @@ -33,23 +33,24 @@ export function registerBsearchRoute( onBatchItem: async ({ request: requestData, options }) => { const search = getScoped(request); const { executionContext, ...restOptions } = options || {}; - if (executionContext) executionContextService.set(executionContext); - return search - .search(requestData, restOptions) - .pipe( - first(), - catchError((err) => { - // Re-throw as object, to get attributes passed to the client - // eslint-disable-next-line no-throw-literal - throw { - message: err.message, - statusCode: err.statusCode, - attributes: err.errBody?.error, - }; - }) - ) - .toPromise(); + return executionContextService.withContext(executionContext, () => + search + .search(requestData, restOptions) + .pipe( + first(), + catchError((err) => { + // Re-throw as object, to get attributes passed to the client + // eslint-disable-next-line no-throw-literal + throw { + message: err.message, + statusCode: err.statusCode, + attributes: err.errBody?.error, + }; + }) + ) + .toPromise() + ); }, }; }); diff --git a/src/plugins/embeddable/common/types.ts b/src/plugins/embeddable/common/types.ts index a45700375672fa..1cfc5073d61251 100644 --- a/src/plugins/embeddable/common/types.ts +++ b/src/plugins/embeddable/common/types.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - +import type { KibanaExecutionContext } from 'src/core/public'; import { PersistableStateService, SerializableState } from '../../kibana_utils/common'; export enum ViewMode { @@ -49,6 +49,8 @@ export type EmbeddableInput = { * Flag whether colors should be synced with other panels */ syncColors?: boolean; + + executionContext?: KibanaExecutionContext; }; export interface PanelState { diff --git a/src/plugins/embeddable/public/public.api.md b/src/plugins/embeddable/public/public.api.md index 54fe2a7b0bec26..33c9f2c8f9ff9c 100644 --- a/src/plugins/embeddable/public/public.api.md +++ b/src/plugins/embeddable/public/public.api.md @@ -28,6 +28,7 @@ import { I18nStart as I18nStart_2 } from 'src/core/public'; import { IconType } from '@elastic/eui'; import { IncomingHttpHeaders } from 'http'; import { KibanaClient } from '@elastic/elasticsearch/api/kibana'; +import { KibanaExecutionContext as KibanaExecutionContext_2 } from 'src/core/public'; import { Location } from 'history'; import { LocationDescriptorObject } from 'history'; import { Logger } from '@kbn/logging'; @@ -421,6 +422,7 @@ export type EmbeddableInput = { disableTriggers?: boolean; searchSessionId?: string; syncColors?: boolean; + executionContext?: KibanaExecutionContext_2; }; // Warning: (ae-missing-release-tag) "EmbeddableInstanceConfiguration" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) diff --git a/src/plugins/embeddable/server/server.api.md b/src/plugins/embeddable/server/server.api.md index f8f3dcb0aa0ba4..4409a37d316214 100644 --- a/src/plugins/embeddable/server/server.api.md +++ b/src/plugins/embeddable/server/server.api.md @@ -6,6 +6,7 @@ import { CoreSetup } from 'kibana/server'; import { CoreStart } from 'kibana/server'; +import { KibanaExecutionContext } from 'src/core/public'; import { Plugin } from 'kibana/server'; // Warning: (ae-forgotten-export) The symbol "EmbeddableStateWithType" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/expressions/common/execution/types.ts b/src/plugins/expressions/common/execution/types.ts index 19537b3f164e79..2d164778605ae4 100644 --- a/src/plugins/expressions/common/execution/types.ts +++ b/src/plugins/expressions/common/execution/types.ts @@ -8,7 +8,7 @@ // eslint-disable-next-line @kbn/eslint/no-restricted-paths import type { KibanaRequest } from 'src/core/server'; -import type { IExecutionContextContainer } from 'src/core/public'; +import type { KibanaExecutionContext } from 'src/core/public'; import { ExpressionType, SerializableState } from '../expression_types'; import { Adapters, RequestAdapter } from '../../../inspector/common'; @@ -67,7 +67,7 @@ export interface ExecutionContext< /** * Contains the meta-data about the source of the expression. */ - getExecutionContext: () => IExecutionContextContainer | undefined; + getExecutionContext: () => KibanaExecutionContext | undefined; } /** diff --git a/src/plugins/expressions/common/service/expressions_services.ts b/src/plugins/expressions/common/service/expressions_services.ts index cd52c8c3239de1..68d868d61ad05a 100644 --- a/src/plugins/expressions/common/service/expressions_services.ts +++ b/src/plugins/expressions/common/service/expressions_services.ts @@ -9,7 +9,7 @@ import { Observable } from 'rxjs'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import type { KibanaRequest } from 'src/core/server'; -import type { IExecutionContextContainer } from 'src/core/public'; +import type { KibanaExecutionContext } from 'src/core/public'; import { Executor } from '../executor'; import { AnyExpressionRenderDefinition, ExpressionRendererRegistry } from '../expression_renderers'; @@ -84,7 +84,7 @@ export interface ExpressionExecutionParams { inspectorAdapters?: Adapters; - executionContext?: IExecutionContextContainer; + executionContext?: KibanaExecutionContext; } /** diff --git a/src/plugins/expressions/public/public.api.md b/src/plugins/expressions/public/public.api.md index 529d6653cb7f1c..4af6b4f1e797ed 100644 --- a/src/plugins/expressions/public/public.api.md +++ b/src/plugins/expressions/public/public.api.md @@ -9,7 +9,7 @@ import { CoreStart } from 'src/core/public'; import { Ensure } from '@kbn/utility-types'; import { EnvironmentMode } from '@kbn/config'; import { EventEmitter } from 'events'; -import { IExecutionContextContainer } from 'src/core/public'; +import { KibanaExecutionContext } from 'src/core/public'; import { KibanaRequest } from 'src/core/server'; import { Observable } from 'rxjs'; import { ObservableLike } from '@kbn/utility-types'; @@ -139,7 +139,7 @@ export type ExecutionContainer = StateContainer { abortSignal: AbortSignal; - getExecutionContext: () => IExecutionContextContainer | undefined; + getExecutionContext: () => KibanaExecutionContext | undefined; getKibanaRequest?: () => KibanaRequest; getSearchContext: () => ExecutionContextSearch; getSearchSessionId: () => string | undefined; @@ -908,7 +908,7 @@ export interface IExpressionLoaderParams { // (undocumented) disableCaching?: boolean; // (undocumented) - executionContext?: IExecutionContextContainer; + executionContext?: KibanaExecutionContext; // (undocumented) hasCompatibleActions?: ExpressionRenderHandlerParams['hasCompatibleActions']; // (undocumented) diff --git a/src/plugins/expressions/public/types/index.ts b/src/plugins/expressions/public/types/index.ts index 675ed7eeed7c3c..ce1381ba8ea43d 100644 --- a/src/plugins/expressions/public/types/index.ts +++ b/src/plugins/expressions/public/types/index.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { IExecutionContextContainer } from 'src/core/public'; +import type { KibanaExecutionContext } from 'src/core/public'; import { Adapters } from '../../../inspector/public'; import { IInterpreterRenderHandlers, @@ -48,7 +48,7 @@ export interface IExpressionLoaderParams { renderMode?: RenderMode; syncColors?: boolean; hasCompatibleActions?: ExpressionRenderHandlerParams['hasCompatibleActions']; - executionContext?: IExecutionContextContainer; + executionContext?: KibanaExecutionContext; /** * The flag to toggle on emitting partial results. diff --git a/src/plugins/expressions/server/server.api.md b/src/plugins/expressions/server/server.api.md index 236c54db7140ce..22280c1bd4b226 100644 --- a/src/plugins/expressions/server/server.api.md +++ b/src/plugins/expressions/server/server.api.md @@ -8,7 +8,7 @@ import { CoreSetup } from 'src/core/server'; import { CoreStart } from 'src/core/server'; import { Ensure } from '@kbn/utility-types'; import { EventEmitter } from 'events'; -import { IExecutionContextContainer } from 'src/core/public'; +import { KibanaExecutionContext } from 'src/core/public'; import { KibanaRequest } from 'src/core/server'; import { Observable } from 'rxjs'; import { ObservableLike } from '@kbn/utility-types'; @@ -137,7 +137,7 @@ export type ExecutionContainer = StateContainer { abortSignal: AbortSignal; - getExecutionContext: () => IExecutionContextContainer | undefined; + getExecutionContext: () => KibanaExecutionContext | undefined; getKibanaRequest?: () => KibanaRequest; getSearchContext: () => ExecutionContextSearch; getSearchSessionId: () => string | undefined; diff --git a/src/plugins/vis_type_timeseries/public/request_handler.ts b/src/plugins/vis_type_timeseries/public/request_handler.ts index 66dbdaaabcddb7..0a110dd65d5e96 100644 --- a/src/plugins/vis_type_timeseries/public/request_handler.ts +++ b/src/plugins/vis_type_timeseries/public/request_handler.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type { IExecutionContextContainer } from 'src/core/public'; +import type { KibanaExecutionContext } from 'src/core/public'; import { getTimezone } from './application/lib/get_timezone'; import { getUISettings, getDataStart, getCoreStart } from './services'; import { ROUTES } from '../common/constants'; @@ -19,7 +19,7 @@ interface MetricsRequestHandlerParams { uiState: Record; visParams: TimeseriesVisParams; searchSessionId?: string; - executionContext?: IExecutionContextContainer; + executionContext?: KibanaExecutionContext; } export const metricsRequestHandler = async ({ diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts index d7ea04daae1aed..b71542a8beeea1 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -384,6 +384,15 @@ export class VisualizeEmbeddable }; private async updateHandler() { + const context = { + type: 'visualization', + name: this.vis.type.title, + id: this.vis.id ?? 'an_unsaved_vis', + description: this.vis.title || this.input.title || this.vis.type.name, + url: this.output.editUrl, + parent: this.parent?.getInput().executionContext, + }; + const expressionParams: IExpressionLoaderParams = { searchContext: { timeRange: this.timeRange, @@ -394,13 +403,7 @@ export class VisualizeEmbeddable syncColors: this.input.syncColors, uiState: this.vis.uiState, inspectorAdapters: this.inspectorAdapters, - executionContext: this.deps.start().core.executionContext.create({ - type: 'visualization', - name: this.vis.type.name, - id: this.vis.id ?? 'an_unsaved_vis', - description: this.vis.title ?? this.vis.type.title, - url: this.output.editUrl, - }), + executionContext: context, }; if (this.abortController) { this.abortController.abort(); diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx b/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx index fd22489eb75566..872132416352f5 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx @@ -59,10 +59,7 @@ interface VisualizationAttributes extends SavedObjectAttributes { export interface VisualizeEmbeddableFactoryDeps { start: StartServicesGetter< - Pick< - VisualizationsStartDeps, - 'inspector' | 'embeddable' | 'savedObjectsClient' | 'executionContext' - > + Pick >; } diff --git a/src/plugins/visualizations/public/mocks.ts b/src/plugins/visualizations/public/mocks.ts index 97800ef40e8ada..901593626a9451 100644 --- a/src/plugins/visualizations/public/mocks.ts +++ b/src/plugins/visualizations/public/mocks.ts @@ -64,7 +64,6 @@ const createInstance = async () => { getAttributeService: jest.fn(), savedObjectsClient: coreMock.createStart().savedObjects.client, savedObjects: savedObjectsPluginMock.createStartContract(), - executionContext: coreMock.createStart().executionContext, }); return { diff --git a/src/plugins/visualizations/public/plugin.ts b/src/plugins/visualizations/public/plugin.ts index f5b2f0edd044e5..ae97080b31fc51 100644 --- a/src/plugins/visualizations/public/plugin.ts +++ b/src/plugins/visualizations/public/plugin.ts @@ -54,7 +54,6 @@ import type { Plugin, ApplicationStart, SavedObjectsClientContract, - ExecutionContextServiceStart, } from '../../../core/public'; import type { UsageCollectionSetup } from '../../usage_collection/public'; import type { UiActionsStart } from '../../ui_actions/public'; @@ -104,7 +103,6 @@ export interface VisualizationsStartDeps { getAttributeService: EmbeddableStart['getAttributeService']; savedObjects: SavedObjectsStart; savedObjectsClient: SavedObjectsClientContract; - executionContext: ExecutionContextServiceStart; } /** diff --git a/test/plugin_functional/test_suites/core_plugins/execution_context.ts b/test/plugin_functional/test_suites/core_plugins/execution_context.ts index 93dc494ba5d6dd..7dc9922dca51d8 100644 --- a/test/plugin_functional/test_suites/core_plugins/execution_context.ts +++ b/test/plugin_functional/test_suites/core_plugins/execution_context.ts @@ -25,13 +25,13 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide await browser.execute(async () => { const coreStart = window._coreProvider.start.core; - const context = coreStart.executionContext.create({ + const context = { type: 'visualization', name: 'execution_context_app', // add a non-ASCII symbols to make sure it doesn't break the context propagation mechanism id: 'Visualization☺漢字', description: 'какое-то странное описание', - }); + }; const result = await coreStart.http.get('/execution_context/pass', { context, diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx index 5cf2abf7b8d0fd..56abf499aac88c 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx @@ -128,7 +128,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, { timeRange: { @@ -168,7 +167,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, { timeRange: { @@ -212,7 +210,6 @@ describe('embeddable', () => { }, errors: [{ shortMessage: '', longMessage: 'my validation error' }], }), - executionContext: coreMock.createStart().executionContext, }, {} as LensEmbeddableInput ); @@ -256,7 +253,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, {} as LensEmbeddableInput ); @@ -295,7 +291,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, { id: '123' } as LensEmbeddableInput ); @@ -337,7 +332,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, { id: '123' } as LensEmbeddableInput ); @@ -386,7 +380,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, { id: '123' } as LensEmbeddableInput ); @@ -433,7 +426,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, { id: '123' } as LensEmbeddableInput ); @@ -487,7 +479,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, input ); @@ -541,7 +532,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, input ); @@ -594,7 +584,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, input ); @@ -636,7 +625,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, { id: '123' } as LensEmbeddableInput ); @@ -678,7 +666,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, { id: '123' } as LensEmbeddableInput ); @@ -720,7 +707,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, { id: '123', timeRange, query, filters } as LensEmbeddableInput ); @@ -777,7 +763,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, ({ id: '123', onLoad } as unknown) as LensEmbeddableInput ); @@ -850,7 +835,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, ({ id: '123', onFilter } as unknown) as LensEmbeddableInput ); @@ -898,7 +882,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, ({ id: '123', onBrushEnd } as unknown) as LensEmbeddableInput ); @@ -946,7 +929,6 @@ describe('embeddable', () => { }, errors: undefined, }), - executionContext: coreMock.createStart().executionContext, }, ({ id: '123', onTableRowClick } as unknown) as LensEmbeddableInput ); diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx index e26466be6f81b4..4ecb86ac1069ff 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.tsx @@ -8,7 +8,6 @@ import { isEqual, uniqBy } from 'lodash'; import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import type { ExecutionContextServiceStart } from 'src/core/public'; import { ExecutionContextSearch, Filter, @@ -98,7 +97,6 @@ export interface LensEmbeddableDeps { getTriggerCompatibleActions?: UiActionsStart['getTriggerCompatibleActions']; capabilities: { canSaveVisualizations: boolean; canSaveDashboards: boolean }; usageCollection?: UsageCollectionSetup; - executionContext: ExecutionContextServiceStart; } export class Embeddable @@ -324,13 +322,16 @@ export class Embeddable if (this.input.onLoad) { this.input.onLoad(true); } - const executionContext = this.deps.executionContext.create({ + + const executionContext = { type: 'lens', name: this.savedVis.visualizationType ?? '', - description: this.savedVis.title ?? this.savedVis.description ?? '', id: this.id, + description: this.savedVis.title || this.input.title || '', url: this.output.editUrl, - }); + parent: this.input.executionContext, + }; + const input = this.getInput(); render( diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts b/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts index ba4e4df8494887..4cc074b5e830c8 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts +++ b/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts @@ -5,12 +5,7 @@ * 2.0. */ -import type { - Capabilities, - HttpSetup, - SavedObjectReference, - ExecutionContextServiceStart, -} from 'kibana/public'; +import type { Capabilities, HttpSetup, SavedObjectReference } from 'kibana/public'; import { i18n } from '@kbn/i18n'; import { RecursiveReadonly } from '@kbn/utility-types'; import { Ast } from '@kbn/interpreter/target/common'; @@ -38,7 +33,6 @@ export interface LensEmbeddableStartServices { indexPatternService: IndexPatternsContract; uiActions?: UiActionsStart; usageCollection?: UsageCollectionSetup; - executionContext: ExecutionContextServiceStart; documentToExpression: ( doc: Document ) => Promise<{ ast: Ast | null; errors: ErrorMessage[] | undefined }>; @@ -93,7 +87,6 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition { indexPatternService, capabilities, usageCollection, - executionContext, } = await this.getStartServices(); const { Embeddable } = await import('../async_services'); @@ -113,7 +106,6 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition { canSaveVisualizations: Boolean(capabilities.visualize.save), }, usageCollection, - executionContext, }, input, parent diff --git a/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx b/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx index b61dba16230286..fc6fcee9428b05 100644 --- a/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx +++ b/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx @@ -14,7 +14,7 @@ import { ReactExpressionRendererType, ReactExpressionRendererProps, } from 'src/plugins/expressions/public'; -import type { IExecutionContextContainer } from 'src/core/public'; +import type { KibanaExecutionContext } from 'src/core/public'; import { ExecutionContextSearch } from 'src/plugins/data/public'; import { DefaultInspectorAdapters, RenderMode } from 'src/plugins/expressions'; import classNames from 'classnames'; @@ -40,7 +40,7 @@ export interface ExpressionWrapperProps { className?: string; canEdit: boolean; onRuntimeError: () => void; - executionContext?: IExecutionContextContainer; + executionContext?: KibanaExecutionContext; } interface VisualizationErrorProps { diff --git a/x-pack/plugins/lens/public/plugin.ts b/x-pack/plugins/lens/public/plugin.ts index ae8aa268c0580a..26608f9cc78bea 100644 --- a/x-pack/plugins/lens/public/plugin.ts +++ b/x-pack/plugins/lens/public/plugin.ts @@ -177,7 +177,6 @@ export class LensPlugin { attributeService: await this.attributeService!(), capabilities: coreStart.application.capabilities, coreHttp: coreStart.http, - executionContext: coreStart.executionContext, timefilter: deps.data.query.timefilter.timefilter, expressionRenderer: deps.expressions.ReactExpressionRenderer, documentToExpression: this.editorFrameService!.documentToExpression,