diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 84076f4c4fbe93..6da2d5d602186a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -299,6 +299,8 @@ x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @elastic/kib /x-pack/plugins/triggers_actions_ui/ @elastic/kibana-alerting-services /x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/ @elastic/kibana-alerting-services /x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/ @elastic/kibana-alerting-services +/docs/user/alerting/ @elastic/kibana-alerting-services +/docs/management/alerting/ @elastic/kibana-alerting-services #CC# /x-pack/legacy/plugins/actions/ @elastic/kibana-alerting-services #CC# /x-pack/legacy/plugins/alerting/ @elastic/kibana-alerting-services #CC# /x-pack/legacy/plugins/task_manager @elastic/kibana-alerting-services diff --git a/.github/ISSUE_TEMPLATE/v8_breaking_change.md b/.github/ISSUE_TEMPLATE/v8_breaking_change.md index a64ce33b8f976d..86e321990d05f5 100644 --- a/.github/ISSUE_TEMPLATE/v8_breaking_change.md +++ b/.github/ISSUE_TEMPLATE/v8_breaking_change.md @@ -30,6 +30,8 @@ requesting the breaking change to be surfaced in the Upgrade Assistant. +**How can we programmatically determine whether the cluster is affected by this breaking change?** + **What can users do to address the change manually?** diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.executioncontextsearch.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.executioncontextsearch.md new file mode 100644 index 00000000000000..67dcb2fa442417 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.executioncontextsearch.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [ExecutionContextSearch](./kibana-plugin-plugins-data-public.executioncontextsearch.md) + +## ExecutionContextSearch type + +Signature: + +```typescript +export declare type ExecutionContextSearch = { + filters?: Filter[]; + query?: Query | Query[]; + timeRange?: TimeRange; +}; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.expressionfunctionkibana.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.expressionfunctionkibana.md new file mode 100644 index 00000000000000..c91f2e8144ead0 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.expressionfunctionkibana.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [ExpressionFunctionKibana](./kibana-plugin-plugins-data-public.expressionfunctionkibana.md) + +## ExpressionFunctionKibana type + +Signature: + +```typescript +export declare type ExpressionFunctionKibana = ExpressionFunctionDefinition<'kibana', ExpressionValueSearchContext | null, object, ExpressionValueSearchContext, ExecutionContext>; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.expressionfunctionkibanacontext.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.expressionfunctionkibanacontext.md new file mode 100644 index 00000000000000..97d2e81d455540 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.expressionfunctionkibanacontext.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [ExpressionFunctionKibanaContext](./kibana-plugin-plugins-data-public.expressionfunctionkibanacontext.md) + +## ExpressionFunctionKibanaContext type + +Signature: + +```typescript +export declare type ExpressionFunctionKibanaContext = ExpressionFunctionDefinition<'kibana_context', KibanaContext | null, Arguments, Promise, ExecutionContext>; +``` diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionvaluesearchcontext.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.expressionvaluesearchcontext.md similarity index 54% rename from docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionvaluesearchcontext.md rename to docs/development/plugins/data/public/kibana-plugin-plugins-data-public.expressionvaluesearchcontext.md index 6e38adde3ba915..4849d82b94a625 100644 --- a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionvaluesearchcontext.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.expressionvaluesearchcontext.md @@ -1,6 +1,6 @@ -[Home](./index.md) > [kibana-plugin-plugins-expressions-server](./kibana-plugin-plugins-expressions-server.md) > [ExpressionValueSearchContext](./kibana-plugin-plugins-expressions-server.expressionvaluesearchcontext.md) +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [ExpressionValueSearchContext](./kibana-plugin-plugins-data-public.expressionvaluesearchcontext.md) ## ExpressionValueSearchContext type diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.getfieldsforindexpattern.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.getfieldsforindexpattern.md index c06c3c6f684922..f288573cd7abb5 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.getfieldsforindexpattern.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.getfieldsforindexpattern.md @@ -9,5 +9,5 @@ Get field list by providing an index patttern (or spec) Signature: ```typescript -getFieldsForIndexPattern: (indexPattern: IndexPattern | IndexPatternSpec, options?: GetFieldsOptions) => Promise; +getFieldsForIndexPattern: (indexPattern: IndexPattern | IndexPatternSpec, options?: GetFieldsOptions | undefined) => Promise; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.getfieldsforwildcard.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.getfieldsforwildcard.md index aec84866b9e585..32bf6fc13b02c2 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.getfieldsforwildcard.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.getfieldsforwildcard.md @@ -9,5 +9,5 @@ Get field list by providing { pattern } Signature: ```typescript -getFieldsForWildcard: (options?: GetFieldsOptions) => Promise; +getFieldsForWildcard: (options: GetFieldsOptions) => Promise; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.md index 34df8656e91759..57bb98de09ebdd 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternsservice.md @@ -26,8 +26,8 @@ export declare class IndexPatternsService | [get](./kibana-plugin-plugins-data-public.indexpatternsservice.get.md) | | (id: string) => Promise<IndexPattern> | Get an index pattern by id. Cache optimized | | [getCache](./kibana-plugin-plugins-data-public.indexpatternsservice.getcache.md) | | () => Promise<SavedObject<IndexPatternSavedObjectAttrs>[] | null | undefined> | | | [getDefault](./kibana-plugin-plugins-data-public.indexpatternsservice.getdefault.md) | | () => Promise<IndexPattern | null> | Get default index pattern | -| [getFieldsForIndexPattern](./kibana-plugin-plugins-data-public.indexpatternsservice.getfieldsforindexpattern.md) | | (indexPattern: IndexPattern | IndexPatternSpec, options?: GetFieldsOptions) => Promise<any> | Get field list by providing an index patttern (or spec) | -| [getFieldsForWildcard](./kibana-plugin-plugins-data-public.indexpatternsservice.getfieldsforwildcard.md) | | (options?: GetFieldsOptions) => Promise<any> | Get field list by providing { pattern } | +| [getFieldsForIndexPattern](./kibana-plugin-plugins-data-public.indexpatternsservice.getfieldsforindexpattern.md) | | (indexPattern: IndexPattern | IndexPatternSpec, options?: GetFieldsOptions | undefined) => Promise<any> | Get field list by providing an index patttern (or spec) | +| [getFieldsForWildcard](./kibana-plugin-plugins-data-public.indexpatternsservice.getfieldsforwildcard.md) | | (options: GetFieldsOptions) => Promise<any> | Get field list by providing { pattern } | | [getIds](./kibana-plugin-plugins-data-public.indexpatternsservice.getids.md) | | (refresh?: boolean) => Promise<string[]> | Get list of index pattern ids | | [getIdsWithTitle](./kibana-plugin-plugins-data-public.indexpatternsservice.getidswithtitle.md) | | (refresh?: boolean) => Promise<Array<{
id: string;
title: string;
}>> | Get list of index pattern ids with titles | | [getTitles](./kibana-plugin-plugins-data-public.indexpatternsservice.gettitles.md) | | (refresh?: boolean) => Promise<string[]> | Get list of index pattern titles | diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.kibanacontext.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.kibanacontext.md similarity index 51% rename from docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.kibanacontext.md rename to docs/development/plugins/data/public/kibana-plugin-plugins-data-public.kibanacontext.md index 108533e8de357e..cb8842c66761df 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.kibanacontext.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.kibanacontext.md @@ -1,6 +1,6 @@ -[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [KibanaContext](./kibana-plugin-plugins-expressions-public.kibanacontext.md) +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [KibanaContext](./kibana-plugin-plugins-data-public.kibanacontext.md) ## KibanaContext type diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md index 255a9947858f6d..bafcd8bdffff97 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md @@ -142,7 +142,11 @@ | [EsdslExpressionFunctionDefinition](./kibana-plugin-plugins-data-public.esdslexpressionfunctiondefinition.md) | | | [EsQuerySortValue](./kibana-plugin-plugins-data-public.esquerysortvalue.md) | | | [EsRawResponseExpressionTypeDefinition](./kibana-plugin-plugins-data-public.esrawresponseexpressiontypedefinition.md) | | +| [ExecutionContextSearch](./kibana-plugin-plugins-data-public.executioncontextsearch.md) | | | [ExistsFilter](./kibana-plugin-plugins-data-public.existsfilter.md) | | +| [ExpressionFunctionKibana](./kibana-plugin-plugins-data-public.expressionfunctionkibana.md) | | +| [ExpressionFunctionKibanaContext](./kibana-plugin-plugins-data-public.expressionfunctionkibanacontext.md) | | +| [ExpressionValueSearchContext](./kibana-plugin-plugins-data-public.expressionvaluesearchcontext.md) | | | [FieldFormatId](./kibana-plugin-plugins-data-public.fieldformatid.md) | id type is needed for creating custom converters. | | [FieldFormatsContentType](./kibana-plugin-plugins-data-public.fieldformatscontenttype.md) | \* | | [FieldFormatsGetConfigFn](./kibana-plugin-plugins-data-public.fieldformatsgetconfigfn.md) | | @@ -161,6 +165,7 @@ | [InputTimeRange](./kibana-plugin-plugins-data-public.inputtimerange.md) | | | [ISearchGeneric](./kibana-plugin-plugins-data-public.isearchgeneric.md) | | | [ISearchSource](./kibana-plugin-plugins-data-public.isearchsource.md) | search source interface | +| [KibanaContext](./kibana-plugin-plugins-data-public.kibanacontext.md) | | | [MatchAllFilter](./kibana-plugin-plugins-data-public.matchallfilter.md) | | | [ParsedInterval](./kibana-plugin-plugins-data-public.parsedinterval.md) | | | [PhraseFilter](./kibana-plugin-plugins-data-public.phrasefilter.md) | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md index d1d20291a6799e..bb45222d096a0d 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md @@ -7,7 +7,7 @@ Signature: ```typescript -SearchBar: React.ComponentClass, "query" | "isLoading" | "filters" | "onRefresh" | "onRefreshChange" | "refreshInterval" | "indexPatterns" | "dataTestSubj" | "timeHistory" | "customSubmitButton" | "screenTitle" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "indicateNoData" | "onFiltersUpdated">, any> & { - WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; +SearchBar: React.ComponentClass, "query" | "isLoading" | "filters" | "onRefresh" | "onRefreshChange" | "refreshInterval" | "indexPatterns" | "dataTestSubj" | "screenTitle" | "showQueryInput" | "showDatePicker" | "showAutoRefreshOnly" | "dateRangeFrom" | "dateRangeTo" | "isRefreshPaused" | "customSubmitButton" | "timeHistory" | "indicateNoData" | "onFiltersUpdated" | "savedQuery" | "showSaveQuery" | "onClearSavedQuery" | "showQueryBar" | "showFilterBar" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated">, any> & { + WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; } ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.executioncontextsearch.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.executioncontextsearch.md new file mode 100644 index 00000000000000..2f94dbe970d44b --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.executioncontextsearch.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ExecutionContextSearch](./kibana-plugin-plugins-data-server.executioncontextsearch.md) + +## ExecutionContextSearch type + +Signature: + +```typescript +export declare type ExecutionContextSearch = { + filters?: Filter[]; + query?: Query | Query[]; + timeRange?: TimeRange; +}; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.expressionfunctionkibana.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.expressionfunctionkibana.md new file mode 100644 index 00000000000000..d80ff78dd803cf --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.expressionfunctionkibana.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ExpressionFunctionKibana](./kibana-plugin-plugins-data-server.expressionfunctionkibana.md) + +## ExpressionFunctionKibana type + +Signature: + +```typescript +export declare type ExpressionFunctionKibana = ExpressionFunctionDefinition<'kibana', ExpressionValueSearchContext | null, object, ExpressionValueSearchContext, ExecutionContext>; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.expressionfunctionkibanacontext.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.expressionfunctionkibanacontext.md new file mode 100644 index 00000000000000..b67f7b8c4b60d0 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.expressionfunctionkibanacontext.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ExpressionFunctionKibanaContext](./kibana-plugin-plugins-data-server.expressionfunctionkibanacontext.md) + +## ExpressionFunctionKibanaContext type + +Signature: + +```typescript +export declare type ExpressionFunctionKibanaContext = ExpressionFunctionDefinition<'kibana_context', KibanaContext | null, Arguments, Promise, ExecutionContext>; +``` diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionvaluesearchcontext.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.expressionvaluesearchcontext.md similarity index 54% rename from docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionvaluesearchcontext.md rename to docs/development/plugins/data/server/kibana-plugin-plugins-data-server.expressionvaluesearchcontext.md index bf64dfe4c86f77..8015482ddec1e0 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionvaluesearchcontext.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.expressionvaluesearchcontext.md @@ -1,6 +1,6 @@ -[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [ExpressionValueSearchContext](./kibana-plugin-plugins-expressions-public.expressionvaluesearchcontext.md) +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ExpressionValueSearchContext](./kibana-plugin-plugins-data-server.expressionvaluesearchcontext.md) ## ExpressionValueSearchContext type diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.getcapabilitiesforrollupindices.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.getcapabilitiesforrollupindices.md new file mode 100644 index 00000000000000..ba2efcc9b75ca1 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.getcapabilitiesforrollupindices.md @@ -0,0 +1,28 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [getCapabilitiesForRollupIndices](./kibana-plugin-plugins-data-server.getcapabilitiesforrollupindices.md) + +## getCapabilitiesForRollupIndices() function + +Signature: + +```typescript +export declare function getCapabilitiesForRollupIndices(indices: { + [key: string]: any; +}): { + [key: string]: any; +}; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| indices | {
[key: string]: any;
} | | + +Returns: + +`{ + [key: string]: any; +}` + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsfetcher.getfieldsforwildcard.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsfetcher.getfieldsforwildcard.md index addd29916d81df..f0989097a727db 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsfetcher.getfieldsforwildcard.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsfetcher.getfieldsforwildcard.md @@ -15,6 +15,8 @@ getFieldsForWildcard(options: { fieldCapsOptions?: { allow_no_indices: boolean; }; + type?: string; + rollupIndex?: string; }): Promise; ``` @@ -22,7 +24,7 @@ getFieldsForWildcard(options: { | Parameter | Type | Description | | --- | --- | --- | -| options | {
pattern: string | string[];
metaFields?: string[];
fieldCapsOptions?: {
allow_no_indices: boolean;
};
} | | +| options | {
pattern: string | string[];
metaFields?: string[];
fieldCapsOptions?: {
allow_no_indices: boolean;
};
type?: string;
rollupIndex?: string;
} | | Returns: diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.start.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.start.md index e7c331bad64e84..6528b1c213ccad 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.start.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsservice.start.md @@ -8,7 +8,7 @@ ```typescript start(core: CoreStart, { fieldFormats, logger }: IndexPatternsServiceStartDeps): { - indexPatternsServiceFactory: (savedObjectsClient: SavedObjectsClientContract) => Promise; + indexPatternsServiceFactory: (savedObjectsClient: SavedObjectsClientContract, elasticsearchClient: ElasticsearchClient) => Promise; }; ``` @@ -22,6 +22,6 @@ start(core: CoreStart, { fieldFormats, logger }: IndexPatternsServiceStartDeps): Returns: `{ - indexPatternsServiceFactory: (savedObjectsClient: SavedObjectsClientContract) => Promise; + indexPatternsServiceFactory: (savedObjectsClient: SavedObjectsClientContract, elasticsearchClient: ElasticsearchClient) => Promise; }` diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.kibanacontext.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.kibanacontext.md similarity index 51% rename from docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.kibanacontext.md rename to docs/development/plugins/data/server/kibana-plugin-plugins-data-server.kibanacontext.md index 023748173e7dd6..1ddc43c633b266 100644 --- a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.kibanacontext.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.kibanacontext.md @@ -1,6 +1,6 @@ -[Home](./index.md) > [kibana-plugin-plugins-expressions-server](./kibana-plugin-plugins-expressions-server.md) > [KibanaContext](./kibana-plugin-plugins-expressions-server.kibanacontext.md) +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [KibanaContext](./kibana-plugin-plugins-data-server.kibanacontext.md) ## KibanaContext type diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md index 82d0a5a3182b96..8957f6d0f06b4c 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md @@ -28,6 +28,7 @@ | Function | Description | | --- | --- | +| [getCapabilitiesForRollupIndices(indices)](./kibana-plugin-plugins-data-server.getcapabilitiesforrollupindices.md) | | | [getDefaultSearchParams(uiSettingsClient)](./kibana-plugin-plugins-data-server.getdefaultsearchparams.md) | | | [getShardTimeout(config)](./kibana-plugin-plugins-data-server.getshardtimeout.md) | | | [getTime(indexPattern, timeRange, options)](./kibana-plugin-plugins-data-server.gettime.md) | | @@ -77,6 +78,7 @@ | [esQuery](./kibana-plugin-plugins-data-server.esquery.md) | | | [fieldFormats](./kibana-plugin-plugins-data-server.fieldformats.md) | | | [indexPatterns](./kibana-plugin-plugins-data-server.indexpatterns.md) | | +| [mergeCapabilitiesWithFields](./kibana-plugin-plugins-data-server.mergecapabilitieswithfields.md) | | | [search](./kibana-plugin-plugins-data-server.search.md) | | | [UI\_SETTINGS](./kibana-plugin-plugins-data-server.ui_settings.md) | | @@ -88,6 +90,10 @@ | [AggGroupName](./kibana-plugin-plugins-data-server.agggroupname.md) | | | [AggParam](./kibana-plugin-plugins-data-server.aggparam.md) | | | [EsaggsExpressionFunctionDefinition](./kibana-plugin-plugins-data-server.esaggsexpressionfunctiondefinition.md) | | +| [ExecutionContextSearch](./kibana-plugin-plugins-data-server.executioncontextsearch.md) | | +| [ExpressionFunctionKibana](./kibana-plugin-plugins-data-server.expressionfunctionkibana.md) | | +| [ExpressionFunctionKibanaContext](./kibana-plugin-plugins-data-server.expressionfunctionkibanacontext.md) | | +| [ExpressionValueSearchContext](./kibana-plugin-plugins-data-server.expressionvaluesearchcontext.md) | | | [FieldFormatsGetConfigFn](./kibana-plugin-plugins-data-server.fieldformatsgetconfigfn.md) | | | [Filter](./kibana-plugin-plugins-data-server.filter.md) | | | [IAggConfig](./kibana-plugin-plugins-data-server.iaggconfig.md) | AggConfig This class represents an aggregation, which is displayed in the left-hand nav of the Visualize app. | @@ -96,6 +102,7 @@ | [IFieldFormatsRegistry](./kibana-plugin-plugins-data-server.ifieldformatsregistry.md) | | | [IFieldParamType](./kibana-plugin-plugins-data-server.ifieldparamtype.md) | | | [IMetricAggType](./kibana-plugin-plugins-data-server.imetricaggtype.md) | | +| [KibanaContext](./kibana-plugin-plugins-data-server.kibanacontext.md) | | | [ParsedInterval](./kibana-plugin-plugins-data-server.parsedinterval.md) | | | [Query](./kibana-plugin-plugins-data-server.query.md) | | | [TabbedAggRow](./kibana-plugin-plugins-data-server.tabbedaggrow.md) | \* | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.mergecapabilitieswithfields.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.mergecapabilitieswithfields.md new file mode 100644 index 00000000000000..2880e2d0d8f2cc --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.mergecapabilitieswithfields.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [mergeCapabilitiesWithFields](./kibana-plugin-plugins-data-server.mergecapabilitieswithfields.md) + +## mergeCapabilitiesWithFields variable + +Signature: + +```typescript +mergeCapabilitiesWithFields: (rollupIndexCapabilities: { + [key: string]: any; +}, fieldsFromFieldCapsApi: { + [key: string]: any; +}, previousFields?: FieldDescriptor[]) => FieldDescriptor[] +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md index 139c5794f01467..43129891c5412f 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md @@ -11,7 +11,7 @@ setup(core: CoreSetup, { expressio __enhance: (enhancements: DataEnhancements) => void; search: ISearchSetup; fieldFormats: { - register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; + register: (customFieldFormat: import("../common").FieldFormatInstanceType) => number; }; }; ``` @@ -29,7 +29,7 @@ setup(core: CoreSetup, { expressio __enhance: (enhancements: DataEnhancements) => void; search: ISearchSetup; fieldFormats: { - register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; + register: (customFieldFormat: import("../common").FieldFormatInstanceType) => number; }; }` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md index 03d3485fce9ee4..8a3dbe5a6350c1 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md @@ -12,7 +12,7 @@ start(core: CoreStart): { fieldFormatServiceFactory: (uiSettings: import("src/core/server").IUiSettingsClient) => Promise; }; indexPatterns: { - indexPatternsServiceFactory: (savedObjectsClient: Pick) => Promise; + indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("src/core/server").ElasticsearchClient) => Promise; }; search: ISearchStart>; }; @@ -31,7 +31,7 @@ start(core: CoreStart): { fieldFormatServiceFactory: (uiSettings: import("src/core/server").IUiSettingsClient) => Promise; }; indexPatterns: { - indexPatternsServiceFactory: (savedObjectsClient: Pick) => Promise; + indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("src/core/server").ElasticsearchClient) => Promise; }; search: ISearchStart>; }` 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 2a1a78b8fcb1a2..86d24534f7a448 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 @@ -9,7 +9,7 @@ Signature: ```typescript -export interface ExecutionContext +export interface ExecutionContext ``` ## Properties diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.kibana.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.kibana.md deleted file mode 100644 index abe8e0ae161ad1..00000000000000 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.kibana.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [ExpressionFunctionDefinitions](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.md) > [kibana](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.kibana.md) - -## ExpressionFunctionDefinitions.kibana property - -Signature: - -```typescript -kibana: ExpressionFunctionKibana; -``` diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.kibana_context.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.kibana_context.md deleted file mode 100644 index 4b58fd84e160d8..00000000000000 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.kibana_context.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [ExpressionFunctionDefinitions](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.md) > [kibana\_context](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.kibana_context.md) - -## ExpressionFunctionDefinitions.kibana\_context property - -Signature: - -```typescript -kibana_context: ExpressionFunctionKibanaContext; -``` diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.md index 53f090ea30c3f8..c6e00842a31e6a 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.md @@ -20,8 +20,6 @@ export interface ExpressionFunctionDefinitions | [cumulative\_sum](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.cumulative_sum.md) | ExpressionFunctionCumulativeSum | | | [derivative](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.derivative.md) | ExpressionFunctionDerivative | | | [font](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.font.md) | ExpressionFunctionFont | | -| [kibana\_context](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.kibana_context.md) | ExpressionFunctionKibanaContext | | -| [kibana](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.kibana.md) | ExpressionFunctionKibana | | | [moving\_average](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.moving_average.md) | ExpressionFunctionMovingAverage | | | [theme](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.theme.md) | ExpressionFunctionTheme | | | [var\_set](./kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.var_set.md) | ExpressionFunctionVarSet | | diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctionkibana.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctionkibana.md deleted file mode 100644 index 8ccf48ba285271..00000000000000 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctionkibana.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [ExpressionFunctionKibana](./kibana-plugin-plugins-expressions-public.expressionfunctionkibana.md) - -## ExpressionFunctionKibana type - -Signature: - -```typescript -export declare type ExpressionFunctionKibana = ExpressionFunctionDefinition<'kibana', ExpressionValueSearchContext | null, object, ExpressionValueSearchContext>; -``` 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 e2ad6215e25d09..2dfc67d2af5fa1 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 @@ -21,7 +21,7 @@ export interface IExpressionLoaderParams | [disableCaching](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.disablecaching.md) | boolean | | | [inspectorAdapters](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.inspectoradapters.md) | Adapters | | | [onRenderError](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.onrendererror.md) | RenderErrorHandlerFnType | | -| [searchContext](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.searchcontext.md) | ExecutionContextSearch | | +| [searchContext](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.searchcontext.md) | SerializableState | | | [searchSessionId](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.searchsessionid.md) | string | | | [uiState](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.uistate.md) | unknown | | | [variables](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.variables.md) | Record<string, any> | | diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.searchcontext.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.searchcontext.md index 523d0c562f7cac..6b5fad950c4e95 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.searchcontext.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.iexpressionloaderparams.searchcontext.md @@ -7,5 +7,5 @@ Signature: ```typescript -searchContext?: ExecutionContextSearch; +searchContext?: SerializableState; ``` diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.kibana_context_name.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.kibana_context_name.md deleted file mode 100644 index e568db84f383d9..00000000000000 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.kibana_context_name.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [KIBANA\_CONTEXT\_NAME](./kibana-plugin-plugins-expressions-public.kibana_context_name.md) - -## KIBANA\_CONTEXT\_NAME type - -Signature: - -```typescript -export declare type KIBANA_CONTEXT_NAME = 'kibana_context'; -``` diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.md index db09f966e2fa51..a03ea324820118 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.md @@ -99,7 +99,6 @@ | [ExpressionAstExpression](./kibana-plugin-plugins-expressions-public.expressionastexpression.md) | | | [ExpressionAstFunction](./kibana-plugin-plugins-expressions-public.expressionastfunction.md) | | | [ExpressionAstNode](./kibana-plugin-plugins-expressions-public.expressionastnode.md) | | -| [ExpressionFunctionKibana](./kibana-plugin-plugins-expressions-public.expressionfunctionkibana.md) | | | [ExpressionRendererComponent](./kibana-plugin-plugins-expressions-public.expressionrenderercomponent.md) | | | [ExpressionsServiceSetup](./kibana-plugin-plugins-expressions-public.expressionsservicesetup.md) | The public contract that ExpressionsService provides to other plugins in Kibana Platform in \*setup\* life-cycle. | | [ExpressionsSetup](./kibana-plugin-plugins-expressions-public.expressionssetup.md) | Expressions public setup contract, extends [ExpressionsServiceSetup](./kibana-plugin-plugins-expressions-public.expressionsservicesetup.md) | @@ -110,13 +109,10 @@ | [ExpressionValueFilter](./kibana-plugin-plugins-expressions-public.expressionvaluefilter.md) | Represents an object that is a Filter. | | [ExpressionValueNum](./kibana-plugin-plugins-expressions-public.expressionvaluenum.md) | | | [ExpressionValueRender](./kibana-plugin-plugins-expressions-public.expressionvaluerender.md) | Represents an object that is intended to be rendered. | -| [ExpressionValueSearchContext](./kibana-plugin-plugins-expressions-public.expressionvaluesearchcontext.md) | | | [ExpressionValueUnboxed](./kibana-plugin-plugins-expressions-public.expressionvalueunboxed.md) | | | [FontLabel](./kibana-plugin-plugins-expressions-public.fontlabel.md) | This type contains a unions of all supported font labels, or the the name of the font the user would see in a UI. | | [FontValue](./kibana-plugin-plugins-expressions-public.fontvalue.md) | This type contains a union of all supported font values, equivalent to the CSS font-value property. | | [InterpreterErrorType](./kibana-plugin-plugins-expressions-public.interpretererrortype.md) | | -| [KIBANA\_CONTEXT\_NAME](./kibana-plugin-plugins-expressions-public.kibana_context_name.md) | | -| [KibanaContext](./kibana-plugin-plugins-expressions-public.kibanacontext.md) | | | [KnownTypeToString](./kibana-plugin-plugins-expressions-public.knowntypetostring.md) | Map the type of the generic to a string-based representation of the type.If the provided generic is its own type interface, we use the value of the type key as a string literal type for it. | | [PointSeries](./kibana-plugin-plugins-expressions-public.pointseries.md) | A PointSeries is a unique structure that represents dots on a chart. | | [PointSeriesColumnName](./kibana-plugin-plugins-expressions-public.pointseriescolumnname.md) | Allowed column names in a PointSeries | 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 047879fd99255f..e2547cc9470d15 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 @@ -9,7 +9,7 @@ Signature: ```typescript -export interface ExecutionContext +export interface ExecutionContext ``` ## Properties diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.kibana.md b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.kibana.md deleted file mode 100644 index 8e6d189f8f450f..00000000000000 --- a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.kibana.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-expressions-server](./kibana-plugin-plugins-expressions-server.md) > [ExpressionFunctionDefinitions](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.md) > [kibana](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.kibana.md) - -## ExpressionFunctionDefinitions.kibana property - -Signature: - -```typescript -kibana: ExpressionFunctionKibana; -``` diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.kibana_context.md b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.kibana_context.md deleted file mode 100644 index f9e248ad6d913f..00000000000000 --- a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.kibana_context.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-expressions-server](./kibana-plugin-plugins-expressions-server.md) > [ExpressionFunctionDefinitions](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.md) > [kibana\_context](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.kibana_context.md) - -## ExpressionFunctionDefinitions.kibana\_context property - -Signature: - -```typescript -kibana_context: ExpressionFunctionKibanaContext; -``` diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.md b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.md index 6f152bb10b37ee..219678244951b4 100644 --- a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.md +++ b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.md @@ -20,8 +20,6 @@ export interface ExpressionFunctionDefinitions | [cumulative\_sum](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.cumulative_sum.md) | ExpressionFunctionCumulativeSum | | | [derivative](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.derivative.md) | ExpressionFunctionDerivative | | | [font](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.font.md) | ExpressionFunctionFont | | -| [kibana\_context](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.kibana_context.md) | ExpressionFunctionKibanaContext | | -| [kibana](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.kibana.md) | ExpressionFunctionKibana | | | [moving\_average](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.moving_average.md) | ExpressionFunctionMovingAverage | | | [theme](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.theme.md) | ExpressionFunctionTheme | | | [var\_set](./kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.var_set.md) | ExpressionFunctionVarSet | | diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctionkibana.md b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctionkibana.md deleted file mode 100644 index aac2ae1c3ca4ea..00000000000000 --- a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctionkibana.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-expressions-server](./kibana-plugin-plugins-expressions-server.md) > [ExpressionFunctionKibana](./kibana-plugin-plugins-expressions-server.expressionfunctionkibana.md) - -## ExpressionFunctionKibana type - -Signature: - -```typescript -export declare type ExpressionFunctionKibana = ExpressionFunctionDefinition<'kibana', ExpressionValueSearchContext | null, object, ExpressionValueSearchContext>; -``` diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.kibana_context_name.md b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.kibana_context_name.md deleted file mode 100644 index bd47c52e0d5cef..00000000000000 --- a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.kibana_context_name.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-expressions-server](./kibana-plugin-plugins-expressions-server.md) > [KIBANA\_CONTEXT\_NAME](./kibana-plugin-plugins-expressions-server.kibana_context_name.md) - -## KIBANA\_CONTEXT\_NAME type - -Signature: - -```typescript -export declare type KIBANA_CONTEXT_NAME = 'kibana_context'; -``` diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.md b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.md index 9e2189dad27321..5f7f373cd927f4 100644 --- a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.md +++ b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.md @@ -83,7 +83,6 @@ | [ExpressionAstExpression](./kibana-plugin-plugins-expressions-server.expressionastexpression.md) | | | [ExpressionAstFunction](./kibana-plugin-plugins-expressions-server.expressionastfunction.md) | | | [ExpressionAstNode](./kibana-plugin-plugins-expressions-server.expressionastnode.md) | | -| [ExpressionFunctionKibana](./kibana-plugin-plugins-expressions-server.expressionfunctionkibana.md) | | | [ExpressionsServerSetup](./kibana-plugin-plugins-expressions-server.expressionsserversetup.md) | | | [ExpressionsServerStart](./kibana-plugin-plugins-expressions-server.expressionsserverstart.md) | | | [ExpressionValue](./kibana-plugin-plugins-expressions-server.expressionvalue.md) | | @@ -93,13 +92,10 @@ | [ExpressionValueFilter](./kibana-plugin-plugins-expressions-server.expressionvaluefilter.md) | Represents an object that is a Filter. | | [ExpressionValueNum](./kibana-plugin-plugins-expressions-server.expressionvaluenum.md) | | | [ExpressionValueRender](./kibana-plugin-plugins-expressions-server.expressionvaluerender.md) | Represents an object that is intended to be rendered. | -| [ExpressionValueSearchContext](./kibana-plugin-plugins-expressions-server.expressionvaluesearchcontext.md) | | | [ExpressionValueUnboxed](./kibana-plugin-plugins-expressions-server.expressionvalueunboxed.md) | | | [FontLabel](./kibana-plugin-plugins-expressions-server.fontlabel.md) | This type contains a unions of all supported font labels, or the the name of the font the user would see in a UI. | | [FontValue](./kibana-plugin-plugins-expressions-server.fontvalue.md) | This type contains a union of all supported font values, equivalent to the CSS font-value property. | | [InterpreterErrorType](./kibana-plugin-plugins-expressions-server.interpretererrortype.md) | | -| [KIBANA\_CONTEXT\_NAME](./kibana-plugin-plugins-expressions-server.kibana_context_name.md) | | -| [KibanaContext](./kibana-plugin-plugins-expressions-server.kibanacontext.md) | | | [KnownTypeToString](./kibana-plugin-plugins-expressions-server.knowntypetostring.md) | Map the type of the generic to a string-based representation of the type.If the provided generic is its own type interface, we use the value of the type key as a string literal type for it. | | [PointSeries](./kibana-plugin-plugins-expressions-server.pointseries.md) | A PointSeries is a unique structure that represents dots on a chart. | | [PointSeriesColumnName](./kibana-plugin-plugins-expressions-server.pointseriescolumnname.md) | Allowed column names in a PointSeries | diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.addtriggeraction.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.addtriggeraction.md index ba9060e01e57de..5a1ab83551d346 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.addtriggeraction.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.addtriggeraction.md @@ -11,5 +11,5 @@ Signature: ```typescript -readonly addTriggerAction: (triggerId: T, action: ActionDefinition | Action) => void; +readonly addTriggerAction: (triggerId: T, action: ActionDefinition | Action) => void; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.getaction.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.getaction.md index 3e433809f94717..5b0b3eea01cb11 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.getaction.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.getaction.md @@ -7,5 +7,5 @@ Signature: ```typescript -readonly getAction: >(id: string) => Action, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK">; +readonly getAction: >(id: string) => Action, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION">; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggeractions.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggeractions.md index 83afcab29689d5..2dda422046318c 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggeractions.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggeractions.md @@ -7,5 +7,5 @@ Signature: ```typescript -readonly getTriggerActions: (triggerId: T) => Action[]; +readonly getTriggerActions: (triggerId: T) => Action[]; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggercompatibleactions.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggercompatibleactions.md index 879f5a3d8628ae..e087753726a8ae 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggercompatibleactions.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggercompatibleactions.md @@ -7,5 +7,5 @@ Signature: ```typescript -readonly getTriggerCompatibleActions: (triggerId: T, context: TriggerContextMapping[T]) => Promise[]>; +readonly getTriggerCompatibleActions: (triggerId: T, context: TriggerContextMapping[T]) => Promise[]>; ``` diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.md index 7fade7c4c841b3..f9eb693b492f70 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.md @@ -21,19 +21,19 @@ export declare class UiActionsService | Property | Modifiers | Type | Description | | --- | --- | --- | --- | | [actions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.actions.md) | | ActionRegistry | | -| [addTriggerAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.addtriggeraction.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T, action: ActionDefinition<TriggerContextMapping[T]> | Action<TriggerContextMapping[T], "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK">) => void | addTriggerAction is similar to attachAction as it attaches action to a trigger, but it also registers the action, if it has not been registered, yet.addTriggerAction also infers better typing of the action argument. | +| [addTriggerAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.addtriggeraction.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T, action: ActionDefinition<TriggerContextMapping[T]> | Action<TriggerContextMapping[T], "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION">) => void | addTriggerAction is similar to attachAction as it attaches action to a trigger, but it also registers the action, if it has not been registered, yet.addTriggerAction also infers better typing of the action argument. | | [attachAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.attachaction.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T, actionId: string) => void | | | [clear](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.clear.md) | | () => void | Removes all registered triggers and actions. | | [detachAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.detachaction.md) | | (triggerId: TriggerId, actionId: string) => void | | | [executeTriggerActions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.executetriggeractions.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T, context: TriggerContext<T>) => Promise<void> | | | [executionService](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.executionservice.md) | | UiActionsExecutionService | | | [fork](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.fork.md) | | () => UiActionsService | "Fork" a separate instance of UiActionsService that inherits all existing triggers and actions, but going forward all new triggers and actions added to this instance of UiActionsService are only available within this instance. | -| [getAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.getaction.md) | | <T extends ActionDefinition<{}>>(id: string) => Action<ActionContext<T>, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK"> | | +| [getAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.getaction.md) | | <T extends ActionDefinition<{}>>(id: string) => Action<ActionContext<T>, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION"> | | | [getTrigger](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettrigger.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T) => TriggerContract<T> | | -| [getTriggerActions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggeractions.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T) => Action<TriggerContextMapping[T], "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK">[] | | -| [getTriggerCompatibleActions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggercompatibleactions.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T, context: TriggerContextMapping[T]) => Promise<Action<TriggerContextMapping[T], "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK">[]> | | +| [getTriggerActions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggeractions.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T) => Action<TriggerContextMapping[T], "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION">[] | | +| [getTriggerCompatibleActions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.gettriggercompatibleactions.md) | | <T extends "" | "SELECT_RANGE_TRIGGER" | "VALUE_CLICK_TRIGGER" | "FILTER_TRIGGER" | "VISUALIZE_FIELD_TRIGGER" | "VISUALIZE_GEO_FIELD_TRIGGER" | "CONTEXT_MENU_TRIGGER" | "PANEL_BADGE_TRIGGER" | "PANEL_NOTIFICATION_TRIGGER">(triggerId: T, context: TriggerContextMapping[T]) => Promise<Action<TriggerContextMapping[T], "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION">[]> | | | [hasAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.hasaction.md) | | (actionId: string) => boolean | | -| [registerAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.registeraction.md) | | <A extends ActionDefinition<{}>>(definition: A) => Action<ActionContext<A>, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK"> | | +| [registerAction](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.registeraction.md) | | <A extends ActionDefinition<{}>>(definition: A) => Action<ActionContext<A>, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION"> | | | [registerTrigger](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.registertrigger.md) | | (trigger: Trigger) => void | | | [triggers](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.triggers.md) | | TriggerRegistry | | | [triggerToActions](./kibana-plugin-plugins-ui_actions-public.uiactionsservice.triggertoactions.md) | | TriggerToActionsRegistry | | diff --git a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.registeraction.md b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.registeraction.md index eeda7b503037dd..bd340eb76fbac2 100644 --- a/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.registeraction.md +++ b/docs/development/plugins/ui_actions/public/kibana-plugin-plugins-ui_actions-public.uiactionsservice.registeraction.md @@ -7,5 +7,5 @@ Signature: ```typescript -readonly registerAction: >(definition: A) => Action, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK">; +readonly registerAction: >(definition: A) => Action, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION">; ``` diff --git a/docs/glossary.asciidoc b/docs/glossary.asciidoc index be24402170bbee..ff03a601739615 100644 --- a/docs/glossary.asciidoc +++ b/docs/glossary.asciidoc @@ -330,6 +330,11 @@ See {kibana-ref}/xpack-spaces.html[Spaces]. // end::space-def[] +[[glossary-stack-alerts]] stack alerts :: +// tag::stack-alert-def[] +The general purpose alert types {kib} provides out of the box. Index threshold and geo alerts are currently the two stack alert types. +// end::stack-alert-def[] + [float] [[t_glos]] diff --git a/docs/user/alerting/alert-types.asciidoc b/docs/user/alerting/alert-types.asciidoc index f71e43c5defc7b..7de5ff56228cc0 100644 --- a/docs/user/alerting/alert-types.asciidoc +++ b/docs/user/alerting/alert-types.asciidoc @@ -2,11 +2,13 @@ [[alert-types]] == Alert types -{kib} supplies alerts types in two ways: some are built into {kib}, while domain-specific alert types are registered by {kib} apps such as <>, <>, and <>. +{kib} supplies alert types in two ways: some are built into {kib} (these are known as stack alerts), while domain-specific alert types are registered by {kib} apps such as <>, <>, and <>. -This section covers built-in alert types. For domain-specific alert types, refer to the documentation for that app. +This section covers stack alerts. For domain-specific alert types, refer to the documentation for that app. +Users will need `all` access to the *Stack Alerts* feature to be able to create and edit any of the alerts listed below. +See <> for more information on configuring roles that provide access to this feature. -Currently {kib} provides one built-in alert type: the <> type. +Currently {kib} provides one stack alert: the <> type. [float] [[alert-type-index-threshold]] diff --git a/docs/user/alerting/alerting-getting-started.asciidoc b/docs/user/alerting/alerting-getting-started.asciidoc index 2b22b49375676f..53aef4aaa062ed 100644 --- a/docs/user/alerting/alerting-getting-started.asciidoc +++ b/docs/user/alerting/alerting-getting-started.asciidoc @@ -6,7 +6,7 @@ beta[] -- -Alerting allows you to detect complex conditions within different {kib} apps and trigger actions when those conditions are met. Alerting is integrated with <>, <>, <>, <>, can be centrally managed from the <> UI, and provides a set of built-in <> and <> for you to use. +Alerting allows you to detect complex conditions within different {kib} apps and trigger actions when those conditions are met. Alerting is integrated with <>, <>, <>, <>, can be centrally managed from the <> UI, and provides a set of built-in <> and <> (known as stack alerts) for you to use. image::images/alerting-overview.png[Alerts and actions UI] diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index 48187fe4653922..0815df4b9b0c7e 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -131,6 +131,7 @@ export class DocLinksService { management: { kibanaSearchSettings: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/advanced-options.html#kibana-search-settings`, dashboardSettings: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/advanced-options.html#kibana-dashboard-settings`, + visualizationSettings: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/advanced-options.html#kibana-visualization-settings`, }, visualize: { guide: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/visualize.html`, diff --git a/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts b/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts index c35ec809fcf8d3..e78b944183df91 100644 --- a/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts +++ b/src/core/server/saved_objects/service/lib/search_dsl/query_params.test.ts @@ -103,12 +103,11 @@ describe('#getQueryParams', () => { if (registry.isMultiNamespace(type)) { const array = [...(namespaces ?? [DEFAULT_NAMESPACE_STRING]), ALL_NAMESPACES_STRING]; - const namespacesClause = { terms: { namespaces: array } }; return { bool: { must: namespaces?.includes(ALL_NAMESPACES_STRING) - ? expect.not.arrayContaining([namespacesClause]) - : expect.arrayContaining([namespacesClause]), + ? [{ term: { type } }] + : [{ term: { type } }, { terms: { namespaces: array } }], must_not: [{ exists: { field: 'namespace' } }], }, }; diff --git a/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts b/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts index 2ecba42e408e77..cb58db171681af 100644 --- a/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts +++ b/src/core/server/saved_objects/service/lib/search_dsl/query_params.ts @@ -78,13 +78,19 @@ function getClauseForType( const searchAcrossAllNamespaces = namespaces.includes(ALL_NAMESPACES_STRING); if (registry.isMultiNamespace(type)) { - const namespacesFilterClause = searchAcrossAllNamespaces - ? {} - : { terms: { namespaces: [...namespaces, ALL_NAMESPACES_STRING] } }; + const typeFilterClause = { term: { type } }; + + const namespacesFilterClause = { + terms: { namespaces: [...namespaces, ALL_NAMESPACES_STRING] }, + }; + + const must = searchAcrossAllNamespaces + ? [typeFilterClause] + : [typeFilterClause, namespacesFilterClause]; return { bool: { - must: [{ term: { type } }, namespacesFilterClause], + must, must_not: [{ exists: { field: 'namespace' } }], }, }; diff --git a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts index aae9b89cdc61fe..19c6e9c7b8a7a7 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts @@ -98,11 +98,12 @@ export class IndexPatternsService { * Refresh cache of index pattern ids and titles */ private async refreshSavedObjectsCache() { - this.savedObjectsCache = await this.savedObjectsClient.find({ + const so = await this.savedObjectsClient.find({ type: 'index-pattern', fields: ['title'], perPage: 10000, }); + this.savedObjectsCache = so; } /** @@ -215,13 +216,13 @@ export class IndexPatternsService { * Get field list by providing { pattern } * @param options */ - getFieldsForWildcard = async (options: GetFieldsOptions = {}) => { + getFieldsForWildcard = async (options: GetFieldsOptions) => { const metaFields = await this.config.get(UI_SETTINGS.META_FIELDS); return this.apiClient.getFieldsForWildcard({ pattern: options.pattern, metaFields, type: options.type, - params: options.params || {}, + rollupIndex: options.rollupIndex, }); }; @@ -231,13 +232,13 @@ export class IndexPatternsService { */ getFieldsForIndexPattern = async ( indexPattern: IndexPattern | IndexPatternSpec, - options: GetFieldsOptions = {} + options?: GetFieldsOptions ) => this.getFieldsForWildcard({ - pattern: indexPattern.title as string, - ...options, type: indexPattern.type, - params: indexPattern.typeMeta && indexPattern.typeMeta.params, + rollupIndex: indexPattern?.typeMeta?.params?.rollup_index, + ...options, + pattern: indexPattern.title as string, }); /** @@ -374,10 +375,10 @@ export class IndexPatternsService { try { spec.fields = isFieldRefreshRequired ? await this.refreshFieldSpecMap(spec.fields || {}, id, spec.title as string, { - pattern: title, + pattern: title as string, metaFields: await this.config.get(UI_SETTINGS.META_FIELDS), type, - params: typeMeta && typeMeta.params, + rollupIndex: typeMeta?.params?.rollupIndex, }) : spec.fields; } catch (err) { diff --git a/src/plugins/data/common/index_patterns/types.ts b/src/plugins/data/common/index_patterns/types.ts index 3387bc3b3c19e4..b381cc0963333f 100644 --- a/src/plugins/data/common/index_patterns/types.ts +++ b/src/plugins/data/common/index_patterns/types.ts @@ -86,15 +86,22 @@ export interface SavedObjectsClientCommon { } export interface GetFieldsOptions { - pattern?: string; + pattern: string; type?: string; - params?: any; lookBack?: boolean; metaFields?: string[]; + rollupIndex?: string; +} + +export interface GetFieldsOptionsTimePattern { + pattern: string; + metaFields: string[]; + lookBack: number; + interval: string; } export interface IIndexPatternsApiClient { - getFieldsForTimePattern: (options: GetFieldsOptions) => Promise; + getFieldsForTimePattern: (options: GetFieldsOptionsTimePattern) => Promise; getFieldsForWildcard: (options: GetFieldsOptions) => Promise; } diff --git a/src/plugins/data/common/search/aggs/agg_config.test.ts b/src/plugins/data/common/search/aggs/agg_config.test.ts index f6fcc29805dc45..9bb47f5cb35755 100644 --- a/src/plugins/data/common/search/aggs/agg_config.test.ts +++ b/src/plugins/data/common/search/aggs/agg_config.test.ts @@ -680,16 +680,6 @@ describe('AggConfig', () => { const json = aggConfig.toExpressionAst()?.arguments.json; expect(json).toEqual([JSON.stringify(configStates.params.json)]); }); - - it(`returns undefined if an expressionName doesn't exist on the agg type`, () => { - const ac = new AggConfigs(indexPattern, [], { typesRegistry }); - const configStates = { - type: 'unknown type', - params: {}, - }; - const aggConfig = ac.createAggConfig(configStates); - expect(aggConfig.toExpressionAst()).toBe(undefined); - }); }); describe('#makeLabel', () => { diff --git a/src/plugins/data/common/search/aggs/agg_configs.test.ts b/src/plugins/data/common/search/aggs/agg_configs.test.ts index 803ccc70b98a76..d1c8e29a03cc7d 100644 --- a/src/plugins/data/common/search/aggs/agg_configs.test.ts +++ b/src/plugins/data/common/search/aggs/agg_configs.test.ts @@ -150,6 +150,27 @@ describe('AggConfigs', () => { ); expect(ac.aggs).toHaveLength(1); }); + + it(`throws if trying to add an agg which doesn't have a type in the registry`, () => { + const configStates = [ + { + enabled: true, + type: 'histogram', + params: {}, + }, + ]; + + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }); + expect(() => + ac.createAggConfig({ + enabled: true, + type: 'oops', + params: {}, + }) + ).toThrowErrorMatchingInlineSnapshot( + `"Unable to find a registered agg type for \\"oops\\"."` + ); + }); }); describe('#getRequestAggs', () => { diff --git a/src/plugins/data/common/search/aggs/agg_configs.ts b/src/plugins/data/common/search/aggs/agg_configs.ts index 282e6f3b538a49..368f44f1611321 100644 --- a/src/plugins/data/common/search/aggs/agg_configs.ts +++ b/src/plugins/data/common/search/aggs/agg_configs.ts @@ -18,6 +18,7 @@ */ import _ from 'lodash'; +import { i18n } from '@kbn/i18n'; import { Assign } from '@kbn/utility-types'; import { ISearchOptions, ISearchSource } from 'src/plugins/data/public'; @@ -122,15 +123,29 @@ export class AggConfigs { { addToAggConfigs = true } = {} ) => { const { type } = params; - let aggConfig; + const getType = (t: string) => { + const typeFromRegistry = this.typesRegistry.get(t); + + if (!typeFromRegistry) { + throw new Error( + i18n.translate('data.search.aggs.error.aggNotFound', { + defaultMessage: 'Unable to find a registered agg type for "{type}".', + values: { type: type as string }, + }) + ); + } + return typeFromRegistry; + }; + + let aggConfig; if (params instanceof AggConfig) { aggConfig = params; params.parent = this; } else { aggConfig = new AggConfig(this, { ...params, - type: typeof type === 'string' ? this.typesRegistry.get(type) : type, + type: typeof type === 'string' ? getType(type) : type, }); } diff --git a/src/plugins/expressions/common/expression_functions/specs/tests/__snapshots__/kibana.test.ts.snap b/src/plugins/data/common/search/expressions/__snapshots__/kibana.test.ts.snap similarity index 100% rename from src/plugins/expressions/common/expression_functions/specs/tests/__snapshots__/kibana.test.ts.snap rename to src/plugins/data/common/search/expressions/__snapshots__/kibana.test.ts.snap diff --git a/src/plugins/data/common/search/expressions/esaggs.ts b/src/plugins/data/common/search/expressions/esaggs.ts index 4f65babdcd3607..47d97a81a67b1f 100644 --- a/src/plugins/data/common/search/expressions/esaggs.ts +++ b/src/plugins/data/common/search/expressions/esaggs.ts @@ -17,11 +17,8 @@ * under the License. */ -import { - KibanaContext, - Datatable, - ExpressionFunctionDefinition, -} from '../../../../../plugins/expressions/common'; +import { Datatable, ExpressionFunctionDefinition } from 'src/plugins/expressions/common'; +import { KibanaContext } from './kibana_context_type'; type Input = KibanaContext | null; type Output = Promise; diff --git a/src/plugins/data/common/search/expressions/index.ts b/src/plugins/data/common/search/expressions/index.ts index 25839a805d8c58..28d892d0919561 100644 --- a/src/plugins/data/common/search/expressions/index.ts +++ b/src/plugins/data/common/search/expressions/index.ts @@ -17,5 +17,8 @@ * under the License. */ +export * from './kibana'; +export * from './kibana_context'; +export * from './kibana_context_type'; export * from './esaggs'; export * from './utils'; diff --git a/src/plugins/expressions/common/expression_functions/specs/tests/kibana.test.ts b/src/plugins/data/common/search/expressions/kibana.test.ts similarity index 92% rename from src/plugins/expressions/common/expression_functions/specs/tests/kibana.test.ts rename to src/plugins/data/common/search/expressions/kibana.test.ts index e5c4b92de4fdbc..58fee1ee1f6a6a 100644 --- a/src/plugins/expressions/common/expression_functions/specs/tests/kibana.test.ts +++ b/src/plugins/data/common/search/expressions/kibana.test.ts @@ -17,14 +17,14 @@ * under the License. */ +import { ExecutionContext } from 'src/plugins/expressions/common'; +import { kibana } from './kibana'; +import { ExpressionValueSearchContext } from './kibana_context_type'; import { functionWrapper } from './utils'; -import { kibana } from '../kibana'; -import { ExecutionContext } from '../../../execution/types'; -import { KibanaContext, ExpressionValueSearchContext } from '../../../expression_types'; describe('interpreter/functions#kibana', () => { const fn = functionWrapper(kibana); - let input: Partial; + let input: Partial; let search: ExpressionValueSearchContext; let context: ExecutionContext; diff --git a/src/plugins/expressions/common/expression_functions/specs/kibana.ts b/src/plugins/data/common/search/expressions/kibana.ts similarity index 82% rename from src/plugins/expressions/common/expression_functions/specs/kibana.ts rename to src/plugins/data/common/search/expressions/kibana.ts index 3ec4c23eab28d6..c31219284760a4 100644 --- a/src/plugins/expressions/common/expression_functions/specs/kibana.ts +++ b/src/plugins/data/common/search/expressions/kibana.ts @@ -18,8 +18,9 @@ */ import { i18n } from '@kbn/i18n'; -import { ExpressionFunctionDefinition } from '../types'; -import { ExpressionValueSearchContext } from '../../expression_types'; +import { ExecutionContext, ExpressionFunctionDefinition } from 'src/plugins/expressions/common'; +import { Adapters } from 'src/plugins/inspector/common'; +import { ExpressionValueSearchContext, ExecutionContextSearch } from './kibana_context_type'; const toArray = (query: undefined | T | T[]): T[] => !query ? [] : Array.isArray(query) ? query : [query]; @@ -29,7 +30,8 @@ export type ExpressionFunctionKibana = ExpressionFunctionDefinition< // TODO: Get rid of the `null` type below. ExpressionValueSearchContext | null, object, - ExpressionValueSearchContext + ExpressionValueSearchContext, + ExecutionContext >; export const kibana: ExpressionFunctionKibana = { @@ -38,7 +40,7 @@ export const kibana: ExpressionFunctionKibana = { inputTypes: ['kibana_context', 'null'], - help: i18n.translate('expressions.functions.kibana.help', { + help: i18n.translate('data.search.functions.kibana.help', { defaultMessage: 'Gets kibana global context', }), diff --git a/src/plugins/expressions/common/expression_functions/specs/kibana_context.ts b/src/plugins/data/common/search/expressions/kibana_context.ts similarity index 84% rename from src/plugins/expressions/common/expression_functions/specs/kibana_context.ts rename to src/plugins/data/common/search/expressions/kibana_context.ts index 2b7d1b8ed9d760..7bf14ff02316eb 100644 --- a/src/plugins/expressions/common/expression_functions/specs/kibana_context.ts +++ b/src/plugins/data/common/search/expressions/kibana_context.ts @@ -16,11 +16,13 @@ * specific language governing permissions and limitations * under the License. */ + import { uniqBy } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { ExpressionFunctionDefinition } from '../../expression_functions'; -import { KibanaContext } from '../../expression_types'; -import { Query, uniqFilters } from '../../../../data/common'; +import { ExpressionFunctionDefinition, ExecutionContext } from 'src/plugins/expressions/common'; +import { Adapters } from 'src/plugins/inspector/common'; +import { Query, uniqFilters } from '../../query'; +import { ExecutionContextSearch, KibanaContext } from './kibana_context_type'; interface Arguments { q?: string | null; @@ -33,7 +35,8 @@ export type ExpressionFunctionKibanaContext = ExpressionFunctionDefinition< 'kibana_context', KibanaContext | null, Arguments, - Promise + Promise, + ExecutionContext >; const getParsedValue = (data: any, defaultValue: any) => @@ -49,7 +52,7 @@ export const kibanaContextFunction: ExpressionFunctionKibanaContext = { name: 'kibana_context', type: 'kibana_context', inputTypes: ['kibana_context', 'null'], - help: i18n.translate('expressions.functions.kibana_context.help', { + help: i18n.translate('data.search.functions.kibana_context.help', { defaultMessage: 'Updates kibana global context', }), args: { @@ -57,28 +60,28 @@ export const kibanaContextFunction: ExpressionFunctionKibanaContext = { types: ['string', 'null'], aliases: ['query', '_'], default: null, - help: i18n.translate('expressions.functions.kibana_context.q.help', { + help: i18n.translate('data.search.functions.kibana_context.q.help', { defaultMessage: 'Specify Kibana free form text query', }), }, filters: { types: ['string', 'null'], default: '"[]"', - help: i18n.translate('expressions.functions.kibana_context.filters.help', { + help: i18n.translate('data.search.functions.kibana_context.filters.help', { defaultMessage: 'Specify Kibana generic filters', }), }, timeRange: { types: ['string', 'null'], default: null, - help: i18n.translate('expressions.functions.kibana_context.timeRange.help', { + help: i18n.translate('data.search.functions.kibana_context.timeRange.help', { defaultMessage: 'Specify Kibana time range filter', }), }, savedSearchId: { types: ['string', 'null'], default: null, - help: i18n.translate('expressions.functions.kibana_context.savedSearchId.help', { + help: i18n.translate('data.search.functions.kibana_context.savedSearchId.help', { defaultMessage: 'Specify saved search ID to be used for queries and filters', }), }, diff --git a/src/plugins/expressions/common/expression_types/specs/kibana_context.ts b/src/plugins/data/common/search/expressions/kibana_context_type.ts similarity index 79% rename from src/plugins/expressions/common/expression_types/specs/kibana_context.ts rename to src/plugins/data/common/search/expressions/kibana_context_type.ts index 3af7b990429c03..a5b459a607991a 100644 --- a/src/plugins/expressions/common/expression_types/specs/kibana_context.ts +++ b/src/plugins/data/common/search/expressions/kibana_context_type.ts @@ -17,8 +17,16 @@ * under the License. */ -import { ExpressionValueBoxed } from '../types'; -import { ExecutionContextSearch } from '../../execution/types'; +import { ExpressionValueBoxed } from 'src/plugins/expressions/common'; +import { Filter } from '../../es_query'; +import { Query, TimeRange } from '../../query'; + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +export type ExecutionContextSearch = { + filters?: Filter[]; + query?: Query | Query[]; + timeRange?: TimeRange; +}; export type ExpressionValueSearchContext = ExpressionValueBoxed< 'kibana_context', diff --git a/src/plugins/data/common/search/expressions/utils/function_wrapper.ts b/src/plugins/data/common/search/expressions/utils/function_wrapper.ts new file mode 100644 index 00000000000000..b5e45d9ca1de05 --- /dev/null +++ b/src/plugins/data/common/search/expressions/utils/function_wrapper.ts @@ -0,0 +1,34 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { mapValues } from 'lodash'; +import { AnyExpressionFunctionDefinition, ExecutionContext } from 'src/plugins/expressions/common'; + +/** + * Takes a function spec and passes in default args, + * overriding with any provided args. + */ +export const functionWrapper = (spec: AnyExpressionFunctionDefinition) => { + const defaultArgs = mapValues(spec.args, (argSpec) => argSpec.default); + return ( + context: object | null, + args: Record = {}, + handlers: ExecutionContext = {} as ExecutionContext + ) => spec.fn(context, { ...defaultArgs, ...args }, handlers); +}; diff --git a/src/plugins/data/common/search/expressions/utils/index.ts b/src/plugins/data/common/search/expressions/utils/index.ts index 75c1809770c787..39f88b0f13feed 100644 --- a/src/plugins/data/common/search/expressions/utils/index.ts +++ b/src/plugins/data/common/search/expressions/utils/index.ts @@ -18,3 +18,4 @@ */ export * from './courier_inspector_stats'; +export * from './function_wrapper'; diff --git a/src/plugins/data/common/utils/index.ts b/src/plugins/data/common/utils/index.ts index 33989f3ad50a7a..8b8686c51b9c19 100644 --- a/src/plugins/data/common/utils/index.ts +++ b/src/plugins/data/common/utils/index.ts @@ -19,4 +19,3 @@ /** @internal */ export { shortenDottedString } from './shorten_dotted_string'; -export { AbortError, toPromise, getCombinedSignal } from './abort_utils'; diff --git a/src/plugins/data/kibana.json b/src/plugins/data/kibana.json index 9cb9b1745373a8..d6f2534bd5e3be 100644 --- a/src/plugins/data/kibana.json +++ b/src/plugins/data/kibana.json @@ -8,7 +8,7 @@ "uiActions" ], "optionalPlugins": ["usageCollection"], - "extraPublicDirs": ["common", "common/utils/abort_utils"], + "extraPublicDirs": ["common"], "requiredBundles": [ "usageCollection", "kibanaUtils", diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index ce020a97423996..129addf3de70ee 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -338,6 +338,12 @@ export { OptionedParamType, OptionedValueProp, ParsedInterval, + // expressions + ExecutionContextSearch, + ExpressionFunctionKibana, + ExpressionFunctionKibanaContext, + ExpressionValueSearchContext, + KibanaContext, // tabify TabbedAggColumn, TabbedAggRow, diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.test.ts b/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.test.ts index 37ee80c2c29e4a..8c48ee44fba9c4 100644 --- a/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.test.ts +++ b/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.test.ts @@ -32,7 +32,12 @@ describe('IndexPatternsApiClient', () => { test('uses the right URI to fetch fields for time patterns', async function () { const expectedPath = '/api/index_patterns/_fields_for_time_pattern'; - await indexPatternsApiClient.getFieldsForTimePattern(); + await indexPatternsApiClient.getFieldsForTimePattern({ + pattern: 'blah', + metaFields: [], + lookBack: 5, + interval: '', + }); expect(fetchSpy).toHaveBeenCalledWith(expectedPath, expect.any(Object)); }); @@ -40,15 +45,7 @@ describe('IndexPatternsApiClient', () => { test('uses the right URI to fetch fields for wildcard', async function () { const expectedPath = '/api/index_patterns/_fields_for_wildcard'; - await indexPatternsApiClient.getFieldsForWildcard(); - - expect(fetchSpy).toHaveBeenCalledWith(expectedPath, expect.any(Object)); - }); - - test('uses the right URI to fetch fields for wildcard given a type', async function () { - const expectedPath = '/api/index_patterns/rollup/_fields_for_wildcard'; - - await indexPatternsApiClient.getFieldsForWildcard({ type: 'rollup' }); + await indexPatternsApiClient.getFieldsForWildcard({ pattern: 'blah' }); expect(fetchSpy).toHaveBeenCalledWith(expectedPath, expect.any(Object)); }); diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts b/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts index 377a3f7f91a50a..ca0f35d6612b2e 100644 --- a/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts +++ b/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts @@ -19,7 +19,11 @@ import { HttpSetup } from 'src/core/public'; import { IndexPatternMissingIndices } from '../../../common/index_patterns/lib'; -import { GetFieldsOptions, IIndexPatternsApiClient } from '../../../common/index_patterns/types'; +import { + GetFieldsOptions, + IIndexPatternsApiClient, + GetFieldsOptionsTimePattern, +} from '../../../common/index_patterns/types'; const API_BASE_URL: string = `/api/index_patterns/`; @@ -48,7 +52,7 @@ export class IndexPatternsApiClient implements IIndexPatternsApiClient { return API_BASE_URL + path.filter(Boolean).map(encodeURIComponent).join('/'); } - getFieldsForTimePattern(options: GetFieldsOptions = {}) { + getFieldsForTimePattern(options: GetFieldsOptionsTimePattern) { const { pattern, lookBack, metaFields } = options; const url = this._getUrl(['_fields_for_time_pattern']); @@ -60,27 +64,12 @@ export class IndexPatternsApiClient implements IIndexPatternsApiClient { }).then((resp: any) => resp.fields); } - getFieldsForWildcard(options: GetFieldsOptions = {}) { - const { pattern, metaFields, type, params } = options; - - let url; - let query; - - if (type) { - url = this._getUrl([type, '_fields_for_wildcard']); - query = { - pattern, - meta_fields: metaFields, - params: JSON.stringify(params), - }; - } else { - url = this._getUrl(['_fields_for_wildcard']); - query = { - pattern, - meta_fields: metaFields, - }; - } - - return this._request(url, query).then((resp: any) => resp.fields); + getFieldsForWildcard({ pattern, metaFields, type, rollupIndex }: GetFieldsOptions) { + return this._request(this._getUrl(['_fields_for_wildcard']), { + pattern, + meta_fields: metaFields, + type, + rollup_index: rollupIndex, + }).then((resp: any) => resp.fields); } } diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index d52edbe5b11dd7..31b05bd4763a24 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -6,6 +6,7 @@ import { $Values } from '@kbn/utility-types'; import { Action } from 'history'; +import { Adapters as Adapters_2 } from 'src/plugins/inspector/common'; import { ApiResponse } from '@elastic/elasticsearch'; import { ApiResponse as ApiResponse_2 } from '@elastic/elasticsearch/lib/Transport'; import { ApplicationStart } from 'kibana/public'; @@ -16,6 +17,7 @@ import { CoreSetup } from 'src/core/public'; import { CoreSetup as CoreSetup_2 } from 'kibana/public'; import { CoreStart } from 'kibana/public'; import { CoreStart as CoreStart_2 } from 'src/core/public'; +import { Datatable as Datatable_2 } from 'src/plugins/expressions/common'; import { DatatableColumn as DatatableColumn_2 } from 'src/plugins/expressions'; import { Ensure } from '@kbn/utility-types'; import { EnvironmentMode } from '@kbn/config'; @@ -26,8 +28,12 @@ import { EuiComboBoxProps } from '@elastic/eui'; import { EuiConfirmModalProps } from '@elastic/eui'; import { EuiGlobalToastListToast } from '@elastic/eui'; import { ExclusiveUnion } from '@elastic/eui'; +import { ExecutionContext } from 'src/plugins/expressions/common'; import { ExpressionAstFunction } from 'src/plugins/expressions/common'; +import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common'; +import { ExpressionFunctionDefinition as ExpressionFunctionDefinition_2 } from 'src/plugins/expressions/public'; import { ExpressionsSetup } from 'src/plugins/expressions/public'; +import { ExpressionValueBoxed } from 'src/plugins/expressions/common'; import { History } from 'history'; import { Href } from 'history'; import { IconType } from '@elastic/eui'; @@ -65,7 +71,7 @@ import { Required } from '@kbn/utility-types'; import * as Rx from 'rxjs'; import { SavedObject } from 'src/core/server'; import { SavedObject as SavedObject_2 } from 'src/core/public'; -import { SavedObjectReference as SavedObjectReference_2 } from 'src/core/types'; +import { SavedObjectReference } from 'src/core/types'; import { SavedObjectsClientContract } from 'src/core/public'; import { Search } from '@elastic/elasticsearch/api/requestParams'; import { SearchResponse } from 'elasticsearch'; @@ -80,7 +86,6 @@ import { UiActionsSetup } from 'src/plugins/ui_actions/public'; import { UiActionsStart } from 'src/plugins/ui_actions/public'; import { Unit } from '@elastic/datemath'; import { UnregisterCallback } from 'history'; -import { UnwrapPromiseOrReturn } from '@kbn/utility-types'; import { UserProvidedValues } from 'src/core/server/types'; // Warning: (ae-missing-release-tag) "ACTION_GLOBAL_APPLY_FILTER" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -525,7 +530,6 @@ export enum ES_FIELD_TYPES { // @public (undocumented) export const ES_SEARCH_STRATEGY = "es"; -// Warning: (ae-forgotten-export) The symbol "ExpressionFunctionDefinition" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "Input" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "Arguments" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "Output" needs to be exported by the entry point index.d.ts @@ -541,7 +545,7 @@ export type EsaggsExpressionFunctionDefinition = ExpressionFunctionDefinition<'e // Warning: (ae-missing-release-tag) "EsdslExpressionFunctionDefinition" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type EsdslExpressionFunctionDefinition = ExpressionFunctionDefinition; +export type EsdslExpressionFunctionDefinition = ExpressionFunctionDefinition_2; // Warning: (ae-missing-release-tag) "esFilters" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -647,6 +651,15 @@ export type EsQuerySortValue = Record; +// Warning: (ae-missing-release-tag) "ExecutionContextSearch" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type ExecutionContextSearch = { + filters?: Filter[]; + query?: Query | Query[]; + timeRange?: TimeRange; +}; + // Warning: (ae-missing-release-tag) "ExistsFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -655,12 +668,28 @@ export type ExistsFilter = Filter & { exists?: FilterExistsProperty; }; +// Warning: (ae-missing-release-tag) "ExpressionFunctionKibana" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type ExpressionFunctionKibana = ExpressionFunctionDefinition<'kibana', ExpressionValueSearchContext | null, object, ExpressionValueSearchContext, ExecutionContext>; + +// Warning: (ae-forgotten-export) The symbol "Arguments" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "ExpressionFunctionKibanaContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type ExpressionFunctionKibanaContext = ExpressionFunctionDefinition<'kibana_context', KibanaContext | null, Arguments_2, Promise, ExecutionContext>; + +// Warning: (ae-missing-release-tag) "ExpressionValueSearchContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type ExpressionValueSearchContext = ExpressionValueBoxed<'kibana_context', ExecutionContextSearch>; + // Warning: (ae-missing-release-tag) "extractReferences" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export const extractSearchSourceReferences: (state: SearchSourceFields) => [SearchSourceFields & { indexRefName?: string; -}, SavedObjectReference_2[]]; +}, SavedObjectReference[]]; // Warning: (ae-missing-release-tag) "FieldFormat" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1338,9 +1367,9 @@ export class IndexPatternsService { // (undocumented) getCache: () => Promise[] | null | undefined>; getDefault: () => Promise; - getFieldsForIndexPattern: (indexPattern: IndexPattern | IndexPatternSpec, options?: GetFieldsOptions) => Promise; + getFieldsForIndexPattern: (indexPattern: IndexPattern | IndexPatternSpec, options?: GetFieldsOptions | undefined) => Promise; // Warning: (ae-forgotten-export) The symbol "GetFieldsOptions" needs to be exported by the entry point index.d.ts - getFieldsForWildcard: (options?: GetFieldsOptions) => Promise; + getFieldsForWildcard: (options: GetFieldsOptions) => Promise; getIds: (refresh?: boolean) => Promise; getIdsWithTitle: (refresh?: boolean) => Promise SearchSourceFields; +}, references: SavedObjectReference[]) => SearchSourceFields; // Warning: (ae-missing-release-tag) "InputTimeRange" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1510,6 +1539,11 @@ export enum KBN_FIELD_TYPES { UNKNOWN = "unknown" } +// Warning: (ae-missing-release-tag) "KibanaContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type KibanaContext = ExpressionValueSearchContext; + // Warning: (ae-missing-release-tag) "KueryNode" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -1962,8 +1996,8 @@ export const search: { // Warning: (ae-missing-release-tag) "SearchBar" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const SearchBar: React.ComponentClass, "query" | "isLoading" | "filters" | "onRefresh" | "onRefreshChange" | "refreshInterval" | "indexPatterns" | "dataTestSubj" | "timeHistory" | "customSubmitButton" | "screenTitle" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "indicateNoData" | "onFiltersUpdated">, any> & { - WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; +export const SearchBar: React.ComponentClass, "query" | "isLoading" | "filters" | "onRefresh" | "onRefreshChange" | "refreshInterval" | "indexPatterns" | "dataTestSubj" | "screenTitle" | "showQueryInput" | "showDatePicker" | "showAutoRefreshOnly" | "dateRangeFrom" | "dateRangeTo" | "isRefreshPaused" | "customSubmitButton" | "timeHistory" | "indicateNoData" | "onFiltersUpdated" | "savedQuery" | "showSaveQuery" | "onClearSavedQuery" | "showQueryBar" | "showFilterBar" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated">, any> & { + WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; }; // Warning: (ae-forgotten-export) The symbol "SearchBarOwnProps" needs to be exported by the entry point index.d.ts @@ -2321,21 +2355,21 @@ export const UI_SETTINGS: { // src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:387:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:387:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:387:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:387:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:390:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:399:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:406:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:407:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:410:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:411:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:414:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:393:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:393:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:393:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:393:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:395:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:396:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:405:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:406:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:407:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:408:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:413:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:416:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:417:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:420:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:45:5 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/src/plugins/data/public/search/errors/timeout_error.test.tsx b/src/plugins/data/public/search/errors/timeout_error.test.tsx index ad3384c389fbf2..2547ee41cbbd7a 100644 --- a/src/plugins/data/public/search/errors/timeout_error.test.tsx +++ b/src/plugins/data/public/search/errors/timeout_error.test.tsx @@ -23,7 +23,7 @@ import { coreMock } from '../../../../../core/public/mocks'; const startMock = coreMock.createStart(); import { mount } from 'enzyme'; -import { AbortError } from 'src/plugins/data/common'; +import { AbortError } from '../../../../kibana_utils/public'; describe('SearchTimeoutError', () => { beforeEach(() => { diff --git a/src/plugins/data/public/search/expressions/esdsl.ts b/src/plugins/data/public/search/expressions/esdsl.ts index 2efb21671b5b7e..07e904928744f5 100644 --- a/src/plugins/data/public/search/expressions/esdsl.ts +++ b/src/plugins/data/public/search/expressions/esdsl.ts @@ -18,15 +18,12 @@ */ import { i18n } from '@kbn/i18n'; -import { - KibanaContext, - ExpressionFunctionDefinition, -} from '../../../../../plugins/expressions/public'; +import { ExpressionFunctionDefinition } from 'src/plugins/expressions/public'; import { getSearchService, getUiSettings } from '../../services'; import { EsRawResponse } from './es_raw_response'; import { RequestStatistics, RequestAdapter } from '../../../../inspector/common'; -import { IEsSearchResponse } from '../../../common/search/es_search'; +import { IEsSearchResponse, KibanaContext } from '../../../common/search'; import { buildEsQuery, getEsQueryConfig } from '../../../common/es_query/es_query'; import { DataPublicPluginStart } from '../../types'; diff --git a/src/plugins/data/public/search/search_interceptor.test.ts b/src/plugins/data/public/search/search_interceptor.test.ts index 472caa5e4f45ff..60274261da25f4 100644 --- a/src/plugins/data/public/search/search_interceptor.test.ts +++ b/src/plugins/data/public/search/search_interceptor.test.ts @@ -21,7 +21,7 @@ import { CoreSetup, CoreStart } from '../../../../core/public'; import { coreMock } from '../../../../core/public/mocks'; import { IEsSearchRequest } from '../../common/search'; import { SearchInterceptor } from './search_interceptor'; -import { AbortError } from '../../common'; +import { AbortError } from '../../../kibana_utils/public'; import { SearchTimeoutError, PainlessError, TimeoutErrorMode } from './errors'; import { searchServiceMock } from './mocks'; import { ISearchStart } from '.'; diff --git a/src/plugins/data/public/search/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor.ts index 3584d75ab86bb1..78e65802bcf99b 100644 --- a/src/plugins/data/public/search/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor.ts @@ -24,13 +24,11 @@ import { PublicMethodsOf } from '@kbn/utility-types'; import { CoreStart, CoreSetup, ToastsSetup } from 'kibana/public'; import { i18n } from '@kbn/i18n'; import { - AbortError, IKibanaSearchRequest, IKibanaSearchResponse, ISearchOptions, ES_SEARCH_STRATEGY, ISessionService, - getCombinedSignal, } from '../../common'; import { SearchUsageCollector } from './collectors'; import { @@ -43,6 +41,7 @@ import { getHttpError, } from './errors'; import { toMountPoint } from '../../../kibana_react/public'; +import { AbortError, getCombinedAbortSignal } from '../../../kibana_utils/public'; export interface SearchInterceptorDeps { http: CoreSetup['http']; @@ -170,7 +169,9 @@ export class SearchInterceptor { ...(abortSignal ? [abortSignal] : []), ]; - const { signal: combinedSignal, cleanup: cleanupCombinedSignal } = getCombinedSignal(signals); + const { signal: combinedSignal, cleanup: cleanupCombinedSignal } = getCombinedAbortSignal( + signals + ); const cleanup = () => { subscription.unsubscribe(); combinedSignal.removeEventListener('abort', cleanup); diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index e5a50077518aff..96fb3f91ea85fe 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -23,10 +23,13 @@ import { ISearchSetup, ISearchStart, SearchEnhancements } from './types'; import { handleResponse } from './fetch'; import { + kibana, + kibanaContext, + kibanaContextFunction, ISearchGeneric, - SearchSourceService, - SearchSourceDependencies, ISessionService, + SearchSourceDependencies, + SearchSourceService, } from '../../common/search'; import { getCallMsearch } from './legacy'; import { AggsService, AggsStartDependencies } from './aggs'; @@ -85,6 +88,10 @@ export class SearchService implements Plugin { session: this.sessionService, }); + expressions.registerFunction(kibana); + expressions.registerFunction(kibanaContextFunction); + expressions.registerType(kibanaContext); + expressions.registerFunction(esdsl); expressions.registerType(esRawResponse); diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 9a9b8b67730cc8..e24869f5237ead 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -134,6 +134,8 @@ export { FieldDescriptor as IndexPatternFieldDescriptor, shouldReadFieldFromDocValues, // used only in logstash_fields fixture FieldDescriptor, + mergeCapabilitiesWithFields, + getCapabilitiesForRollupIndices, } from './index_patterns'; export { @@ -206,6 +208,12 @@ export { OptionedParamType, OptionedValueProp, ParsedInterval, + // expressions + ExecutionContextSearch, + ExpressionFunctionKibana, + ExpressionFunctionKibanaContext, + ExpressionValueSearchContext, + KibanaContext, // search ISearchOptions, IEsSearchRequest, diff --git a/src/plugins/data/server/index_patterns/fetcher/index.ts b/src/plugins/data/server/index_patterns/fetcher/index.ts index 19306696885dbe..5d8ef62df96270 100644 --- a/src/plugins/data/server/index_patterns/fetcher/index.ts +++ b/src/plugins/data/server/index_patterns/fetcher/index.ts @@ -18,4 +18,8 @@ */ export * from './index_patterns_fetcher'; -export { shouldReadFieldFromDocValues } from './lib'; +export { + shouldReadFieldFromDocValues, + mergeCapabilitiesWithFields, + getCapabilitiesForRollupIndices, +} from './lib'; diff --git a/src/plugins/data/server/index_patterns/fetcher/index_patterns_fetcher.ts b/src/plugins/data/server/index_patterns/fetcher/index_patterns_fetcher.ts index e75b8761984ec9..24dad39088b8fe 100644 --- a/src/plugins/data/server/index_patterns/fetcher/index_patterns_fetcher.ts +++ b/src/plugins/data/server/index_patterns/fetcher/index_patterns_fetcher.ts @@ -18,8 +18,15 @@ */ import { ElasticsearchClient } from 'kibana/server'; +import { keyBy } from 'lodash'; -import { getFieldCapabilities, resolveTimePattern, createNoMatchingIndicesError } from './lib'; +import { + getFieldCapabilities, + resolveTimePattern, + createNoMatchingIndicesError, + getCapabilitiesForRollupIndices, + mergeCapabilitiesWithFields, +} from './lib'; export interface FieldDescriptor { aggregatable: boolean; @@ -58,11 +65,44 @@ export class IndexPatternsFetcher { pattern: string | string[]; metaFields?: string[]; fieldCapsOptions?: { allow_no_indices: boolean }; + type?: string; + rollupIndex?: string; }): Promise { - const { pattern, metaFields, fieldCapsOptions } = options; - return await getFieldCapabilities(this.elasticsearchClient, pattern, metaFields, { - allow_no_indices: fieldCapsOptions ? fieldCapsOptions.allow_no_indices : this.allowNoIndices, - }); + const { pattern, metaFields, fieldCapsOptions, type, rollupIndex } = options; + const fieldCapsResponse = await getFieldCapabilities( + this.elasticsearchClient, + pattern, + metaFields, + { + allow_no_indices: fieldCapsOptions + ? fieldCapsOptions.allow_no_indices + : this.allowNoIndices, + } + ); + if (type === 'rollup' && rollupIndex) { + const rollupFields: FieldDescriptor[] = []; + const rollupIndexCapabilities = getCapabilitiesForRollupIndices( + ( + await this.elasticsearchClient.rollup.getRollupIndexCaps({ + index: rollupIndex, + }) + ).body + )[rollupIndex].aggs; + const fieldCapsResponseObj = keyBy(fieldCapsResponse, 'name'); + + // Keep meta fields + metaFields!.forEach( + (field: string) => + fieldCapsResponseObj[field] && rollupFields.push(fieldCapsResponseObj[field]) + ); + + return mergeCapabilitiesWithFields( + rollupIndexCapabilities, + fieldCapsResponseObj, + rollupFields + ); + } + return fieldCapsResponse; } /** diff --git a/src/plugins/data/server/index_patterns/fetcher/lib/__tests__/fixtures/index.js b/src/plugins/data/server/index_patterns/fetcher/lib/__tests__/fixtures/index.js new file mode 100644 index 00000000000000..d675702ae54e93 --- /dev/null +++ b/src/plugins/data/server/index_patterns/fetcher/lib/__tests__/fixtures/index.js @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { jobs } from './jobs'; diff --git a/x-pack/plugins/rollup/server/lib/__tests__/fixtures/jobs.js b/src/plugins/data/server/index_patterns/fetcher/lib/__tests__/fixtures/jobs.js similarity index 65% rename from x-pack/plugins/rollup/server/lib/__tests__/fixtures/jobs.js rename to src/plugins/data/server/index_patterns/fetcher/lib/__tests__/fixtures/jobs.js index c03b7c33abe0a1..39ebd9595eeafc 100644 --- a/x-pack/plugins/rollup/server/lib/__tests__/fixtures/jobs.js +++ b/src/plugins/data/server/index_patterns/fetcher/lib/__tests__/fixtures/jobs.js @@ -1,7 +1,20 @@ /* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ export const jobs = [ diff --git a/x-pack/plugins/rollup/server/lib/__tests__/jobs_compatibility.js b/src/plugins/data/server/index_patterns/fetcher/lib/__tests__/jobs_compatibility.js similarity index 81% rename from x-pack/plugins/rollup/server/lib/__tests__/jobs_compatibility.js rename to src/plugins/data/server/index_patterns/fetcher/lib/__tests__/jobs_compatibility.js index a67f67de859f5b..e3c93ac1f86160 100644 --- a/x-pack/plugins/rollup/server/lib/__tests__/jobs_compatibility.js +++ b/src/plugins/data/server/index_patterns/fetcher/lib/__tests__/jobs_compatibility.js @@ -1,8 +1,22 @@ /* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ + import expect from '@kbn/expect'; import { areJobsCompatible, mergeJobConfigurations } from '../jobs_compatibility'; import { jobs } from './fixtures'; diff --git a/src/plugins/data/server/index_patterns/fetcher/lib/index.ts b/src/plugins/data/server/index_patterns/fetcher/lib/index.ts index 20e74d2b1a579d..b2fd3a1a09a251 100644 --- a/src/plugins/data/server/index_patterns/fetcher/lib/index.ts +++ b/src/plugins/data/server/index_patterns/fetcher/lib/index.ts @@ -20,3 +20,5 @@ export { getFieldCapabilities, shouldReadFieldFromDocValues } from './field_capabilities'; export { resolveTimePattern } from './resolve_time_pattern'; export { createNoMatchingIndicesError } from './errors'; +export * from './merge_capabilities_with_fields'; +export * from './map_capabilities'; diff --git a/x-pack/plugins/rollup/server/lib/jobs_compatibility.ts b/src/plugins/data/server/index_patterns/fetcher/lib/jobs_compatibility.ts similarity index 79% rename from x-pack/plugins/rollup/server/lib/jobs_compatibility.ts rename to src/plugins/data/server/index_patterns/fetcher/lib/jobs_compatibility.ts index f5f54cf9a54e86..f21de8907ee245 100644 --- a/x-pack/plugins/rollup/server/lib/jobs_compatibility.ts +++ b/src/plugins/data/server/index_patterns/fetcher/lib/jobs_compatibility.ts @@ -1,7 +1,20 @@ /* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ import { isEqual } from 'lodash'; diff --git a/src/plugins/data/server/index_patterns/fetcher/lib/map_capabilities.ts b/src/plugins/data/server/index_patterns/fetcher/lib/map_capabilities.ts new file mode 100644 index 00000000000000..61871748340128 --- /dev/null +++ b/src/plugins/data/server/index_patterns/fetcher/lib/map_capabilities.ts @@ -0,0 +1,37 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { mergeJobConfigurations } from './jobs_compatibility'; + +export function getCapabilitiesForRollupIndices(indices: { [key: string]: any }) { + const indexNames = Object.keys(indices); + const capabilities = {} as { [key: string]: any }; + + indexNames.forEach((index) => { + try { + capabilities[index] = mergeJobConfigurations(indices[index].rollup_jobs); + } catch (e) { + capabilities[index] = { + error: e.message, + }; + } + }); + + return capabilities; +} diff --git a/x-pack/plugins/rollup/server/lib/merge_capabilities_with_fields.ts b/src/plugins/data/server/index_patterns/fetcher/lib/merge_capabilities_with_fields.ts similarity index 70% rename from x-pack/plugins/rollup/server/lib/merge_capabilities_with_fields.ts rename to src/plugins/data/server/index_patterns/fetcher/lib/merge_capabilities_with_fields.ts index 51111e9e45d0ab..dd69f4b7ff0078 100644 --- a/x-pack/plugins/rollup/server/lib/merge_capabilities_with_fields.ts +++ b/src/plugins/data/server/index_patterns/fetcher/lib/merge_capabilities_with_fields.ts @@ -1,20 +1,30 @@ /* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ // Merge rollup capabilities information with field information -export interface Field { - name?: string; - [key: string]: any; -} +import { FieldDescriptor } from '../index_patterns_fetcher'; export const mergeCapabilitiesWithFields = ( rollupIndexCapabilities: { [key: string]: any }, fieldsFromFieldCapsApi: { [key: string]: any }, - previousFields: Field[] = [] + previousFields: FieldDescriptor[] = [] ) => { const rollupFields = [...previousFields]; const rollupFieldNames: string[] = []; diff --git a/src/plugins/data/server/index_patterns/index.ts b/src/plugins/data/server/index_patterns/index.ts index 683d1c445fd72e..3305b1bb9a92f1 100644 --- a/src/plugins/data/server/index_patterns/index.ts +++ b/src/plugins/data/server/index_patterns/index.ts @@ -17,5 +17,11 @@ * under the License. */ export * from './utils'; -export { IndexPatternsFetcher, FieldDescriptor, shouldReadFieldFromDocValues } from './fetcher'; +export { + IndexPatternsFetcher, + FieldDescriptor, + shouldReadFieldFromDocValues, + mergeCapabilitiesWithFields, + getCapabilitiesForRollupIndices, +} from './fetcher'; export { IndexPatternsService, IndexPatternsServiceStart } from './index_patterns_service'; diff --git a/src/plugins/data/server/index_patterns/index_patterns_api_client.ts b/src/plugins/data/server/index_patterns/index_patterns_api_client.ts index 2dc6f40c5a6f1f..21a3bf6e73e611 100644 --- a/src/plugins/data/server/index_patterns/index_patterns_api_client.ts +++ b/src/plugins/data/server/index_patterns/index_patterns_api_client.ts @@ -17,13 +17,30 @@ * under the License. */ -import { GetFieldsOptions, IIndexPatternsApiClient } from '../../common/index_patterns/types'; +import { ElasticsearchClient } from 'kibana/server'; +import { + GetFieldsOptions, + IIndexPatternsApiClient, + GetFieldsOptionsTimePattern, +} from '../../common/index_patterns/types'; +import { IndexPatternsFetcher } from './fetcher'; export class IndexPatternsApiServer implements IIndexPatternsApiClient { - async getFieldsForTimePattern(options: GetFieldsOptions = {}) { - throw new Error('IndexPatternsApiServer - getFieldsForTimePattern not defined'); + esClient: ElasticsearchClient; + constructor(elasticsearchClient: ElasticsearchClient) { + this.esClient = elasticsearchClient; } - async getFieldsForWildcard(options: GetFieldsOptions = {}) { - throw new Error('IndexPatternsApiServer - getFieldsForWildcard not defined'); + async getFieldsForWildcard({ pattern, metaFields, type, rollupIndex }: GetFieldsOptions) { + const indexPatterns = new IndexPatternsFetcher(this.esClient); + return await indexPatterns.getFieldsForWildcard({ + pattern, + metaFields, + type, + rollupIndex, + }); + } + async getFieldsForTimePattern(options: GetFieldsOptionsTimePattern) { + const indexPatterns = new IndexPatternsFetcher(this.esClient); + return await indexPatterns.getFieldsForTimePattern(options); } } diff --git a/src/plugins/data/server/index_patterns/index_patterns_service.ts b/src/plugins/data/server/index_patterns/index_patterns_service.ts index d665e3715fa72a..af2d4d6a73e0f8 100644 --- a/src/plugins/data/server/index_patterns/index_patterns_service.ts +++ b/src/plugins/data/server/index_patterns/index_patterns_service.ts @@ -17,7 +17,14 @@ * under the License. */ -import { CoreSetup, CoreStart, Plugin, Logger, SavedObjectsClientContract } from 'kibana/server'; +import { + CoreSetup, + CoreStart, + Plugin, + Logger, + SavedObjectsClientContract, + ElasticsearchClient, +} from 'kibana/server'; import { registerRoutes } from './routes'; import { indexPatternSavedObjectType } from '../saved_objects'; import { capabilitiesProvider } from './capabilities_provider'; @@ -29,7 +36,8 @@ import { SavedObjectsClientServerToCommon } from './saved_objects_client_wrapper export interface IndexPatternsServiceStart { indexPatternsServiceFactory: ( - savedObjectsClient: SavedObjectsClientContract + savedObjectsClient: SavedObjectsClientContract, + elasticsearchClient: ElasticsearchClient ) => Promise; } @@ -50,14 +58,17 @@ export class IndexPatternsService implements Plugin { + indexPatternsServiceFactory: async ( + savedObjectsClient: SavedObjectsClientContract, + elasticsearchClient: ElasticsearchClient + ) => { const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient); const formats = await fieldFormats.fieldFormatServiceFactory(uiSettingsClient); return new IndexPatternsCommonService({ uiSettings: new UiSettingsServerToCommon(uiSettingsClient), savedObjectsClient: new SavedObjectsClientServerToCommon(savedObjectsClient), - apiClient: new IndexPatternsApiServer(), + apiClient: new IndexPatternsApiServer(elasticsearchClient), fieldFormats: formats, onError: (error) => { logger.error(error); diff --git a/src/plugins/data/server/index_patterns/routes.ts b/src/plugins/data/server/index_patterns/routes.ts index 041eb235d01e08..f8af52954fc61e 100644 --- a/src/plugins/data/server/index_patterns/routes.ts +++ b/src/plugins/data/server/index_patterns/routes.ts @@ -42,13 +42,15 @@ export function registerRoutes(http: HttpServiceSetup) { meta_fields: schema.oneOf([schema.string(), schema.arrayOf(schema.string())], { defaultValue: [], }), + type: schema.maybe(schema.string()), + rollup_index: schema.maybe(schema.string()), }), }, }, async (context, request, response) => { const { asCurrentUser } = context.core.elasticsearch.client; const indexPatterns = new IndexPatternsFetcher(asCurrentUser); - const { pattern, meta_fields: metaFields } = request.query; + const { pattern, meta_fields: metaFields, type, rollup_index: rollupIndex } = request.query; let parsedFields: string[] = []; try { @@ -61,6 +63,8 @@ export function registerRoutes(http: HttpServiceSetup) { const fields = await indexPatterns.getFieldsForWildcard({ pattern, metaFields: parsedFields, + type, + rollupIndex, }); return response.ok({ diff --git a/src/plugins/data/server/plugin.ts b/src/plugins/data/server/plugin.ts index 88f24b7ca5a70c..3ec4e7e64e382f 100644 --- a/src/plugins/data/server/plugin.ts +++ b/src/plugins/data/server/plugin.ts @@ -96,7 +96,7 @@ export class DataServerPlugin core.uiSettings.register(getUiSettings()); const searchSetup = this.searchService.setup(core, { - registerFunction: expressions.registerFunction, + expressions, usageCollection, }); diff --git a/src/plugins/data/server/search/aggs/aggs_service.test.ts b/src/plugins/data/server/search/aggs/aggs_service.test.ts index cb4239cc339c45..e58420f6c2f071 100644 --- a/src/plugins/data/server/search/aggs/aggs_service.test.ts +++ b/src/plugins/data/server/search/aggs/aggs_service.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { KibanaRequest } from 'src/core/server'; +import { KibanaRequest, ElasticsearchClient } from 'src/core/server'; import { coreMock } from '../../../../../core/server/mocks'; import { expressionsPluginMock } from '../../../../../plugins/expressions/server/mocks'; @@ -63,7 +63,8 @@ describe('AggsService - server', () => { expect(start).toHaveProperty('asScopedToClient'); const contract = await start.asScopedToClient( - savedObjects.getScopedClient({} as KibanaRequest) + savedObjects.getScopedClient({} as KibanaRequest), + {} as ElasticsearchClient ); expect(contract).toHaveProperty('calculateAutoTimeExpression'); expect(contract).toHaveProperty('createAggConfigs'); @@ -74,7 +75,10 @@ describe('AggsService - server', () => { service.setup(setupDeps); const start = await service .start(startDeps) - .asScopedToClient(savedObjects.getScopedClient({} as KibanaRequest)); + .asScopedToClient( + savedObjects.getScopedClient({} as KibanaRequest), + {} as ElasticsearchClient + ); expect(start.types.get('terms').name).toBe('terms'); }); @@ -83,7 +87,10 @@ describe('AggsService - server', () => { service.setup(setupDeps); const start = await service .start(startDeps) - .asScopedToClient(savedObjects.getScopedClient({} as KibanaRequest)); + .asScopedToClient( + savedObjects.getScopedClient({} as KibanaRequest), + {} as ElasticsearchClient + ); const aggTypes = getAggTypes(); expect(start.types.getAll().buckets.length).toBe(aggTypes.buckets.length); @@ -103,7 +110,10 @@ describe('AggsService - server', () => { const start = await service .start(startDeps) - .asScopedToClient(savedObjects.getScopedClient({} as KibanaRequest)); + .asScopedToClient( + savedObjects.getScopedClient({} as KibanaRequest), + {} as ElasticsearchClient + ); const aggTypes = getAggTypes(); expect(start.types.getAll().buckets.length).toBe(aggTypes.buckets.length + 1); diff --git a/src/plugins/data/server/search/aggs/aggs_service.ts b/src/plugins/data/server/search/aggs/aggs_service.ts index c805c8af6694cf..c23f748b1eeb53 100644 --- a/src/plugins/data/server/search/aggs/aggs_service.ts +++ b/src/plugins/data/server/search/aggs/aggs_service.ts @@ -19,7 +19,11 @@ import { pick } from 'lodash'; -import { UiSettingsServiceStart, SavedObjectsClientContract } from 'src/core/server'; +import { + UiSettingsServiceStart, + SavedObjectsClientContract, + ElasticsearchClient, +} from 'src/core/server'; import { ExpressionsServiceSetup } from 'src/plugins/expressions/common'; import { AggsCommonService, @@ -65,7 +69,10 @@ export class AggsService { public start({ fieldFormats, uiSettings, indexPatterns }: AggsStartDependencies): AggsStart { return { - asScopedToClient: async (savedObjectsClient: SavedObjectsClientContract) => { + asScopedToClient: async ( + savedObjectsClient: SavedObjectsClientContract, + elasticsearchClient: ElasticsearchClient + ) => { const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient); const formats = await fieldFormats.fieldFormatServiceFactory(uiSettingsClient); @@ -82,8 +89,9 @@ export class AggsService { types, } = this.aggsCommonService.start({ getConfig, - getIndexPattern: (await indexPatterns.indexPatternsServiceFactory(savedObjectsClient)) - .get, + getIndexPattern: ( + await indexPatterns.indexPatternsServiceFactory(savedObjectsClient, elasticsearchClient) + ).get, isDefaultTimezone, }); diff --git a/src/plugins/data/server/search/aggs/types.ts b/src/plugins/data/server/search/aggs/types.ts index 1b21d948b25d90..2c28c970cbb843 100644 --- a/src/plugins/data/server/search/aggs/types.ts +++ b/src/plugins/data/server/search/aggs/types.ts @@ -17,11 +17,14 @@ * under the License. */ -import { SavedObjectsClientContract } from 'src/core/server'; +import { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; import { AggsCommonSetup, AggsStart as Start } from '../../../common'; export type AggsSetup = AggsCommonSetup; export interface AggsStart { - asScopedToClient: (savedObjectsClient: SavedObjectsClientContract) => Promise; + asScopedToClient: ( + savedObjectsClient: SavedObjectsClientContract, + elasticsearchClient: ElasticsearchClient + ) => Promise; } diff --git a/src/plugins/data/server/search/search_service.test.ts b/src/plugins/data/server/search/search_service.test.ts index 2b513be147e9d2..0700afd8d6c838 100644 --- a/src/plugins/data/server/search/search_service.test.ts +++ b/src/plugins/data/server/search/search_service.test.ts @@ -44,7 +44,10 @@ describe('Search service', () => { it('exposes proper contract', async () => { const setup = plugin.setup(mockCoreSetup, ({ packageInfo: { version: '8' }, - registerFunction: jest.fn(), + expressions: { + registerFunction: jest.fn(), + registerType: jest.fn(), + }, } as unknown) as SearchServiceSetupDependencies); expect(setup).toHaveProperty('aggs'); expect(setup).toHaveProperty('registerSearchStrategy'); diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index c500c62914c0b9..d8aa588719e3e2 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -30,6 +30,7 @@ import { StartServicesAccessor, } from 'src/core/server'; import { first } from 'rxjs/operators'; +import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; import { ISearchSetup, ISearchStart, @@ -38,7 +39,7 @@ import { SearchStrategyDependencies, } from './types'; -import { AggsService, AggsSetupDependencies } from './aggs'; +import { AggsService } from './aggs'; import { FieldFormatsStart } from '../field_formats'; import { IndexPatternsServiceStart } from '../index_patterns'; @@ -50,15 +51,18 @@ import { registerUsageCollector } from './collectors/register'; import { usageProvider } from './collectors/usage'; import { searchTelemetry } from '../saved_objects'; import { - IKibanaSearchRequest, - IKibanaSearchResponse, IEsSearchRequest, IEsSearchResponse, + IKibanaSearchRequest, + IKibanaSearchResponse, + ISearchClient, + ISearchOptions, + kibana, + kibanaContext, + kibanaContextFunction, SearchSourceDependencies, - SearchSourceService, searchSourceRequiredUiSettings, - ISearchOptions, - ISearchClient, + SearchSourceService, } from '../../common/search'; import { getShardDelayBucketAgg, @@ -77,7 +81,7 @@ type StrategyMap = Record>; /** @internal */ export interface SearchServiceSetupDependencies { - registerFunction: AggsSetupDependencies['registerFunction']; + expressions: ExpressionsServerSetup; usageCollection?: UsageCollectionSetup; } @@ -106,7 +110,7 @@ export class SearchService implements Plugin { public setup( core: CoreSetup<{}, DataPluginStart>, - { registerFunction, usageCollection }: SearchServiceSetupDependencies + { expressions, usageCollection }: SearchServiceSetupDependencies ): ISearchSetup { const usage = usageCollection ? usageProvider(core) : undefined; @@ -137,7 +141,11 @@ export class SearchService implements Plugin { registerUsageCollector(usageCollection, this.initializerContext); } - const aggs = this.aggsService.setup({ registerFunction }); + expressions.registerFunction(kibana); + expressions.registerFunction(kibanaContextFunction); + expressions.registerType(kibanaContext); + + const aggs = this.aggsService.setup({ registerFunction: expressions.registerFunction }); this.initializerContext.config .create() @@ -146,7 +154,7 @@ export class SearchService implements Plugin { .then((value) => { if (value.search.aggs.shardDelay.enabled) { aggs.types.registerBucket(SHARD_DELAY_AGG_NAME, getShardDelayBucketAgg); - registerFunction(aggShardDelay); + expressions.registerFunction(aggShardDelay); } }); @@ -169,7 +177,11 @@ export class SearchService implements Plugin { const { elasticsearch, savedObjects, uiSettings } = core; const asScoped = this.asScopedProvider(core); return { - aggs: this.aggsService.start({ fieldFormats, uiSettings, indexPatterns }), + aggs: this.aggsService.start({ + fieldFormats, + uiSettings, + indexPatterns, + }), getSearchStrategy: this.getSearchStrategy, asScoped, searchSource: { @@ -177,7 +189,8 @@ export class SearchService implements Plugin { const esClient = elasticsearch.client.asScoped(request); const savedObjectsClient = savedObjects.getScopedClient(request); const scopedIndexPatterns = await indexPatterns.indexPatternsServiceFactory( - savedObjectsClient + savedObjectsClient, + esClient.asCurrentUser ); const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient); diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index f62a70c9e4ce1b..131b3e4c39c6bb 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -5,6 +5,7 @@ ```ts import { $Values } from '@kbn/utility-types'; +import { Adapters } from 'src/plugins/inspector/common'; import { ApiResponse } from '@elastic/elasticsearch'; import { Assign } from '@kbn/utility-types'; import { BehaviorSubject } from 'rxjs'; @@ -13,14 +14,19 @@ import { CoreSetup } from 'src/core/server'; import { CoreSetup as CoreSetup_2 } from 'kibana/server'; import { CoreStart } from 'src/core/server'; import { CoreStart as CoreStart_2 } from 'kibana/server'; +import { Datatable } from 'src/plugins/expressions/common'; import { DatatableColumn } from 'src/plugins/expressions'; import { Duration } from 'moment'; -import { ElasticsearchClient } from 'kibana/server'; +import { ElasticsearchClient } from 'src/core/server'; +import { ElasticsearchClient as ElasticsearchClient_2 } from 'kibana/server'; import { Ensure } from '@kbn/utility-types'; import { EnvironmentMode } from '@kbn/config'; import { ErrorToastOptions } from 'src/core/public/notifications'; +import { ExecutionContext } from 'src/plugins/expressions/common'; import { ExpressionAstFunction } from 'src/plugins/expressions/common'; +import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common'; import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; +import { ExpressionValueBoxed } from 'src/plugins/expressions/common'; import { ISavedObjectsRepository } from 'kibana/server'; import { IScopedClusterClient } from 'src/core/server'; import { ISearchOptions as ISearchOptions_2 } from 'src/plugins/data/public'; @@ -55,7 +61,6 @@ import { ToastInputFields } from 'src/core/public/notifications'; import { Type } from '@kbn/config-schema'; import { TypeOf } from '@kbn/config-schema'; import { Unit } from '@elastic/datemath'; -import { UnwrapPromiseOrReturn } from '@kbn/utility-types'; // Warning: (ae-forgotten-export) The symbol "AggConfigSerialized" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "AggConfigOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -224,7 +229,6 @@ export enum ES_FIELD_TYPES { // @public (undocumented) export const ES_SEARCH_STRATEGY = "es"; -// Warning: (ae-forgotten-export) The symbol "ExpressionFunctionDefinition" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "Input" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "Arguments" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "Output" needs to be exported by the entry point index.d.ts @@ -285,6 +289,31 @@ export interface EsQueryConfig { queryStringOptions: Record; } +// Warning: (ae-missing-release-tag) "ExecutionContextSearch" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type ExecutionContextSearch = { + filters?: Filter[]; + query?: Query | Query[]; + timeRange?: TimeRange; +}; + +// Warning: (ae-missing-release-tag) "ExpressionFunctionKibana" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type ExpressionFunctionKibana = ExpressionFunctionDefinition<'kibana', ExpressionValueSearchContext | null, object, ExpressionValueSearchContext, ExecutionContext>; + +// Warning: (ae-forgotten-export) The symbol "Arguments" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "ExpressionFunctionKibanaContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type ExpressionFunctionKibanaContext = ExpressionFunctionDefinition<'kibana_context', KibanaContext | null, Arguments_2, Promise, ExecutionContext>; + +// Warning: (ae-missing-release-tag) "ExpressionValueSearchContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type ExpressionValueSearchContext = ExpressionValueBoxed<'kibana_context', ExecutionContextSearch>; + // Warning: (ae-missing-release-tag) "FieldDescriptor" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -361,6 +390,15 @@ export type Filter = { query?: any; }; +// Warning: (ae-missing-release-tag) "getCapabilitiesForRollupIndices" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function getCapabilitiesForRollupIndices(indices: { + [key: string]: any; +}): { + [key: string]: any; +}; + // Warning: (ae-forgotten-export) The symbol "IUiSettingsClient" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "getDefaultSearchParams" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -660,7 +698,7 @@ export const indexPatterns: { // // @public (undocumented) export class IndexPatternsFetcher { - constructor(elasticsearchClient: ElasticsearchClient, allowNoIndices?: boolean); + constructor(elasticsearchClient: ElasticsearchClient_2, allowNoIndices?: boolean); getFieldsForTimePattern(options: { pattern: string; metaFields: string[]; @@ -673,6 +711,8 @@ export class IndexPatternsFetcher { fieldCapsOptions?: { allow_no_indices: boolean; }; + type?: string; + rollupIndex?: string; }): Promise; } @@ -687,7 +727,7 @@ export class IndexPatternsService implements Plugin_3 Promise; + indexPatternsServiceFactory: (savedObjectsClient: SavedObjectsClientContract_2, elasticsearchClient: ElasticsearchClient_2) => Promise; }; } @@ -779,6 +819,11 @@ export enum KBN_FIELD_TYPES { UNKNOWN = "unknown" } +// Warning: (ae-missing-release-tag) "KibanaContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type KibanaContext = ExpressionValueSearchContext; + // Warning: (ae-missing-release-tag) "KueryNode" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -791,6 +836,15 @@ export interface KueryNode { type: keyof NodeTypes; } +// Warning: (ae-missing-release-tag) "mergeCapabilitiesWithFields" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const mergeCapabilitiesWithFields: (rollupIndexCapabilities: { + [key: string]: any; +}, fieldsFromFieldCapsApi: { + [key: string]: any; +}, previousFields?: FieldDescriptor[]) => FieldDescriptor[]; + // Warning: (ae-missing-release-tag) "METRIC_TYPES" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -885,7 +939,7 @@ export class Plugin implements Plugin_2 void; search: ISearchSetup; fieldFormats: { - register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; + register: (customFieldFormat: import("../common").FieldFormatInstanceType) => number; }; }; // (undocumented) @@ -894,7 +948,7 @@ export class Plugin implements Plugin_2 Promise; }; indexPatterns: { - indexPatternsServiceFactory: (savedObjectsClient: Pick) => Promise; + indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: import("src/core/server").ElasticsearchClient) => Promise; }; search: ISearchStart>; }; @@ -1162,22 +1216,22 @@ export function usageProvider(core: CoreSetup_2): SearchUsage; // src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:127:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:127:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:235:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:235:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:235:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:235:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:250:5 - (ae-forgotten-export) The symbol "getTotalLoaded" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:251:5 - (ae-forgotten-export) The symbol "toSnakeCase" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:255:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:256:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:265:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:266:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:267:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:271:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:272:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:276:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:279:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index_patterns/index_patterns_service.ts:50:14 - (ae-forgotten-export) The symbol "IndexPatternsService" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:243:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:243:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:243:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:243:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:258:5 - (ae-forgotten-export) The symbol "getTotalLoaded" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:259:5 - (ae-forgotten-export) The symbol "toSnakeCase" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:263:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:264:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:273:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:274:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:275:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:279:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:280:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:284:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:287:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index_patterns/index_patterns_service.ts:58:14 - (ae-forgotten-export) The symbol "IndexPatternsService" needs to be exported by the entry point index.d.ts // src/plugins/data/server/plugin.ts:88:66 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts // src/plugins/data/server/search/types.ts:104:5 - (ae-forgotten-export) The symbol "ISearchStartSearchSource" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/es_ui_shared/public/url/attempt_to_uri_decode.test.ts b/src/plugins/es_ui_shared/public/url/attempt_to_uri_decode.test.ts index 15750c76678004..6654611faa18b0 100644 --- a/src/plugins/es_ui_shared/public/url/attempt_to_uri_decode.test.ts +++ b/src/plugins/es_ui_shared/public/url/attempt_to_uri_decode.test.ts @@ -19,14 +19,51 @@ import { attemptToURIDecode } from './attempt_to_uri_decode'; +// this function doesn't work for % with other special chars or sequence %25 +// known issue https://github.com/elastic/kibana/issues/82440 test('decodes an encoded string', () => { - const encodedString = 'test%3F'; - expect(attemptToURIDecode(encodedString)).toBe('test?'); + const originalName = 'test;,/?:@&=+$#'; + const encodedName = encodeURIComponent(originalName); + // react router v5 automatically decodes route match params + const reactRouterDecoded = decodeURI(encodedName); + + expect(attemptToURIDecode(encodedName)).toBe(originalName); + expect(attemptToURIDecode(reactRouterDecoded)).toBe(originalName); }); -// react router partially decodes %25 sequence to % in match params -// https://github.com/elastic/kibana/pull/81664 test('ignores the error if a string is already decoded', () => { - const decodedString = 'test%'; - expect(attemptToURIDecode(decodedString)).toBe(decodedString); + const originalName = 'test%'; + + const encodedName = encodeURIComponent(originalName); + // react router v5 automatically decodes route match params + const reactRouterDecoded = decodeURI(encodedName); + + expect(attemptToURIDecode(encodedName)).toBe(originalName); + expect(attemptToURIDecode(reactRouterDecoded)).toBe(originalName); +}); + +test('returns wrong decoded value for %25 sequence', () => { + const originalName = 'test%25'; + + const encodedName = encodeURIComponent(originalName); + // react router v5 automatically decodes route match params + const reactRouterDecoded = decodeURI(encodedName); + + expect(attemptToURIDecode(encodedName)).toBe(originalName); + expect(attemptToURIDecode(reactRouterDecoded)).not.toBe(originalName); +}); + +test('returns wrong decoded value for % with other escaped characters', () => { + const originalName = 'test%?#'; + + const encodedName = encodeURIComponent(originalName); + // react router v5 automatically decodes route match params + const reactRouterDecoded = decodeURI(encodedName); + + expect(attemptToURIDecode(encodedName)).toBe(originalName); + expect(attemptToURIDecode(reactRouterDecoded)).not.toBe(originalName); +}); + +test("doesn't convert undefined to a string", () => { + expect(attemptToURIDecode(undefined)).toBeUndefined(); }); diff --git a/src/plugins/es_ui_shared/public/url/attempt_to_uri_decode.ts b/src/plugins/es_ui_shared/public/url/attempt_to_uri_decode.ts index 65444b83f77bb2..37e4761106e44c 100644 --- a/src/plugins/es_ui_shared/public/url/attempt_to_uri_decode.ts +++ b/src/plugins/es_ui_shared/public/url/attempt_to_uri_decode.ts @@ -19,12 +19,14 @@ /* * Use this function with any match params coming from react router to safely decode values. - * https://github.com/elastic/kibana/pull/81664 + * After an update to react router v6, this functions should be deprecated. + * Known issue for navigation with special characters in paths + * https://github.com/elastic/kibana/issues/82440 */ -export const attemptToURIDecode = (value: string) => { +export const attemptToURIDecode = (value?: string): string | undefined => { let result = value; try { - result = decodeURIComponent(value); + result = value ? decodeURIComponent(value) : value; } catch (e) { // do nothing } diff --git a/src/plugins/expressions/common/execution/execution.ts b/src/plugins/expressions/common/execution/execution.ts index ba115a7538604d..50a469c338d73a 100644 --- a/src/plugins/expressions/common/execution/execution.ts +++ b/src/plugins/expressions/common/execution/execution.ts @@ -22,8 +22,7 @@ import { keys, last, mapValues, reduce, zipObject } from 'lodash'; import { Executor } from '../executor'; import { createExecutionContainer, ExecutionContainer } from './container'; import { createError } from '../util'; -import { Defer, now } from '../../../kibana_utils/common'; -import { toPromise } from '../../../data/common/utils/abort_utils'; +import { abortSignalToPromise, Defer, now } from '../../../kibana_utils/common'; import { RequestAdapter, DataAdapter, Adapters } from '../../../inspector/common'; import { isExpressionValueError, ExpressionValueError } from '../expression_types/specs/error'; import { @@ -93,7 +92,7 @@ export class Execution< /** * Promise that rejects if/when abort controller sends "abort" signal. */ - private readonly abortRejection = toPromise(this.abortController.signal); + private readonly abortRejection = abortSignalToPromise(this.abortController.signal); /** * Races a given promise against the "abort" event of `abortController`. diff --git a/src/plugins/expressions/common/execution/types.ts b/src/plugins/expressions/common/execution/types.ts index 50475c3bd94aeb..abe3e08fc20c26 100644 --- a/src/plugins/expressions/common/execution/types.ts +++ b/src/plugins/expressions/common/execution/types.ts @@ -17,16 +17,18 @@ * under the License. */ -import { ExpressionType } from '../expression_types'; +import { ExpressionType, SerializableState } from '../expression_types'; import { Adapters, DataAdapter, RequestAdapter } from '../../../inspector/common'; -import { TimeRange, Query, Filter } from '../../../data/common'; import { SavedObject, SavedObjectAttributes } from '../../../../core/public'; /** * `ExecutionContext` is an object available to all functions during a single execution; * it provides various methods to perform side-effects. */ -export interface ExecutionContext { +export interface ExecutionContext< + InspectorAdapters extends Adapters = Adapters, + ExecutionContextSearch extends SerializableState = SerializableState +> { /** * Get search context of the expression. */ @@ -79,9 +81,3 @@ export interface DefaultInspectorAdapters extends Adapters { requests: RequestAdapter; data: DataAdapter; } - -export interface ExecutionContextSearch { - filters?: Filter[]; - query?: Query | Query[]; - timeRange?: TimeRange; -} diff --git a/src/plugins/expressions/common/expression_functions/specs/index.ts b/src/plugins/expressions/common/expression_functions/specs/index.ts index 11706f65dbd322..10ccd014fd7bdb 100644 --- a/src/plugins/expressions/common/expression_functions/specs/index.ts +++ b/src/plugins/expressions/common/expression_functions/specs/index.ts @@ -19,8 +19,6 @@ import { clog } from './clog'; import { font } from './font'; -import { kibana } from './kibana'; -import { kibanaContextFunction } from './kibana_context'; import { variableSet } from './var_set'; import { variable } from './var'; import { AnyExpressionFunctionDefinition } from '../types'; @@ -32,8 +30,6 @@ import { movingAverage } from './moving_average'; export const functionSpecs: AnyExpressionFunctionDefinition[] = [ clog, font, - kibana, - kibanaContextFunction, variableSet, variable, theme, @@ -44,8 +40,6 @@ export const functionSpecs: AnyExpressionFunctionDefinition[] = [ export * from './clog'; export * from './font'; -export * from './kibana'; -export * from './kibana_context'; export * from './var_set'; export * from './var'; export * from './theme'; diff --git a/src/plugins/expressions/common/expression_functions/specs/tests/var.test.ts b/src/plugins/expressions/common/expression_functions/specs/tests/var.test.ts index 762f34e3f55666..efcb5555cc63bf 100644 --- a/src/plugins/expressions/common/expression_functions/specs/tests/var.test.ts +++ b/src/plugins/expressions/common/expression_functions/specs/tests/var.test.ts @@ -20,12 +20,11 @@ import { functionWrapper } from './utils'; import { variable } from '../var'; import { ExecutionContext } from '../../../execution/types'; -import { KibanaContext } from '../../../expression_types'; describe('expression_functions', () => { describe('var', () => { const fn = functionWrapper(variable); - let input: Partial; + let input: Partial>; let context: ExecutionContext; beforeEach(() => { diff --git a/src/plugins/expressions/common/expression_functions/specs/tests/var_set.test.ts b/src/plugins/expressions/common/expression_functions/specs/tests/var_set.test.ts index 365ae5b89baeae..17d9c4ab98c1a1 100644 --- a/src/plugins/expressions/common/expression_functions/specs/tests/var_set.test.ts +++ b/src/plugins/expressions/common/expression_functions/specs/tests/var_set.test.ts @@ -20,12 +20,11 @@ import { functionWrapper } from './utils'; import { variableSet } from '../var_set'; import { ExecutionContext } from '../../../execution/types'; -import { KibanaContext } from '../../../expression_types'; describe('expression_functions', () => { describe('var_set', () => { const fn = functionWrapper(variableSet); - let input: Partial; + let input: Partial>; let context: ExecutionContext; let variables: Record; diff --git a/src/plugins/expressions/common/expression_functions/types.ts b/src/plugins/expressions/common/expression_functions/types.ts index 4a93cfa9211ff7..52e4b4d9facf3c 100644 --- a/src/plugins/expressions/common/expression_functions/types.ts +++ b/src/plugins/expressions/common/expression_functions/types.ts @@ -24,8 +24,6 @@ import { ExecutionContext } from '../execution/types'; import { ExpressionFunctionClog, ExpressionFunctionFont, - ExpressionFunctionKibanaContext, - ExpressionFunctionKibana, ExpressionFunctionVarSet, ExpressionFunctionVar, ExpressionFunctionTheme, @@ -129,8 +127,6 @@ export type AnyExpressionFunctionDefinition = ExpressionFunctionDefinition< export interface ExpressionFunctionDefinitions { clog: ExpressionFunctionClog; font: ExpressionFunctionFont; - kibana_context: ExpressionFunctionKibanaContext; - kibana: ExpressionFunctionKibana; var_set: ExpressionFunctionVarSet; var: ExpressionFunctionVar; theme: ExpressionFunctionTheme; diff --git a/src/plugins/expressions/common/expression_types/specs/index.ts b/src/plugins/expressions/common/expression_types/specs/index.ts index 00c52a2545cd67..ec8dee1f7fc52b 100644 --- a/src/plugins/expressions/common/expression_types/specs/index.ts +++ b/src/plugins/expressions/common/expression_types/specs/index.ts @@ -22,7 +22,6 @@ import { datatable } from './datatable'; import { error } from './error'; import { filter } from './filter'; import { image } from './image'; -import { kibanaContext } from './kibana_context'; import { nullType } from './null'; import { num } from './num'; import { number } from './number'; @@ -40,7 +39,6 @@ export const typeSpecs: AnyExpressionTypeDefinition[] = [ error, filter, image, - kibanaContext, nullType, num, number, @@ -57,7 +55,6 @@ export * from './datatable'; export * from './error'; export * from './filter'; export * from './image'; -export * from './kibana_context'; export * from './null'; export * from './num'; export * from './number'; diff --git a/src/plugins/expressions/common/service/expressions_services.ts b/src/plugins/expressions/common/service/expressions_services.ts index 01289ca1ae57a8..c9cc0680360bb1 100644 --- a/src/plugins/expressions/common/service/expressions_services.ts +++ b/src/plugins/expressions/common/service/expressions_services.ts @@ -26,7 +26,6 @@ import { AnyExpressionFunctionDefinition } from '../expression_functions'; import { SavedObjectReference } from '../../../../core/types'; import { PersistableStateService, SerializableState } from '../../../kibana_utils/common'; import { Adapters } from '../../../inspector/common/adapters'; -import { ExecutionContextSearch } from '../execution'; /** * The public contract that `ExpressionsService` provides to other plugins @@ -48,7 +47,7 @@ export type ExpressionsServiceSetup = Pick< >; export interface ExpressionExecutionParams { - searchContext?: ExecutionContextSearch; + searchContext?: SerializableState; variables?: Record; diff --git a/src/plugins/expressions/kibana.json b/src/plugins/expressions/kibana.json index 67bbf4b6e54546..23c7fe722fdb35 100644 --- a/src/plugins/expressions/kibana.json +++ b/src/plugins/expressions/kibana.json @@ -6,7 +6,6 @@ "extraPublicDirs": ["common", "common/fonts"], "requiredBundles": [ "kibanaUtils", - "inspector", - "data" + "inspector" ] } diff --git a/src/plugins/expressions/public/index.ts b/src/plugins/expressions/public/index.ts index 893d68238747d3..385055bc2fdc2d 100644 --- a/src/plugins/expressions/public/index.ts +++ b/src/plugins/expressions/public/index.ts @@ -66,7 +66,6 @@ export { ExpressionFunction, ExpressionFunctionDefinition, ExpressionFunctionDefinitions, - ExpressionFunctionKibana, ExpressionFunctionParameter, ExpressionImage, ExpressionRenderDefinition, @@ -81,7 +80,6 @@ export { ExpressionValueError, ExpressionValueNum, ExpressionValueRender, - ExpressionValueSearchContext, ExpressionValueUnboxed, ExpressionValueFilter, Font, @@ -96,8 +94,6 @@ export { InterpreterErrorType, IRegistry, isExpressionAstBuilder, - KIBANA_CONTEXT_NAME, - KibanaContext, KnownTypeToString, Overflow, parse, diff --git a/src/plugins/expressions/public/plugin.test.ts b/src/plugins/expressions/public/plugin.test.ts index d9dde1f6def684..0b21fe354d3d35 100644 --- a/src/plugins/expressions/public/plugin.test.ts +++ b/src/plugins/expressions/public/plugin.test.ts @@ -50,14 +50,6 @@ describe('ExpressionsPublicPlugin', () => { const bar = await setup.run('var_set name="foo" value="bar" | var name="foo"', null); expect(bar).toBe('bar'); }); - - test('kibana_context function is available', async () => { - const { setup } = await expressionsPluginMock.createPlugin(); - const result = await setup.run('kibana_context', null); - expect(result).toMatchObject({ - type: 'kibana_context', - }); - }); }); }); @@ -81,15 +73,6 @@ describe('ExpressionsPublicPlugin', () => { } `); }); - - test('"kibana" function return value of type "kibana_context"', async () => { - const { doStart } = await expressionsPluginMock.createPlugin(); - const start = await doStart(); - const execution = start.execute('kibana', null); - const result = await execution.getData(); - - expect((result as any).type).toBe('kibana_context'); - }); }); }); }); diff --git a/src/plugins/expressions/public/public.api.md b/src/plugins/expressions/public/public.api.md index 773d61ebe2e28a..17f8e6255f6bb0 100644 --- a/src/plugins/expressions/public/public.api.md +++ b/src/plugins/expressions/public/public.api.md @@ -130,15 +130,15 @@ export class Execution = StateContainer, ExecutionPureTransitions>; +// Warning: (ae-forgotten-export) The symbol "SerializableState" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "ExecutionContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export interface ExecutionContext { +export interface ExecutionContext { abortSignal: AbortSignal; // Warning: (ae-forgotten-export) The symbol "SavedObjectAttributes" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "SavedObject" needs to be exported by the entry point index.d.ts getSavedObject?: (type: string, id: string) => Promise>; - // Warning: (ae-forgotten-export) The symbol "ExecutionContextSearch" needs to be exported by the entry point index.d.ts getSearchContext: () => ExecutionContextSearch; getSearchSessionId: () => string | undefined; inspectorAdapters: InspectorAdapters; @@ -396,12 +396,6 @@ export interface ExpressionFunctionDefinitions { // // (undocumented) font: ExpressionFunctionFont; - // (undocumented) - kibana: ExpressionFunctionKibana; - // Warning: (ae-forgotten-export) The symbol "ExpressionFunctionKibanaContext" needs to be exported by the entry point index.d.ts - // - // (undocumented) - kibana_context: ExpressionFunctionKibanaContext; // Warning: (ae-forgotten-export) The symbol "ExpressionFunctionMovingAverage" needs to be exported by the entry point index.d.ts // // (undocumented) @@ -420,11 +414,6 @@ export interface ExpressionFunctionDefinitions { var_set: ExpressionFunctionVarSet; } -// Warning: (ae-missing-release-tag) "ExpressionFunctionKibana" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type ExpressionFunctionKibana = ExpressionFunctionDefinition<'kibana', ExpressionValueSearchContext | null, object, ExpressionValueSearchContext>; - // Warning: (ae-missing-release-tag) "ExpressionFunctionParameter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -789,11 +778,6 @@ export { ExpressionValueRender } export { ExpressionValueRender as Render } -// Warning: (ae-missing-release-tag) "ExpressionValueSearchContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type ExpressionValueSearchContext = ExpressionValueBoxed<'kibana_context', ExecutionContextSearch>; - // Warning: (ae-missing-release-tag) "ExpressionValueUnboxed" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -908,7 +892,7 @@ export interface IExpressionLoaderParams { // (undocumented) onRenderError?: RenderErrorHandlerFnType; // (undocumented) - searchContext?: ExecutionContextSearch; + searchContext?: SerializableState_2; // (undocumented) searchSessionId?: string; // (undocumented) @@ -956,16 +940,6 @@ export interface IRegistry { // @public export function isExpressionAstBuilder(val: any): val is ExpressionAstExpressionBuilder; -// Warning: (ae-missing-release-tag) "KIBANA_CONTEXT_NAME" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type KIBANA_CONTEXT_NAME = 'kibana_context'; - -// Warning: (ae-missing-release-tag) "KibanaContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type KibanaContext = ExpressionValueSearchContext; - // Warning: (ae-missing-release-tag) "KnownTypeToString" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public diff --git a/src/plugins/expressions/public/types/index.ts b/src/plugins/expressions/public/types/index.ts index 1643b5734ef1a8..4af36fea169a1b 100644 --- a/src/plugins/expressions/public/types/index.ts +++ b/src/plugins/expressions/public/types/index.ts @@ -21,8 +21,8 @@ import { Adapters } from '../../../inspector/public'; import { IInterpreterRenderHandlers, ExpressionValue, - ExecutionContextSearch, ExpressionsService, + SerializableState, } from '../../common'; /** @@ -42,7 +42,7 @@ export interface ExpressionInterpreter { } export interface IExpressionLoaderParams { - searchContext?: ExecutionContextSearch; + searchContext?: SerializableState; context?: ExpressionValue; variables?: Record; // Enables debug tracking on each expression in the AST diff --git a/src/plugins/expressions/server/index.ts b/src/plugins/expressions/server/index.ts index cc22d4b500d978..287b91049b1aef 100644 --- a/src/plugins/expressions/server/index.ts +++ b/src/plugins/expressions/server/index.ts @@ -57,7 +57,6 @@ export { ExpressionFunction, ExpressionFunctionDefinition, ExpressionFunctionDefinitions, - ExpressionFunctionKibana, ExpressionFunctionParameter, ExpressionImage, ExpressionRenderDefinition, @@ -72,7 +71,6 @@ export { ExpressionValueError, ExpressionValueNum, ExpressionValueRender, - ExpressionValueSearchContext, ExpressionValueUnboxed, ExpressionValueFilter, Font, @@ -87,8 +85,6 @@ export { InterpreterErrorType, IRegistry, isExpressionAstBuilder, - KIBANA_CONTEXT_NAME, - KibanaContext, KnownTypeToString, Overflow, parse, diff --git a/src/plugins/expressions/server/server.api.md b/src/plugins/expressions/server/server.api.md index 27a3193bf78945..e5b499206ebdd8 100644 --- a/src/plugins/expressions/server/server.api.md +++ b/src/plugins/expressions/server/server.api.md @@ -128,15 +128,15 @@ export class Execution = StateContainer, ExecutionPureTransitions>; +// Warning: (ae-forgotten-export) The symbol "SerializableState" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "ExecutionContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export interface ExecutionContext { +export interface ExecutionContext { abortSignal: AbortSignal; // Warning: (ae-forgotten-export) The symbol "SavedObjectAttributes" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "SavedObject" needs to be exported by the entry point index.d.ts getSavedObject?: (type: string, id: string) => Promise>; - // Warning: (ae-forgotten-export) The symbol "ExecutionContextSearch" needs to be exported by the entry point index.d.ts getSearchContext: () => ExecutionContextSearch; getSearchSessionId: () => string | undefined; inspectorAdapters: InspectorAdapters; @@ -368,12 +368,6 @@ export interface ExpressionFunctionDefinitions { // // (undocumented) font: ExpressionFunctionFont; - // (undocumented) - kibana: ExpressionFunctionKibana; - // Warning: (ae-forgotten-export) The symbol "ExpressionFunctionKibanaContext" needs to be exported by the entry point index.d.ts - // - // (undocumented) - kibana_context: ExpressionFunctionKibanaContext; // Warning: (ae-forgotten-export) The symbol "ExpressionFunctionMovingAverage" needs to be exported by the entry point index.d.ts // // (undocumented) @@ -392,11 +386,6 @@ export interface ExpressionFunctionDefinitions { var_set: ExpressionFunctionVarSet; } -// Warning: (ae-missing-release-tag) "ExpressionFunctionKibana" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type ExpressionFunctionKibana = ExpressionFunctionDefinition<'kibana', ExpressionValueSearchContext | null, object, ExpressionValueSearchContext>; - // Warning: (ae-missing-release-tag) "ExpressionFunctionParameter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -640,11 +629,6 @@ export { ExpressionValueRender } export { ExpressionValueRender as Render } -// Warning: (ae-missing-release-tag) "ExpressionValueSearchContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type ExpressionValueSearchContext = ExpressionValueBoxed<'kibana_context', ExecutionContextSearch>; - // Warning: (ae-missing-release-tag) "ExpressionValueUnboxed" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -777,16 +761,6 @@ export interface IRegistry { // @public export function isExpressionAstBuilder(val: any): val is ExpressionAstExpressionBuilder; -// Warning: (ae-missing-release-tag) "KIBANA_CONTEXT_NAME" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type KIBANA_CONTEXT_NAME = 'kibana_context'; - -// Warning: (ae-missing-release-tag) "KibanaContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type KibanaContext = ExpressionValueSearchContext; - // Warning: (ae-missing-release-tag) "KnownTypeToString" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public diff --git a/src/plugins/data/common/utils/abort_utils.test.ts b/src/plugins/kibana_utils/common/abort_utils.test.ts similarity index 84% rename from src/plugins/data/common/utils/abort_utils.test.ts rename to src/plugins/kibana_utils/common/abort_utils.test.ts index 358f00e5e82bd9..8ccbf752b4d1b6 100644 --- a/src/plugins/data/common/utils/abort_utils.test.ts +++ b/src/plugins/kibana_utils/common/abort_utils.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { AbortError, toPromise, getCombinedSignal } from './abort_utils'; +import { AbortError, abortSignalToPromise, getCombinedAbortSignal } from './abort_utils'; jest.useFakeTimers(); @@ -37,11 +37,11 @@ describe('AbortUtils', () => { }); }); - describe('toPromise', () => { + describe('abortSignalToPromise', () => { describe('rejects', () => { test('should not reject if the signal does not abort', async () => { const controller = new AbortController(); - const promise = toPromise(controller.signal).promise; + const promise = abortSignalToPromise(controller.signal).promise; const whenRejected = jest.fn(); promise.catch(whenRejected); await flushPromises(); @@ -50,7 +50,7 @@ describe('AbortUtils', () => { test('should reject if the signal does abort', async () => { const controller = new AbortController(); - const promise = toPromise(controller.signal).promise; + const promise = abortSignalToPromise(controller.signal).promise; const whenRejected = jest.fn(); promise.catch(whenRejected); controller.abort(); @@ -61,13 +61,13 @@ describe('AbortUtils', () => { test('should expose cleanup handler', () => { const controller = new AbortController(); - const promise = toPromise(controller.signal); + const promise = abortSignalToPromise(controller.signal); expect(promise.cleanup).toBeDefined(); }); test('calling clean up handler prevents rejects', async () => { const controller = new AbortController(); - const { promise, cleanup } = toPromise(controller.signal); + const { promise, cleanup } = abortSignalToPromise(controller.signal); const whenRejected = jest.fn(); promise.catch(whenRejected); cleanup(); @@ -78,9 +78,9 @@ describe('AbortUtils', () => { }); }); - describe('getCombinedSignal', () => { + describe('getCombinedAbortSignal', () => { test('should return an AbortSignal', () => { - const signal = getCombinedSignal([]).signal; + const signal = getCombinedAbortSignal([]).signal; expect(signal).toBeInstanceOf(AbortSignal); }); @@ -89,7 +89,7 @@ describe('AbortUtils', () => { const controller2 = new AbortController(); setTimeout(() => controller1.abort(), 2000); setTimeout(() => controller2.abort(), 1000); - const signal = getCombinedSignal([controller1.signal, controller2.signal]).signal; + const signal = getCombinedAbortSignal([controller1.signal, controller2.signal]).signal; expect(signal.aborted).toBe(false); jest.advanceTimersByTime(500); await flushPromises(); @@ -101,7 +101,7 @@ describe('AbortUtils', () => { const controller2 = new AbortController(); setTimeout(() => controller1.abort(), 2000); setTimeout(() => controller2.abort(), 1000); - const signal = getCombinedSignal([controller1.signal, controller2.signal]).signal; + const signal = getCombinedAbortSignal([controller1.signal, controller2.signal]).signal; expect(signal.aborted).toBe(false); jest.advanceTimersByTime(1000); await flushPromises(); @@ -112,7 +112,7 @@ describe('AbortUtils', () => { const controller1 = new AbortController(); const controller2 = new AbortController(); controller1.abort(); - const signal = getCombinedSignal([controller1.signal, controller2.signal]).signal; + const signal = getCombinedAbortSignal([controller1.signal, controller2.signal]).signal; expect(signal.aborted).toBe(true); }); @@ -132,7 +132,7 @@ describe('AbortUtils', () => { const controller1 = createMockController(); const controller2 = createMockController(); - const { cleanup } = getCombinedSignal([ + const { cleanup } = getCombinedAbortSignal([ controller1.controller.signal, controller2.controller.signal, ]); @@ -150,7 +150,7 @@ describe('AbortUtils', () => { const controller1 = createMockController(); const controller2 = createMockController(); - getCombinedSignal([controller1.controller.signal, controller2.controller.signal]); + getCombinedAbortSignal([controller1.controller.signal, controller2.controller.signal]); expect(controller1.getTotalListeners()).toBe(1); expect(controller2.getTotalListeners()).toBe(1); diff --git a/src/plugins/data/common/utils/abort_utils.ts b/src/plugins/kibana_utils/common/abort_utils.ts similarity index 91% rename from src/plugins/data/common/utils/abort_utils.ts rename to src/plugins/kibana_utils/common/abort_utils.ts index 81f30b7454c7b4..dd8db349316936 100644 --- a/src/plugins/data/common/utils/abort_utils.ts +++ b/src/plugins/kibana_utils/common/abort_utils.ts @@ -36,7 +36,9 @@ export class AbortError extends Error { * * @param signal The `AbortSignal` to generate the `Promise` from */ -export function toPromise(signal: AbortSignal): { promise: Promise; cleanup: () => void } { +export function abortSignalToPromise( + signal: AbortSignal +): { promise: Promise; cleanup: () => void } { let abortHandler: () => void; const cleanup = () => { if (abortHandler) { @@ -60,7 +62,7 @@ export function toPromise(signal: AbortSignal): { promise: Promise; clean * * @param signals */ -export function getCombinedSignal( +export function getCombinedAbortSignal( signals: AbortSignal[] ): { signal: AbortSignal; cleanup: () => void } { const controller = new AbortController(); @@ -69,7 +71,7 @@ export function getCombinedSignal( if (signals.some((signal) => signal.aborted)) { controller.abort(); } else { - const promises = signals.map((signal) => toPromise(signal)); + const promises = signals.map((signal) => abortSignalToPromise(signal)); cleanup = () => { promises.forEach((p) => p.cleanup()); controller.signal.removeEventListener('abort', cleanup); diff --git a/src/plugins/kibana_utils/common/index.ts b/src/plugins/kibana_utils/common/index.ts index e09290c811c7b3..a49b7100594ba1 100644 --- a/src/plugins/kibana_utils/common/index.ts +++ b/src/plugins/kibana_utils/common/index.ts @@ -24,6 +24,7 @@ export * from './ui'; export * from './state_containers'; export * from './typed_json'; export * from './errors'; +export { AbortError, abortSignalToPromise, getCombinedAbortSignal } from './abort_utils'; export { createGetterSetter, Get, Set } from './create_getter_setter'; export { distinctUntilChangedWithInitialValue } from './distinct_until_changed_with_initial_value'; export { url } from './url'; diff --git a/src/plugins/kibana_utils/public/index.ts b/src/plugins/kibana_utils/public/index.ts index 9ba42d39139da8..46a0cc4a10f009 100644 --- a/src/plugins/kibana_utils/public/index.ts +++ b/src/plugins/kibana_utils/public/index.ts @@ -18,12 +18,15 @@ */ export { + AbortError, + abortSignalToPromise, calculateObjectHash, defer, Defer, fieldWildcardFilter, fieldWildcardMatcher, Get, + getCombinedAbortSignal, JsonArray, JsonObject, JsonValue, diff --git a/src/plugins/kibana_utils/server/index.ts b/src/plugins/kibana_utils/server/index.ts index bf3361d1e5369b..d994a4940bdfd5 100644 --- a/src/plugins/kibana_utils/server/index.ts +++ b/src/plugins/kibana_utils/server/index.ts @@ -18,10 +18,13 @@ */ export { + AbortError, + abortSignalToPromise, createGetterSetter, fieldWildcardFilter, fieldWildcardMatcher, Get, + getCombinedAbortSignal, Set, url, } from '../common'; diff --git a/src/plugins/ui_actions/public/public.api.md b/src/plugins/ui_actions/public/public.api.md index 8393f7480d4e47..3e40c94e116fbe 100644 --- a/src/plugins/ui_actions/public/public.api.md +++ b/src/plugins/ui_actions/public/public.api.md @@ -233,7 +233,7 @@ export class UiActionsService { // // (undocumented) protected readonly actions: ActionRegistry; - readonly addTriggerAction: (triggerId: T, action: UiActionsActionDefinition | Action) => void; + readonly addTriggerAction: (triggerId: T, action: UiActionsActionDefinition | Action) => void; // (undocumented) readonly attachAction: (triggerId: T, actionId: string) => void; readonly clear: () => void; @@ -247,21 +247,21 @@ export class UiActionsService { readonly executionService: UiActionsExecutionService; readonly fork: () => UiActionsService; // (undocumented) - readonly getAction: >(id: string) => Action, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK">; + readonly getAction: >(id: string) => Action, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION">; // Warning: (ae-forgotten-export) The symbol "TriggerContract" needs to be exported by the entry point index.d.ts // // (undocumented) readonly getTrigger: (triggerId: T) => TriggerContract; // (undocumented) - readonly getTriggerActions: (triggerId: T) => Action[]; + readonly getTriggerActions: (triggerId: T) => Action[]; // (undocumented) - readonly getTriggerCompatibleActions: (triggerId: T, context: TriggerContextMapping[T]) => Promise[]>; + readonly getTriggerCompatibleActions: (triggerId: T, context: TriggerContextMapping[T]) => Promise[]>; // (undocumented) readonly hasAction: (actionId: string) => boolean; // Warning: (ae-forgotten-export) The symbol "ActionContext" needs to be exported by the entry point index.d.ts // // (undocumented) - readonly registerAction: >(definition: A) => Action, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK">; + readonly registerAction: >(definition: A) => Action, "" | "ACTION_VISUALIZE_FIELD" | "ACTION_VISUALIZE_GEO_FIELD" | "ACTION_VISUALIZE_LENS_FIELD" | "ACTION_GLOBAL_APPLY_FILTER" | "ACTION_SELECT_RANGE" | "ACTION_VALUE_CLICK" | "ACTION_CUSTOMIZE_PANEL" | "ACTION_ADD_PANEL" | "openInspector" | "deletePanel" | "editPanel" | "togglePanel" | "replacePanel" | "clonePanel" | "addToFromLibrary" | "unlinkFromLibrary" | "ACTION_LIBRARY_NOTIFICATION">; // (undocumented) readonly registerTrigger: (trigger: Trigger) => void; // Warning: (ae-forgotten-export) The symbol "TriggerRegistry" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/usage_collection/server/routes/stats/stats.ts b/src/plugins/usage_collection/server/routes/stats/stats.ts index ef64d15fabc2d0..d38250067053c1 100644 --- a/src/plugins/usage_collection/server/routes/stats/stats.ts +++ b/src/plugins/usage_collection/server/routes/stats/stats.ts @@ -73,8 +73,9 @@ export function registerStatsRoute({ return collectorSet.toObject(usage); }; - const getClusterUuid = async (callCluster: LegacyAPICaller): Promise => { - const { cluster_uuid: uuid } = await callCluster('info', { filterPath: 'cluster_uuid' }); + const getClusterUuid = async (asCurrentUser: ElasticsearchClient): Promise => { + const { body } = await asCurrentUser.info({ filter_path: 'cluster_uuid' }); + const { cluster_uuid: uuid } = body; return uuid; }; @@ -103,7 +104,7 @@ export function registerStatsRoute({ let extended; if (isExtended) { const callCluster = context.core.elasticsearch.legacy.client.callAsCurrentUser; - const esClient = context.core.elasticsearch.client.asCurrentUser; + const { asCurrentUser } = context.core.elasticsearch.client; const savedObjectsClient = context.core.savedObjects.client; if (shouldGetUsage) { @@ -114,9 +115,12 @@ export function registerStatsRoute({ } const usagePromise = shouldGetUsage - ? getUsage(callCluster, esClient, savedObjectsClient) + ? getUsage(callCluster, asCurrentUser, savedObjectsClient) : Promise.resolve({}); - const [usage, clusterUuid] = await Promise.all([usagePromise, getClusterUuid(callCluster)]); + const [usage, clusterUuid] = await Promise.all([ + usagePromise, + getClusterUuid(asCurrentUser), + ]); let modifiedUsage = usage; if (isLegacy) { diff --git a/src/plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap b/src/plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap index 2a521bc01219cb..26173cddb37161 100644 --- a/src/plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap +++ b/src/plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap @@ -17,12 +17,12 @@ exports[`DefaultEditorAgg component should init with the default set of props 1` extraAction={
{ const actionIcons = []; + const aggTitle = agg.type?.title?.toLowerCase(); if (showError) { actionIcons.push({ @@ -170,7 +172,8 @@ function DefaultEditorAgg({ color: 'danger', type: 'alert', tooltip: i18n.translate('visDefaultEditor.agg.errorsAriaLabel', { - defaultMessage: 'Aggregation has errors', + defaultMessage: '{schemaTitle} {aggTitle} aggregation has errors', + values: { aggTitle, schemaTitle }, }), dataTestSubj: 'hasErrorsAggregationIcon', }); @@ -184,7 +187,8 @@ function DefaultEditorAgg({ type: 'eye', onClick: () => onToggleEnableAgg(agg.id, false), tooltip: i18n.translate('visDefaultEditor.agg.disableAggButtonTooltip', { - defaultMessage: 'Disable aggregation', + defaultMessage: 'Disable {schemaTitle} {aggTitle} aggregation', + values: { aggTitle, schemaTitle }, }), dataTestSubj: 'toggleDisableAggregationBtn disable', }); @@ -196,7 +200,8 @@ function DefaultEditorAgg({ type: 'eyeClosed', onClick: () => onToggleEnableAgg(agg.id, true), tooltip: i18n.translate('visDefaultEditor.agg.enableAggButtonTooltip', { - defaultMessage: 'Enable aggregation', + defaultMessage: 'Enable {schemaTitle} {aggTitle} aggregation', + values: { aggTitle, schemaTitle }, }), dataTestSubj: 'toggleDisableAggregationBtn enable', }); @@ -206,7 +211,8 @@ function DefaultEditorAgg({ id: 'dragHandle', type: 'grab', tooltip: i18n.translate('visDefaultEditor.agg.modifyPriorityButtonTooltip', { - defaultMessage: 'Modify priority by dragging', + defaultMessage: 'Modify priority of {schemaTitle} {aggTitle} by dragging', + values: { aggTitle, schemaTitle }, }), dataTestSubj: 'dragHandleBtn', }); @@ -218,7 +224,8 @@ function DefaultEditorAgg({ type: 'cross', onClick: () => removeAgg(agg.id), tooltip: i18n.translate('visDefaultEditor.agg.removeDimensionButtonTooltip', { - defaultMessage: 'Remove dimension', + defaultMessage: 'Remove {schemaTitle} {aggTitle} aggregation', + values: { aggTitle, schemaTitle }, }), dataTestSubj: 'removeDimensionBtn', }); @@ -257,7 +264,7 @@ function DefaultEditorAgg({
); }; - const schemaTitle = getSchemaByName(schemas, agg.schema).title; + const buttonContent = ( <> {schemaTitle || agg.schema} {showDescription && {aggDescription}} diff --git a/src/plugins/vis_default_editor/public/components/agg_add.tsx b/src/plugins/vis_default_editor/public/components/agg_add.tsx index 46d5af8cec6801..e78f2fcc4453cf 100644 --- a/src/plugins/vis_default_editor/public/components/agg_add.tsx +++ b/src/plugins/vis_default_editor/public/components/agg_add.tsx @@ -56,22 +56,26 @@ function DefaultEditorAggAdd({ addSchema(schema); }; + const groupNameLabel = + groupName === AggGroupNames.Buckets + ? i18n.translate('visDefaultEditor.aggAdd.bucketLabel', { defaultMessage: 'bucket' }) + : i18n.translate('visDefaultEditor.aggAdd.metricLabel', { defaultMessage: 'metric' }); + const addButton = ( setIsPopoverOpen(!isPopoverOpen)} + aria-label={i18n.translate('visDefaultEditor.aggAdd.addGroupButtonLabel', { + defaultMessage: 'Add {groupNameLabel}', + values: { groupNameLabel }, + })} > ); - const groupNameLabel = - groupName === AggGroupNames.Buckets - ? i18n.translate('visDefaultEditor.aggAdd.bucketLabel', { defaultMessage: 'bucket' }) - : i18n.translate('visDefaultEditor.aggAdd.metricLabel', { defaultMessage: 'metric' }); - const isSchemaDisabled = (schema: Schema): boolean => { const count = group.filter((agg) => agg.schema === schema.name).length; return count >= schema.max; diff --git a/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts b/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts index 1f0ac8b2b93928..7a630f36b51f44 100644 --- a/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts +++ b/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts @@ -18,8 +18,7 @@ */ import { i18n } from '@kbn/i18n'; -import { KIBANA_CONTEXT_NAME } from 'src/plugins/expressions/public'; -import { TimeRange, Filter, esQuery, Query } from '../../../data/public'; +import { KibanaContext, TimeRange, Filter, esQuery, Query } from '../../../data/public'; import { TimelionVisDependencies } from '../plugin'; import { getTimezone } from './get_timezone'; import { TimelionVisParams } from '../timelion_vis_fn'; @@ -59,7 +58,7 @@ export interface TimelionSuccessResponse { sheet: Sheet[]; stats: Stats; visType: string; - type: KIBANA_CONTEXT_NAME; + type: KibanaContext['type']; } export function getTimelionRequestHandler({ diff --git a/src/plugins/vis_type_timelion/public/timelion_vis_fn.ts b/src/plugins/vis_type_timelion/public/timelion_vis_fn.ts index a0cd410e197ff0..2e8878b11e9157 100644 --- a/src/plugins/vis_type_timelion/public/timelion_vis_fn.ts +++ b/src/plugins/vis_type_timelion/public/timelion_vis_fn.ts @@ -19,18 +19,14 @@ import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { - ExpressionFunctionDefinition, - KibanaContext, - Render, -} from 'src/plugins/expressions/public'; +import { ExpressionFunctionDefinition, Render } from 'src/plugins/expressions/public'; import { getTimelionRequestHandler, TimelionSuccessResponse, } from './helpers/timelion_request_handler'; import { TIMELION_VIS_NAME } from './timelion_vis_type'; import { TimelionVisDependencies } from './plugin'; -import { Filter, Query, TimeRange } from '../../data/common'; +import { KibanaContext, Filter, Query, TimeRange } from '../../data/public'; type Input = KibanaContext | null; type Output = Promise>; diff --git a/src/plugins/vis_type_timeseries/common/vis_schema.ts b/src/plugins/vis_type_timeseries/common/vis_schema.ts index 27f09fb574b0f3..9ec5ae1424ae3c 100644 --- a/src/plugins/vis_type_timeseries/common/vis_schema.ts +++ b/src/plugins/vis_type_timeseries/common/vis_schema.ts @@ -120,7 +120,7 @@ export const metricsItems = schema.object({ type: stringRequired, value: stringOptionalNullable, values: schema.maybe(schema.nullable(schema.arrayOf(schema.nullable(schema.string())))), - size: stringOptionalNullable, + size: stringOrNumberOptionalNullable, agg_with: stringOptionalNullable, order: stringOptionalNullable, order_by: stringOptionalNullable, diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/calculation.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/calculation.js index bb3d39797656f7..5bf4fb55ee5e52 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/calculation.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/calculation.js @@ -26,6 +26,7 @@ import { createChangeHandler } from '../lib/create_change_handler'; import { createSelectHandler } from '../lib/create_select_handler'; import { createTextHandler } from '../lib/create_text_handler'; import { CalculationVars, newVariable } from './vars'; +import { METRIC_TYPES } from '../../../../common/metric_types'; import { FormattedMessage } from '@kbn/i18n/react'; import { @@ -99,6 +100,7 @@ export function CalculationAgg(props) { onChange={handleChange} name="variables" model={model} + exclude={[METRIC_TYPES.TOP_HIT]} /> diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/cumulative_sum.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/cumulative_sum.js index 11b3e303e7e00a..0b879adbd37aea 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/cumulative_sum.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/cumulative_sum.js @@ -24,6 +24,7 @@ import { AggSelect } from './agg_select'; import { MetricSelect } from './metric_select'; import { createChangeHandler } from '../lib/create_change_handler'; import { createSelectHandler } from '../lib/create_select_handler'; +import { METRIC_TYPES } from '../../../../common/metric_types'; import { FormattedMessage } from '@kbn/i18n/react'; import { htmlIdGenerator, @@ -80,6 +81,7 @@ export function CumulativeSumAgg(props) { metrics={siblings} metric={model} value={model.field} + exclude={[METRIC_TYPES.TOP_HIT]} /> diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/derivative.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/derivative.js index faf1a59adc4aac..fa1289dc74c721 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/derivative.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/derivative.js @@ -25,6 +25,7 @@ import { AggRow } from './agg_row'; import { createChangeHandler } from '../lib/create_change_handler'; import { createSelectHandler } from '../lib/create_select_handler'; import { createTextHandler } from '../lib/create_text_handler'; +import { METRIC_TYPES } from '../../../../common/metric_types'; import { htmlIdGenerator, EuiFlexGroup, @@ -91,6 +92,7 @@ export const DerivativeAgg = (props) => { metrics={siblings} metric={model} value={model.field} + exclude={[METRIC_TYPES.TOP_HIT]} fullWidth /> diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/moving_average.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/moving_average.js index 316e0f9af43bdc..fb945d2606bc88 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/moving_average.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/moving_average.js @@ -25,6 +25,7 @@ import { MetricSelect } from './metric_select'; import { createChangeHandler } from '../lib/create_change_handler'; import { createSelectHandler } from '../lib/create_select_handler'; import { createNumberHandler } from '../lib/create_number_handler'; +import { METRIC_TYPES } from '../../../../common/metric_types'; import { htmlIdGenerator, EuiFlexGroup, @@ -153,6 +154,7 @@ export const MovingAverageAgg = (props) => { metrics={siblings} metric={model} value={model.field} + exclude={[METRIC_TYPES.TOP_HIT]} /> diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_only.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_only.js index 1999862f7aa0e0..6ca5fa8e7447f3 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_only.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_only.js @@ -24,6 +24,7 @@ import { MetricSelect } from './metric_select'; import { AggRow } from './agg_row'; import { createChangeHandler } from '../lib/create_change_handler'; import { createSelectHandler } from '../lib/create_select_handler'; +import { METRIC_TYPES } from '../../../../common/metric_types'; import { htmlIdGenerator, EuiFlexGroup, @@ -85,6 +86,7 @@ export const PositiveOnlyAgg = (props) => { metrics={siblings} metric={model} value={model.field} + exclude={[METRIC_TYPES.TOP_HIT]} /> diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js index 10b3d551bb89f7..e3a0c74273539e 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js @@ -25,6 +25,7 @@ import { AggRow } from './agg_row'; import { createChangeHandler } from '../lib/create_change_handler'; import { createSelectHandler } from '../lib/create_select_handler'; import { createNumberHandler } from '../lib/create_number_handler'; +import { METRIC_TYPES } from '../../../../common/metric_types'; import { htmlIdGenerator, EuiFlexGroup, @@ -87,6 +88,7 @@ export const SerialDiffAgg = (props) => { metrics={siblings} metric={model} value={model.field} + exclude={[METRIC_TYPES.TOP_HIT]} /> diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/std_sibling.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/std_sibling.js index 30e5c57ac90ba8..bed5e9caa9f872 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/std_sibling.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/std_sibling.js @@ -25,6 +25,8 @@ import { AggSelect } from './agg_select'; import { createChangeHandler } from '../lib/create_change_handler'; import { createSelectHandler } from '../lib/create_select_handler'; import { createTextHandler } from '../lib/create_text_handler'; +import { METRIC_TYPES } from '../../../../common/metric_types'; + import { htmlIdGenerator, EuiFlexGroup, @@ -154,7 +156,7 @@ const StandardSiblingAggUi = (props) => { > diff --git a/src/plugins/vis_type_timeseries/public/metrics_fn.ts b/src/plugins/vis_type_timeseries/public/metrics_fn.ts index b573225feaab1d..8652d703f963e3 100644 --- a/src/plugins/vis_type_timeseries/public/metrics_fn.ts +++ b/src/plugins/vis_type_timeseries/public/metrics_fn.ts @@ -19,7 +19,8 @@ import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { ExpressionFunctionDefinition, KibanaContext, Render } from '../../expressions/public'; +import { KibanaContext } from '../../data/public'; +import { ExpressionFunctionDefinition, Render } from '../../expressions/public'; // @ts-ignore import { metricsRequestHandler } from './request_handler'; diff --git a/src/plugins/vis_type_timeseries/server/lib/get_fields.ts b/src/plugins/vis_type_timeseries/server/lib/get_fields.ts index b52188129f77f1..dc49e280a2bb73 100644 --- a/src/plugins/vis_type_timeseries/server/lib/get_fields.ts +++ b/src/plugins/vis_type_timeseries/server/lib/get_fields.ts @@ -62,10 +62,12 @@ export async function getFields( let indexPatternString = indexPattern; if (!indexPatternString) { - const [{ savedObjects }, { data }] = await framework.core.getStartServices(); + const [{ savedObjects, elasticsearch }, { data }] = await framework.core.getStartServices(); const savedObjectsClient = savedObjects.getScopedClient(request); + const clusterClient = elasticsearch.client.asScoped(request).asCurrentUser; const indexPatternsService = await data.indexPatterns.indexPatternsServiceFactory( - savedObjectsClient + savedObjectsClient, + clusterClient ); const defaultIndexPattern = await indexPatternsService.getDefault(); indexPatternString = get(defaultIndexPattern, 'title', ''); diff --git a/src/plugins/vis_type_vega/public/vega_fn.ts b/src/plugins/vis_type_vega/public/vega_fn.ts index 25d4e76c336b3a..5a8113aeeea113 100644 --- a/src/plugins/vis_type_vega/public/vega_fn.ts +++ b/src/plugins/vis_type_vega/public/vega_fn.ts @@ -19,16 +19,12 @@ import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { - ExecutionContext, - ExpressionFunctionDefinition, - KibanaContext, - Render, -} from '../../expressions/public'; +import { ExecutionContextSearch } from '../../data/public'; +import { ExecutionContext, ExpressionFunctionDefinition, Render } from '../../expressions/public'; import { VegaVisualizationDependencies } from './plugin'; import { createVegaRequestHandler } from './vega_request_handler'; import { VegaInspectorAdapters } from './vega_inspector/index'; -import { TimeRange, Query } from '../../data/public'; +import { KibanaContext, TimeRange, Query } from '../../data/public'; import { VegaParser } from './data_model/vega_parser'; type Input = KibanaContext | null; @@ -51,7 +47,7 @@ export type VegaExpressionFunctionDefinition = ExpressionFunctionDefinition< Input, Arguments, Output, - ExecutionContext + ExecutionContext >; export const createVegaFn = ( diff --git a/src/plugins/visualizations/public/embeddable/_index.scss b/src/plugins/visualizations/public/embeddable/_index.scss index c1e3809657bfa0..9703e90159f481 100644 --- a/src/plugins/visualizations/public/embeddable/_index.scss +++ b/src/plugins/visualizations/public/embeddable/_index.scss @@ -1,2 +1 @@ -@import 'visualize_lab_disabled'; @import 'embeddables'; diff --git a/src/plugins/visualizations/public/embeddable/_visualize_lab_disabled.scss b/src/plugins/visualizations/public/embeddable/_visualize_lab_disabled.scss deleted file mode 100644 index 914480ff8c777e..00000000000000 --- a/src/plugins/visualizations/public/embeddable/_visualize_lab_disabled.scss +++ /dev/null @@ -1,13 +0,0 @@ -.visDisabledLabVisualization { - width: 100%; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - text-align: center; -} - -.visDisabledLabVisualization__icon { - font-size: $euiFontSizeXL; -} - diff --git a/src/plugins/visualizations/public/embeddable/disabled_lab_visualization.tsx b/src/plugins/visualizations/public/embeddable/disabled_lab_visualization.tsx index 3d2af2c591a3ce..ea7760f31d54c9 100644 --- a/src/plugins/visualizations/public/embeddable/disabled_lab_visualization.tsx +++ b/src/plugins/visualizations/public/embeddable/disabled_lab_visualization.tsx @@ -17,29 +17,42 @@ * under the License. */ -import { FormattedMessage } from '@kbn/i18n/react'; +import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; +import { EuiEmptyPrompt, EuiLink } from '@elastic/eui'; import React from 'react'; +import { getDocLinks } from '../services'; export function DisabledLabVisualization({ title }: { title: string }) { + const advancedSettingsLink = getDocLinks().links.management.visualizationSettings; return ( -
- + ); } diff --git a/test/functional/apps/management/_import_objects.ts b/test/functional/apps/management/_import_objects.ts index 4a7a85c738fc2b..52428c944d666e 100644 --- a/test/functional/apps/management/_import_objects.ts +++ b/test/functional/apps/management/_import_objects.ts @@ -37,7 +37,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('import objects', function describeIndexTests() { describe('.ndjson file', () => { beforeEach(async function () { - // delete .kibana index and then wait for Kibana to re-create it await kibanaServer.uiSettings.replace({}); await PageObjects.settings.navigateTo(); await esArchiver.load('management'); @@ -471,16 +470,20 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); }); - it('should display an explicit error message when importing a file bigger than allowed', async () => { - await PageObjects.savedObjects.importFile( - path.join(__dirname, 'exports', '_import_too_big.ndjson') - ); + describe('when bigger than savedObjects.maxImportPayloadBytes (not Cloud)', function () { + // see --savedObjects.maxImportPayloadBytes in config file + this.tags(['skipCloud']); + it('should display an explicit error message when importing a file bigger than allowed', async () => { + await PageObjects.savedObjects.importFile( + path.join(__dirname, 'exports', '_import_too_big.ndjson') + ); - await PageObjects.savedObjects.checkImportError(); + await PageObjects.savedObjects.checkImportError(); - const errorText = await PageObjects.savedObjects.getImportErrorText(); + const errorText = await PageObjects.savedObjects.getImportErrorText(); - expect(errorText).to.contain(`Payload content length greater than maximum allowed`); + expect(errorText).to.contain(`Payload content length greater than maximum allowed`); + }); }); it('should display an explicit error message when importing an invalid file', async () => { diff --git a/test/functional/apps/management/_mgmt_import_saved_objects.js b/test/functional/apps/management/_mgmt_import_saved_objects.js index 3a9f8665fd33bc..d479a7006d0f88 100644 --- a/test/functional/apps/management/_mgmt_import_saved_objects.js +++ b/test/functional/apps/management/_mgmt_import_saved_objects.js @@ -29,6 +29,7 @@ export default function ({ getService, getPageObjects }) { describe('mgmt saved objects', function describeIndexTests() { beforeEach(async function () { + await esArchiver.load('empty_kibana'); await esArchiver.load('discover'); await PageObjects.settings.navigateTo(); }); diff --git a/test/functional/apps/management/_scripted_fields.js b/test/functional/apps/management/_scripted_fields.js index 6da9ebed0538a8..5ca01f239e762f 100644 --- a/test/functional/apps/management/_scripted_fields.js +++ b/test/functional/apps/management/_scripted_fields.js @@ -198,35 +198,44 @@ export default function ({ getService, getPageObjects }) { }); it('should visualize scripted field in vertical bar chart', async function () { - const expectedChartValues = [ - ['14', '31'], - ['10', '29'], - ['7', '24'], - ['11', '24'], - ['12', '23'], - ['20', '23'], - ['19', '21'], - ['6', '20'], - ['17', '20'], - ['30', '20'], - ['13', '19'], - ['18', '18'], - ['16', '17'], - ['5', '16'], - ['8', '16'], - ['15', '14'], - ['3', '13'], - ['2', '12'], - ['9', '10'], - ['4', '9'], - ]; await filterBar.removeAllFilters(); await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName); await PageObjects.header.waitUntilLoadingHasFinished(); - await inspector.open(); - await inspector.setTablePageSize(50); - await inspector.expectTableData(expectedChartValues); + if (await PageObjects.common.isOss()) { + // OSS renders a vertical bar chart and we check the data in the Inspect panel + const expectedChartValues = [ + ['14', '31'], + ['10', '29'], + ['7', '24'], + ['11', '24'], + ['12', '23'], + ['20', '23'], + ['19', '21'], + ['6', '20'], + ['17', '20'], + ['30', '20'], + ['13', '19'], + ['18', '18'], + ['16', '17'], + ['5', '16'], + ['8', '16'], + ['15', '14'], + ['3', '13'], + ['2', '12'], + ['9', '10'], + ['4', '9'], + ]; + + await inspector.open(); + await inspector.setTablePageSize(50); + await inspector.expectTableData(expectedChartValues); + } else { + // verify Lens opens a visualization + expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( + 'Average of ram_Pain1' + ); + } }); }); @@ -309,11 +318,19 @@ export default function ({ getService, getPageObjects }) { it('should visualize scripted field in vertical bar chart', async function () { await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); await PageObjects.header.waitUntilLoadingHasFinished(); - await inspector.open(); - await inspector.expectTableData([ - ['good', '359'], - ['bad', '27'], - ]); + if (await PageObjects.common.isOss()) { + // OSS renders a vertical bar chart and we check the data in the Inspect panel + await inspector.open(); + await inspector.expectTableData([ + ['good', '359'], + ['bad', '27'], + ]); + } else { + // verify Lens opens a visualization + expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( + 'Top values of painString' + ); + } }); }); @@ -397,11 +414,19 @@ export default function ({ getService, getPageObjects }) { it('should visualize scripted field in vertical bar chart', async function () { await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); await PageObjects.header.waitUntilLoadingHasFinished(); - await inspector.open(); - await inspector.expectTableData([ - ['true', '359'], - ['false', '27'], - ]); + if (await PageObjects.common.isOss()) { + // OSS renders a vertical bar chart and we check the data in the Inspect panel + await inspector.open(); + await inspector.expectTableData([ + ['true', '359'], + ['false', '27'], + ]); + } else { + // verify Lens opens a visualization + expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( + 'Top values of painBool' + ); + } }); }); @@ -488,30 +513,39 @@ export default function ({ getService, getPageObjects }) { it('should visualize scripted field in vertical bar chart', async function () { await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); await PageObjects.header.waitUntilLoadingHasFinished(); - await inspector.open(); - await inspector.setTablePageSize(50); - await inspector.expectTableData([ - ['2015-09-17 20:00', '1'], - ['2015-09-17 21:00', '1'], - ['2015-09-17 23:00', '1'], - ['2015-09-18 00:00', '1'], - ['2015-09-18 03:00', '1'], - ['2015-09-18 04:00', '1'], - ['2015-09-18 04:00', '1'], - ['2015-09-18 04:00', '1'], - ['2015-09-18 04:00', '1'], - ['2015-09-18 05:00', '1'], - ['2015-09-18 05:00', '1'], - ['2015-09-18 05:00', '1'], - ['2015-09-18 05:00', '1'], - ['2015-09-18 06:00', '1'], - ['2015-09-18 06:00', '1'], - ['2015-09-18 06:00', '1'], - ['2015-09-18 06:00', '1'], - ['2015-09-18 07:00', '1'], - ['2015-09-18 07:00', '1'], - ['2015-09-18 07:00', '1'], - ]); + + if (await PageObjects.common.isOss()) { + // OSS renders a vertical bar chart and we check the data in the Inspect panel + await inspector.open(); + await inspector.setTablePageSize(50); + await inspector.expectTableData([ + ['2015-09-17 20:00', '1'], + ['2015-09-17 21:00', '1'], + ['2015-09-17 23:00', '1'], + ['2015-09-18 00:00', '1'], + ['2015-09-18 03:00', '1'], + ['2015-09-18 04:00', '1'], + ['2015-09-18 04:00', '1'], + ['2015-09-18 04:00', '1'], + ['2015-09-18 04:00', '1'], + ['2015-09-18 05:00', '1'], + ['2015-09-18 05:00', '1'], + ['2015-09-18 05:00', '1'], + ['2015-09-18 05:00', '1'], + ['2015-09-18 06:00', '1'], + ['2015-09-18 06:00', '1'], + ['2015-09-18 06:00', '1'], + ['2015-09-18 06:00', '1'], + ['2015-09-18 07:00', '1'], + ['2015-09-18 07:00', '1'], + ['2015-09-18 07:00', '1'], + ]); + } else { + // verify Lens opens a visualization + expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( + 'painDate' + ); + } }); }); }); diff --git a/test/plugin_functional/plugins/data_search/server/plugin.ts b/test/plugin_functional/plugins/data_search/server/plugin.ts index e016ef56802f3b..ca22e82188403a 100644 --- a/test/plugin_functional/plugins/data_search/server/plugin.ts +++ b/test/plugin_functional/plugins/data_search/server/plugin.ts @@ -58,14 +58,16 @@ export class DataSearchTestPlugin }, }, async (context, req, res) => { - const [{ savedObjects }, { data }] = await core.getStartServices(); + const [{ savedObjects, elasticsearch }, { data }] = await core.getStartServices(); const service = await data.search.searchSource.asScoped(req); + const clusterClient = elasticsearch.client.asScoped(req).asCurrentUser; const savedObjectsClient = savedObjects.getScopedClient(req); // Since the index pattern ID can change on each test run, we need // to look it up on the fly and insert it into the request. const indexPatterns = await data.indexPatterns.indexPatternsServiceFactory( - savedObjectsClient + savedObjectsClient, + clusterClient ); const ids = await indexPatterns.getIds(); // @ts-expect-error Force overwriting the request diff --git a/test/plugin_functional/plugins/index_patterns/server/plugin.ts b/test/plugin_functional/plugins/index_patterns/server/plugin.ts index a54502b7402115..c05b71b834c70b 100644 --- a/test/plugin_functional/plugins/index_patterns/server/plugin.ts +++ b/test/plugin_functional/plugins/index_patterns/server/plugin.ts @@ -36,13 +36,35 @@ export class IndexPatternsTestPlugin public setup(core: CoreSetup) { const router = core.http.createRouter(); + router.post( + { + path: '/api/index-patterns-plugin/create', + validate: { + body: schema.object({}, { unknowns: 'allow' }), + }, + }, + async (context, req, res) => { + const [{ savedObjects, elasticsearch }, { data }] = await core.getStartServices(); + const savedObjectsClient = savedObjects.getScopedClient(req); + const service = await data.indexPatterns.indexPatternsServiceFactory( + savedObjectsClient, + elasticsearch.client.asScoped(req).asCurrentUser + ); + const ids = await service.createAndSave(req.body); + return res.ok({ body: ids }); + } + ); + router.get( { path: '/api/index-patterns-plugin/get-all', validate: false }, async (context, req, res) => { - const [{ savedObjects }, { data }] = await core.getStartServices(); + const [{ savedObjects, elasticsearch }, { data }] = await core.getStartServices(); const savedObjectsClient = savedObjects.getScopedClient(req); - const service = await data.indexPatterns.indexPatternsServiceFactory(savedObjectsClient); - const ids = await service.getIds(); + const service = await data.indexPatterns.indexPatternsServiceFactory( + savedObjectsClient, + elasticsearch.client.asScoped(req).asCurrentUser + ); + const ids = await service.getIds(true); return res.ok({ body: ids }); } ); @@ -58,9 +80,12 @@ export class IndexPatternsTestPlugin }, async (context, req, res) => { const id = (req.params as Record).id; - const [{ savedObjects }, { data }] = await core.getStartServices(); + const [{ savedObjects, elasticsearch }, { data }] = await core.getStartServices(); const savedObjectsClient = savedObjects.getScopedClient(req); - const service = await data.indexPatterns.indexPatternsServiceFactory(savedObjectsClient); + const service = await data.indexPatterns.indexPatternsServiceFactory( + savedObjectsClient, + elasticsearch.client.asScoped(req).asCurrentUser + ); const ip = await service.get(id); return res.ok({ body: ip.toSpec() }); } @@ -76,10 +101,13 @@ export class IndexPatternsTestPlugin }, }, async (context, req, res) => { - const [{ savedObjects }, { data }] = await core.getStartServices(); + const [{ savedObjects, elasticsearch }, { data }] = await core.getStartServices(); const id = (req.params as Record).id; const savedObjectsClient = savedObjects.getScopedClient(req); - const service = await data.indexPatterns.indexPatternsServiceFactory(savedObjectsClient); + const service = await data.indexPatterns.indexPatternsServiceFactory( + savedObjectsClient, + elasticsearch.client.asScoped(req).asCurrentUser + ); const ip = await service.get(id); await service.updateSavedObject(ip); return res.ok(); @@ -96,10 +124,13 @@ export class IndexPatternsTestPlugin }, }, async (context, req, res) => { - const [{ savedObjects }, { data }] = await core.getStartServices(); + const [{ savedObjects, elasticsearch }, { data }] = await core.getStartServices(); const id = (req.params as Record).id; const savedObjectsClient = savedObjects.getScopedClient(req); - const service = await data.indexPatterns.indexPatternsServiceFactory(savedObjectsClient); + const service = await data.indexPatterns.indexPatternsServiceFactory( + savedObjectsClient, + elasticsearch.client.asScoped(req).asCurrentUser + ); await service.delete(id); return res.ok(); } diff --git a/test/plugin_functional/test_suites/data_plugin/index_patterns.ts b/test/plugin_functional/test_suites/data_plugin/index_patterns.ts index 2c846dc7803115..2e94f61c7ded8e 100644 --- a/test/plugin_functional/test_suites/data_plugin/index_patterns.ts +++ b/test/plugin_functional/test_suites/data_plugin/index_patterns.ts @@ -23,16 +23,25 @@ import '../../plugins/core_provider_plugin/types'; export default function ({ getService }: PluginFunctionalProviderContext) { const supertest = getService('supertest'); - // skipping the tests as it deletes index patterns created by other test causing unexpected failures - // https://github.com/elastic/kibana/issues/79886 - describe.skip('index patterns', function () { + describe('index patterns', function () { let indexPatternId = ''; - it('can get all ids', async () => { - const body = await (await supertest.get('/api/index-patterns-plugin/get-all').expect(200)) - .body; - indexPatternId = body[0]; - expect(body.length > 0).to.equal(true); + it('can create an index pattern', async () => { + const title = 'shakes*'; + const fieldFormats = { bytes: { id: 'bytes' } }; + const body = await ( + await supertest + .post('/api/index-patterns-plugin/create') + .set('kbn-xsrf', 'anything') + .send({ title, fieldFormats }) + .expect(200) + ).body; + + indexPatternId = body.id; + expect(body.id).not.empty(); + expect(body.title).to.equal(title); + expect(body.fields.length).to.equal(15); + expect(body.fieldFormatMap).to.eql(fieldFormats); }); it('can get index pattern by id', async () => { diff --git a/x-pack/plugins/actions/README.md b/x-pack/plugins/actions/README.md index 4fef9bc582d088..432a4bfff7a6b9 100644 --- a/x-pack/plugins/actions/README.md +++ b/x-pack/plugins/actions/README.md @@ -69,18 +69,21 @@ Table of Contents - [`secrets`](#secrets-6) - [`params`](#params-6) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice) + - [`subActionParams (getFields)`](#subactionparams-getfields-1) - [Jira](#jira) - [`config`](#config-7) - [`secrets`](#secrets-7) - [`params`](#params-7) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-1) - [`subActionParams (issueTypes)`](#subactionparams-issuetypes) + - [`subActionParams (getFields)`](#subactionparams-getfields-2) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-2) - [IBM Resilient](#ibm-resilient) - [`config`](#config-8) - [`secrets`](#secrets-8) - [`params`](#params-8) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-3) + - [`subActionParams (getFields)`](#subactionparams-getfields-3) - [Command Line Utility](#command-line-utility) - [Developing New Action Types](#developing-new-action-types) - [licensing](#licensing) @@ -563,7 +566,7 @@ The ServiceNow action uses the [V2 Table API](https://developer.servicenow.com/a | Property | Description | Type | | --------------- | ------------------------------------------------------------------------------------ | ------ | -| subAction | The sub action to perform. It can be `pushToService`, `handshake`, and `getIncident` | string | +| subAction | The sub action to perform. It can be `getFields`, `pushToService`, `handshake`, and `getIncident` | string | | subActionParams | The parameters of the sub action | object | #### `subActionParams (pushToService)` @@ -580,6 +583,10 @@ The ServiceNow action uses the [V2 Table API](https://developer.servicenow.com/a | urgency | The name of the urgency in ServiceNow. | string _(optional)_ | | impact | The name of the impact in ServiceNow. | string _(optional)_ | +#### `subActionParams (getFields)` + +No parameters for `getFields` sub-action. Provide an empty object `{}`. + --- ## Jira @@ -606,7 +613,7 @@ The Jira action uses the [V2 API](https://developer.atlassian.com/cloud/jira/pla | Property | Description | Type | | --------------- | ----------------------------------------------------------------------------------------------------------------------- | ------ | -| subAction | The sub action to perform. It can be `pushToService`, `handshake`, `getIncident`, `issueTypes`, and `fieldsByIssueType` | string | +| subAction | The sub action to perform. It can be `getFields`, `pushToService`, `handshake`, `getIncident`, `issueTypes`, and `fieldsByIssueType` | string | | subActionParams | The parameters of the sub action | object | #### `subActionParams (pushToService)` @@ -627,6 +634,10 @@ The Jira action uses the [V2 API](https://developer.atlassian.com/cloud/jira/pla No parameters for `issueTypes` sub-action. Provide an empty object `{}`. +#### `subActionParams (getFields)` + +No parameters for `getFields` sub-action. Provide an empty object `{}`. + #### `subActionParams (pushToService)` | Property | Description | Type | @@ -655,7 +666,7 @@ ID: `.resilient` | Property | Description | Type | | --------------- | ------------------------------------------------------------------------------------ | ------ | -| subAction | The sub action to perform. It can be `pushToService`, `handshake`, and `getIncident` | string | +| subAction | The sub action to perform. It can be `getFields`, `pushToService`, `handshake`, and `getIncident` | string | | subActionParams | The parameters of the sub action | object | #### `subActionParams (pushToService)` @@ -670,6 +681,10 @@ ID: `.resilient` | incidentTypes | An array with the ids of IBM Resilient incident types. | number[] _(optional)_ | | severityCode | IBM Resilient id of the severity code. | number _(optional)_ | +#### `subActionParams (getFields)` + +No parameters for `getFields` sub-action. Provide an empty object `{}`. + # Command Line Utility The [`kbn-action`](https://github.com/pmuellr/kbn-action) tool can be used to send HTTP requests to the Actions plugin. For instance, to create a Slack action from the `.slack` Action Type, use the following command: diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts index e8fa9f76df7780..5a7617ada1bf02 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts @@ -15,804 +15,792 @@ describe('api', () => { beforeEach(() => { externalService = externalServiceMock.create(); - jest.clearAllMocks(); }); - afterEach(() => { - jest.clearAllMocks(); - }); - - describe('pushToService', () => { - describe('create incident - cases', () => { - test('it creates an incident', async () => { - const params = { ...apiParams, externalId: null }; - const res = await api.pushToService({ - externalService, - mapping, - params, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-1', - title: 'CK-1', - pushedDate: '2020-04-27T10:59:46.202Z', - url: 'https://siem-kibana.atlassian.net/browse/CK-1', - comments: [ - { - commentId: 'case-comment-1', - pushedDate: '2020-04-27T10:59:46.202Z', - }, - { - commentId: 'case-comment-2', - pushedDate: '2020-04-27T10:59:46.202Z', - }, - ], - }); - }); - - test('it creates an incident without comments', async () => { - const params = { ...apiParams, externalId: null, comments: [] }; - const res = await api.pushToService({ - externalService, - mapping, - params, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-1', - title: 'CK-1', - pushedDate: '2020-04-27T10:59:46.202Z', - url: 'https://siem-kibana.atlassian.net/browse/CK-1', - }); - }); - - test('it calls createIncident correctly', async () => { - const params = { ...apiParams, externalId: null }; - await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); - - expect(externalService.createIncident).toHaveBeenCalledWith({ - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - description: - 'Incident description (created at 2020-04-27T10:59:46.202Z by Elastic User)', - summary: 'Incident title (created at 2020-04-27T10:59:46.202Z by Elastic User)', - }, - }); - expect(externalService.updateIncident).not.toHaveBeenCalled(); - }); - - test('it calls createIncident correctly without mapping', async () => { - const params = { ...apiParams, externalId: null }; - await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); - - expect(externalService.createIncident).toHaveBeenCalledWith({ - incident: { - description: 'Incident description', - summary: 'Incident title', - issueType: '10006', - labels: ['kibana', 'elastic'], - priority: 'High', - parent: null, - }, - }); - expect(externalService.updateIncident).not.toHaveBeenCalled(); + describe('create incident - cases', () => { + test('it creates an incident', async () => { + const params = { ...apiParams, externalId: null }; + const res = await api.pushToService({ + externalService, + mapping, + params, + logger: mockedLogger, }); - test('it calls createComment correctly', async () => { - const params = { ...apiParams, externalId: null }; - await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); - expect(externalService.createComment).toHaveBeenCalledTimes(2); - expect(externalService.createComment).toHaveBeenNthCalledWith(1, { - incidentId: 'incident-1', - comment: { + expect(res).toEqual({ + id: 'incident-1', + title: 'CK-1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', + comments: [ + { commentId: 'case-comment-1', - comment: 'A comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, + pushedDate: '2020-04-27T10:59:46.202Z', }, - }); - - expect(externalService.createComment).toHaveBeenNthCalledWith(2, { - incidentId: 'incident-1', - comment: { + { commentId: 'case-comment-2', - comment: 'Another comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, + pushedDate: '2020-04-27T10:59:46.202Z', }, - }); + ], }); + }); - test('it calls createComment correctly without mapping', async () => { - const params = { ...apiParams, externalId: null }; - await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); - expect(externalService.createComment).toHaveBeenCalledTimes(2); - expect(externalService.createComment).toHaveBeenNthCalledWith(1, { - incidentId: 'incident-1', - comment: { - commentId: 'case-comment-1', - comment: 'A comment', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - }, - }); + test('it creates an incident without comments', async () => { + const params = { ...apiParams, externalId: null, comments: [] }; + const res = await api.pushToService({ + externalService, + mapping, + params, + logger: mockedLogger, + }); - expect(externalService.createComment).toHaveBeenNthCalledWith(2, { - incidentId: 'incident-1', - comment: { - commentId: 'case-comment-2', - comment: 'Another comment', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - }, - }); + expect(res).toEqual({ + id: 'incident-1', + title: 'CK-1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', }); }); - describe('update incident', () => { - test('it updates an incident', async () => { - const res = await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-1', - title: 'CK-1', - pushedDate: '2020-04-27T10:59:46.202Z', - url: 'https://siem-kibana.atlassian.net/browse/CK-1', - comments: [ - { - commentId: 'case-comment-1', - pushedDate: '2020-04-27T10:59:46.202Z', - }, - { - commentId: 'case-comment-2', - pushedDate: '2020-04-27T10:59:46.202Z', - }, - ], - }); - }); - - test('it updates an incident without comments', async () => { - const params = { ...apiParams, comments: [] }; - const res = await api.pushToService({ - externalService, - mapping, - params, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-1', - title: 'CK-1', - pushedDate: '2020-04-27T10:59:46.202Z', - url: 'https://siem-kibana.atlassian.net/browse/CK-1', - }); - }); - - test('it calls updateIncident correctly', async () => { - const params = { ...apiParams }; - await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); - - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - description: - 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', - summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + test('it calls createIncident correctly', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); + + expect(externalService.createIncident).toHaveBeenCalledWith({ + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + description: 'Incident description (created at 2020-04-27T10:59:46.202Z by Elastic User)', + summary: 'Incident title (created at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + expect(externalService.updateIncident).not.toHaveBeenCalled(); + }); + + test('it calls createIncident correctly without mapping', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); + + expect(externalService.createIncident).toHaveBeenCalledWith({ + incident: { + description: 'Incident description', + summary: 'Incident title', + issueType: '10006', + labels: ['kibana', 'elastic'], + priority: 'High', + parent: null, + }, + }); + expect(externalService.updateIncident).not.toHaveBeenCalled(); + }); + + test('it calls createComment correctly', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); + expect(externalService.createComment).toHaveBeenCalledTimes(2); + expect(externalService.createComment).toHaveBeenNthCalledWith(1, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-1', + comment: 'A comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - expect(externalService.createIncident).not.toHaveBeenCalled(); - }); - - test('it calls updateIncident correctly without mapping', async () => { - const params = { ...apiParams }; - await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); - - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - description: 'Incident description', - summary: 'Incident title', - issueType: '10006', - labels: ['kibana', 'elastic'], - priority: 'High', - parent: null, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - expect(externalService.createIncident).not.toHaveBeenCalled(); + }, }); - test('it calls createComment correctly', async () => { - const params = { ...apiParams }; - await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); - expect(externalService.createComment).toHaveBeenCalledTimes(2); - expect(externalService.createComment).toHaveBeenNthCalledWith(1, { - incidentId: 'incident-1', - comment: { - commentId: 'case-comment-1', - comment: 'A comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, + expect(externalService.createComment).toHaveBeenNthCalledWith(2, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-2', + comment: 'Another comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - - expect(externalService.createComment).toHaveBeenNthCalledWith(2, { - incidentId: 'incident-1', - comment: { - commentId: 'case-comment-2', - comment: 'Another comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); + }, }); + }); - test('it calls createComment correctly without mapping', async () => { - const params = { ...apiParams }; - await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); - expect(externalService.createComment).toHaveBeenCalledTimes(2); - expect(externalService.createComment).toHaveBeenNthCalledWith(1, { - incidentId: 'incident-1', - comment: { - commentId: 'case-comment-1', - comment: 'A comment', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, + test('it calls createComment correctly without mapping', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); + expect(externalService.createComment).toHaveBeenCalledTimes(2); + expect(externalService.createComment).toHaveBeenNthCalledWith(1, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-1', + comment: 'A comment', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); + }, + }); - expect(externalService.createComment).toHaveBeenNthCalledWith(2, { - incidentId: 'incident-1', - comment: { - commentId: 'case-comment-2', - comment: 'Another comment', - createdAt: '2020-04-27T10:59:46.202Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-04-27T10:59:46.202Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, + expect(externalService.createComment).toHaveBeenNthCalledWith(2, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-2', + comment: 'Another comment', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); + }, }); }); + }); - describe('issueTypes', () => { - test('it returns the issue types correctly', async () => { - const res = await api.issueTypes({ - externalService, - params: {}, - }); - expect(res).toEqual([ + describe('update incident', () => { + test('it updates an incident', async () => { + const res = await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + + expect(res).toEqual({ + id: 'incident-1', + title: 'CK-1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', + comments: [ { - id: '10006', - name: 'Task', + commentId: 'case-comment-1', + pushedDate: '2020-04-27T10:59:46.202Z', }, { - id: '10007', - name: 'Bug', + commentId: 'case-comment-2', + pushedDate: '2020-04-27T10:59:46.202Z', }, - ]); + ], }); }); - describe('fieldsByIssueType', () => { - test('it returns the fields correctly', async () => { - const res = await api.fieldsByIssueType({ - externalService, - params: { id: '10006' }, - }); - expect(res).toEqual({ - summary: { allowedValues: [], defaultValue: {} }, - priority: { - allowedValues: [ - { - name: 'Medium', - id: '3', - }, - ], - defaultValue: { name: 'Medium', id: '3' }, - }, - }); + test('it updates an incident without comments', async () => { + const params = { ...apiParams, comments: [] }; + const res = await api.pushToService({ + externalService, + mapping, + params, + logger: mockedLogger, + }); + + expect(res).toEqual({ + id: 'incident-1', + title: 'CK-1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', }); }); - describe('getIssues', () => { - test('it returns the issues correctly', async () => { - const res = await api.issues({ - externalService, - params: { title: 'Title test' }, - }); - expect(res).toEqual([ - { - id: '10267', - key: 'RJ-107', - title: 'Test title', - }, - ]); + test('it calls updateIncident correctly', async () => { + const params = { ...apiParams }; + await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); + + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + description: 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, }); + expect(externalService.createIncident).not.toHaveBeenCalled(); }); - describe('getIssue', () => { - test('it returns the issue correctly', async () => { - const res = await api.issue({ - externalService, - params: { id: 'RJ-107' }, - }); - expect(res).toEqual({ - id: '10267', - key: 'RJ-107', - title: 'Test title', - }); + test('it calls updateIncident correctly without mapping', async () => { + const params = { ...apiParams }; + await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); + + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + description: 'Incident description', + summary: 'Incident title', + issueType: '10006', + labels: ['kibana', 'elastic'], + priority: 'High', + parent: null, + }, }); + expect(externalService.createIncident).not.toHaveBeenCalled(); }); - describe('mapping variations', () => { - test('overwrite & append', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'append', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', - description: - 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', - }, - }); - }); - - test('nothing & append', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'nothing', - }); - - mapping.set('description', { - target: 'description', - actionType: 'append', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'nothing', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - description: - 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + test('it calls createComment correctly', async () => { + const params = { ...apiParams }; + await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); + expect(externalService.createComment).toHaveBeenCalledTimes(2); + expect(externalService.createComment).toHaveBeenNthCalledWith(1, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-1', + comment: 'A comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('append & append', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'append', - }); - - mapping.set('description', { - target: 'description', - actionType: 'append', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'append', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - summary: - 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', - description: - 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('nothing & nothing', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'nothing', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'nothing', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, + }, + }); + + expect(externalService.createComment).toHaveBeenNthCalledWith(2, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-2', + comment: 'Another comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('overwrite & nothing', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('overwrite & overwrite', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', - description: - 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('it calls createComment correctly without mapping', async () => { + const params = { ...apiParams }; + await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); + expect(externalService.createComment).toHaveBeenCalledTimes(2); + expect(externalService.createComment).toHaveBeenNthCalledWith(1, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-1', + comment: 'A comment', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('nothing & overwrite', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'nothing', - }); - - mapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'nothing', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - description: - 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('append & overwrite', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'append', - }); - - mapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'append', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - summary: - 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', - description: - 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + + expect(externalService.createComment).toHaveBeenNthCalledWith(2, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-2', + comment: 'Another comment', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('append & nothing', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'append', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'append', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - labels: ['kibana', 'elastic'], - priority: 'High', - issueType: '10006', - parent: null, - summary: - 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', }, - }); - }); - - test('comment nothing', async () => { - mapping.set('title', { - target: 'summary', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'nothing', - }); - - mapping.set('summary', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - logger: mockedLogger, - }); - expect(externalService.createComment).not.toHaveBeenCalled(); + }, + }); + }); + }); + + describe('issueTypes', () => { + test('it returns the issue types correctly', async () => { + const res = await api.issueTypes({ + externalService, + params: {}, + }); + expect(res).toEqual([ + { + id: '10006', + name: 'Task', + }, + { + id: '10007', + name: 'Bug', + }, + ]); + }); + }); + + describe('fieldsByIssueType', () => { + test('it returns the fields correctly', async () => { + const res = await api.fieldsByIssueType({ + externalService, + params: { id: '10006' }, + }); + expect(res).toEqual({ + summary: { allowedValues: [], defaultValue: {} }, + priority: { + allowedValues: [ + { + name: 'Medium', + id: '3', + }, + ], + defaultValue: { name: 'Medium', id: '3' }, + }, + }); + }); + }); + + describe('getIssues', () => { + test('it returns the issues correctly', async () => { + const res = await api.issues({ + externalService, + params: { title: 'Title test' }, + }); + expect(res).toEqual([ + { + id: '10267', + key: 'RJ-107', + title: 'Test title', + }, + ]); + }); + }); + + describe('getIssue', () => { + test('it returns the issue correctly', async () => { + const res = await api.issue({ + externalService, + params: { id: 'RJ-107' }, + }); + expect(res).toEqual({ + id: '10267', + key: 'RJ-107', + title: 'Test title', + }); + }); + }); + + describe('mapping variations', () => { + test('overwrite & append', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + description: + 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('nothing & append', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + description: + 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('append & append', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + summary: + 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + description: + 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('nothing & nothing', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + }, + }); + }); + + test('overwrite & nothing', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('overwrite & overwrite', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + description: 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('nothing & overwrite', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + description: 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('append & overwrite', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + summary: + 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + description: 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('append & nothing', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', + parent: null, + summary: + 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('comment nothing', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'nothing', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, }); + expect(externalService.createComment).not.toHaveBeenCalled(); }); }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts index 679c1541964ce5..feeb69b1d1a0ec 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts @@ -17,6 +17,7 @@ import { PushToServiceApiParams, PushToServiceResponse, GetIssueHandlerArgs, + GetCommonFieldsHandlerArgs, } from './types'; // TODO: to remove, need to support Case @@ -39,6 +40,11 @@ const getIssueTypesHandler = async ({ externalService }: GetIssueTypesHandlerArg return res; }; +const getFieldsHandler = async ({ externalService }: GetCommonFieldsHandlerArgs) => { + const res = await externalService.getFields(); + return res; +}; + const getFieldsByIssueTypeHandler = async ({ externalService, params, @@ -157,6 +163,7 @@ const pushToServiceHandler = async ({ }; export const api: ExternalServiceApi = { + getFields: getFieldsHandler, handshake: handshakeHandler, pushToService: pushToServiceHandler, getIncident: getIncidentHandler, diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts index 9d6ff90c337009..c70c0810926f48 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts @@ -40,6 +40,7 @@ interface GetActionTypeParams { } const supportedSubActions: string[] = [ + 'getFields', 'pushToService', 'issueTypes', 'fieldsByIssueType', @@ -145,6 +146,13 @@ async function executor( }); } + if (subAction === 'getFields') { + data = await api.getFields({ + externalService, + params: subActionParams, + }); + } + if (subAction === 'issues') { const getIssuesParams = subActionParams as ExecutorSubActionGetIssuesParams; data = await api.issues({ diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts index b98eda799e3aad..87a0f156a0c2a9 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts @@ -73,6 +73,20 @@ const createMock = (): jest.Mocked => { key: 'RJ-107', title: 'Test title', })), + getFields: jest.fn().mockImplementation(() => ({ + description: { + allowedValues: [], + defaultValue: {}, + required: true, + schema: { type: 'string' }, + }, + summary: { + allowedValues: [], + defaultValue: {}, + required: true, + schema: { type: 'string' }, + }, + })), }; service.createComment.mockImplementationOnce(() => @@ -97,7 +111,6 @@ const createMock = (): jest.Mocked => { const externalServiceMock = { create: createMock, }; - const mapping: Map> = new Map(); mapping.set('title', { diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts index 513ca2cf18e6c7..70b60ada9c3864 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts @@ -55,6 +55,7 @@ export const ExecutorSubActionGetIncidentParamsSchema = schema.object({ }); // Reserved for future implementation +export const ExecutorSubActionCommonFieldsParamsSchema = schema.object({}); export const ExecutorSubActionHandshakeParamsSchema = schema.object({}); export const ExecutorSubActionGetCapabilitiesParamsSchema = schema.object({}); export const ExecutorSubActionGetIssueTypesParamsSchema = schema.object({}); @@ -65,6 +66,10 @@ export const ExecutorSubActionGetIssuesParamsSchema = schema.object({ title: sch export const ExecutorSubActionGetIssueParamsSchema = schema.object({ id: schema.string() }); export const ExecutorParamsSchema = schema.oneOf([ + schema.object({ + subAction: schema.literal('getFields'), + subActionParams: ExecutorSubActionCommonFieldsParamsSchema, + }), schema.object({ subAction: schema.literal('getIncident'), subActionParams: ExecutorSubActionGetIncidentParamsSchema, diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts index fe4e135c76fc37..2165ba56428c94 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts @@ -57,8 +57,10 @@ const fieldsResponse = { id: '10006', name: 'Task', fields: { - summary: { fieldId: 'summary' }, + summary: { required: true, schema: { type: 'string' }, fieldId: 'summary' }, priority: { + required: false, + schema: { type: 'string' }, fieldId: 'priority', allowedValues: [ { @@ -198,7 +200,7 @@ describe('Jira service', () => { error.response = { data: { errors: { summary: 'Required field' } } }; throw error; }); - expect(service.getIncident('1')).rejects.toThrow( + await expect(service.getIncident('1')).rejects.toThrow( '[Action][Jira]: Unable to get incident with id 1. Error: An error has occurred Reason: Required field' ); }); @@ -348,7 +350,7 @@ describe('Jira service', () => { throw error; }); - expect( + await expect( service.createIncident({ incident: { summary: 'title', @@ -442,7 +444,7 @@ describe('Jira service', () => { throw error; }); - expect( + await expect( service.updateIncident({ incidentId: '1', incident: { @@ -526,7 +528,7 @@ describe('Jira service', () => { throw error; }); - expect( + await expect( service.createComment({ incidentId: '1', comment: { @@ -587,7 +589,7 @@ describe('Jira service', () => { throw error; }); - expect(service.getCapabilities()).rejects.toThrow( + await expect(service.getCapabilities()).rejects.toThrow( '[Action][Jira]: Unable to get capabilities. Error: An error has occurred. Reason: Could not get capabilities' ); }); @@ -657,7 +659,7 @@ describe('Jira service', () => { throw error; }); - expect(service.getIssueTypes()).rejects.toThrow( + await expect(service.getIssueTypes()).rejects.toThrow( '[Action][Jira]: Unable to get issue types. Error: An error has occurred. Reason: Could not get issue types' ); }); @@ -741,7 +743,7 @@ describe('Jira service', () => { throw error; }); - expect(service.getIssueTypes()).rejects.toThrow( + await expect(service.getIssueTypes()).rejects.toThrow( '[Action][Jira]: Unable to get issue types. Error: An error has occurred. Reason: Could not get issue types' ); }); @@ -765,6 +767,8 @@ describe('Jira service', () => { expect(res).toEqual({ priority: { + required: false, + schema: { type: 'string' }, allowedValues: [ { id: '1', name: 'Highest' }, { id: '2', name: 'High' }, @@ -774,7 +778,12 @@ describe('Jira service', () => { ], defaultValue: { id: '3', name: 'Medium' }, }, - summary: { allowedValues: [], defaultValue: {} }, + summary: { + required: true, + schema: { type: 'string' }, + allowedValues: [], + defaultValue: {}, + }, }); }); @@ -815,7 +824,7 @@ describe('Jira service', () => { throw error; }); - expect(service.getFieldsByIssueType('10006')).rejects.toThrow( + await expect(service.getFieldsByIssueType('10006')).rejects.toThrow( '[Action][Jira]: Unable to get fields. Error: An error has occurred. Reason: Could not get fields' ); }); @@ -837,8 +846,10 @@ describe('Jira service', () => { requestMock.mockImplementationOnce(() => ({ data: { values: [ - { fieldId: 'summary' }, + { required: true, schema: { type: 'string' }, fieldId: 'summary' }, { + required: false, + schema: { type: 'string' }, fieldId: 'priority', allowedValues: [ { @@ -859,10 +870,17 @@ describe('Jira service', () => { expect(res).toEqual({ priority: { + required: false, + schema: { type: 'string' }, allowedValues: [{ id: '3', name: 'Medium' }], defaultValue: { id: '3', name: 'Medium' }, }, - summary: { allowedValues: [], defaultValue: {} }, + summary: { + required: true, + schema: { type: 'string' }, + allowedValues: [], + defaultValue: {}, + }, }); }); @@ -881,8 +899,10 @@ describe('Jira service', () => { requestMock.mockImplementationOnce(() => ({ data: { values: [ - { fieldId: 'summary' }, + { required: true, schema: { type: 'string' }, fieldId: 'summary' }, { + required: true, + schema: { type: 'string' }, fieldId: 'priority', allowedValues: [ { @@ -927,7 +947,7 @@ describe('Jira service', () => { throw error; }); - expect(service.getFieldsByIssueType('10006')).rejects.toThrow( + await expect(service.getFieldsByIssueType('10006')).rejects.toThrowError( '[Action][Jira]: Unable to get fields. Error: An error has occurred. Reason: Could not get issue types' ); }); @@ -976,7 +996,7 @@ describe('Jira service', () => { throw error; }); - expect(service.getIssues('Test title')).rejects.toThrow( + await expect(service.getIssues('Test title')).rejects.toThrow( '[Action][Jira]: Unable to get issues. Error: An error has occurred. Reason: Could not get issue types' ); }); @@ -1020,9 +1040,128 @@ describe('Jira service', () => { throw error; }); - expect(service.getIssue('RJ-107')).rejects.toThrow( + await expect(service.getIssue('RJ-107')).rejects.toThrow( '[Action][Jira]: Unable to get issue with id RJ-107. Error: An error has occurred. Reason: Could not get issue types' ); }); }); + + describe('getFields', () => { + const callMocks = () => { + requestMock + .mockImplementationOnce(() => ({ + data: { + capabilities: { + 'list-project-issuetypes': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes', + 'list-issuetype-fields': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields', + }, + }, + })) + .mockImplementationOnce(() => ({ + data: { + values: issueTypesResponse.data.projects[0].issuetypes, + }, + })) + .mockImplementationOnce(() => ({ + data: { + capabilities: { + 'list-project-issuetypes': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes', + 'list-issuetype-fields': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields', + }, + }, + })) + .mockImplementationOnce(() => ({ + data: { + capabilities: { + 'list-project-issuetypes': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes', + 'list-issuetype-fields': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields', + }, + }, + })) + .mockImplementationOnce(() => ({ + data: { + values: [ + { required: true, schema: { type: 'string' }, fieldId: 'summary' }, + { required: true, schema: { type: 'string' }, fieldId: 'description' }, + { + required: false, + schema: { type: 'string' }, + fieldId: 'priority', + allowedValues: [ + { + name: 'Medium', + id: '3', + }, + ], + defaultValue: { + name: 'Medium', + id: '3', + }, + }, + ], + }, + })) + .mockImplementationOnce(() => ({ + data: { + values: [ + { required: true, schema: { type: 'string' }, fieldId: 'summary' }, + { required: true, schema: { type: 'string' }, fieldId: 'description' }, + ], + }, + })); + }; + beforeEach(() => { + jest.resetAllMocks(); + }); + test('it should call request with correct arguments', async () => { + callMocks(); + await service.getFields(); + const callUrls = [ + 'https://siem-kibana.atlassian.net/rest/capabilities', + 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes', + 'https://siem-kibana.atlassian.net/rest/capabilities', + 'https://siem-kibana.atlassian.net/rest/capabilities', + 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes/10006', + 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes/10007', + ]; + requestMock.mock.calls.forEach((call, i) => { + expect(call[0].url).toEqual(callUrls[i]); + }); + }); + test('it returns common fields correctly', async () => { + callMocks(); + const res = await service.getFields(); + expect(res).toEqual({ + description: { + allowedValues: [], + defaultValue: {}, + required: true, + schema: { type: 'string' }, + }, + summary: { + allowedValues: [], + defaultValue: {}, + required: true, + schema: { type: 'string' }, + }, + }); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementation(() => { + const error: ResponseError = new Error('An error has occurred'); + error.response = { data: { errors: { summary: 'Required field' } } }; + throw error; + }); + await expect(service.getFields()).rejects.toThrow( + '[Action][Jira]: Unable to get capabilities. Error: An error has occurred. Reason: Required field' + ); + }); + }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts index f5347891f4f705..b3c5bb4a84de5b 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts @@ -8,18 +8,20 @@ import axios from 'axios'; import { Logger } from '../../../../../../src/core/server'; import { - ExternalServiceCredentials, - ExternalService, + CreateCommentParams, CreateIncidentParams, - UpdateIncidentParams, - JiraPublicConfigurationType, - JiraSecretConfigurationType, + ExternalService, + ExternalServiceCommentResponse, + ExternalServiceCredentials, + ExternalServiceIncidentResponse, Fields, - CreateCommentParams, + FieldSchema, + GetCommonFieldsResponse, Incident, + JiraPublicConfigurationType, + JiraSecretConfigurationType, ResponseError, - ExternalServiceCommentResponse, - ExternalServiceIncidentResponse, + UpdateIncidentParams, } from './types'; import * as i18n from './translations'; @@ -127,14 +129,21 @@ export const createExternalService = ( issueTypes.map((type) => ({ id: type.id, name: type.name })); const normalizeFields = (fields: { - [key: string]: { allowedValues?: Array<{}>; defaultValue?: {} }; + [key: string]: { + allowedValues?: Array<{}>; + defaultValue?: {}; + required: boolean; + schema: FieldSchema; + }; }) => Object.keys(fields ?? {}).reduce((fieldsAcc, fieldKey) => { return { ...fieldsAcc, [fieldKey]: { + required: fields[fieldKey]?.required, allowedValues: fields[fieldKey]?.allowedValues ?? [], defaultValue: fields[fieldKey]?.defaultValue ?? {}, + schema: fields[fieldKey]?.schema, }, }; }, {}); @@ -326,7 +335,6 @@ export const createExternalService = ( const getIssueTypes = async () => { const capabilitiesResponse = await getCapabilities(); const supportsNewAPI = hasSupportForNewAPI(capabilitiesResponse); - try { if (!supportsNewAPI) { const res = await request({ @@ -366,7 +374,6 @@ export const createExternalService = ( const getFieldsByIssueType = async (issueTypeId: string) => { const capabilitiesResponse = await getCapabilities(); const supportsNewAPI = hasSupportForNewAPI(capabilitiesResponse); - try { if (!supportsNewAPI) { const res = await request({ @@ -378,6 +385,7 @@ export const createExternalService = ( }); const fields = res.data.projects[0]?.issuetypes[0]?.fields || {}; + return normalizeFields(fields); } else { const res = await request({ @@ -409,6 +417,30 @@ export const createExternalService = ( } }; + const getFields = async () => { + try { + const issueTypes = await getIssueTypes(); + const fieldsPerIssueType = await Promise.all( + issueTypes.map((issueType) => getFieldsByIssueType(issueType.id)) + ); + return fieldsPerIssueType.reduce((acc: GetCommonFieldsResponse, fieldTypesByIssue) => { + const currentListOfFields = Object.keys(acc); + return currentListOfFields.length === 0 + ? fieldTypesByIssue + : currentListOfFields.reduce( + (add: GetCommonFieldsResponse, field) => + Object.keys(fieldTypesByIssue).includes(field) + ? { ...add, [field]: acc[field] } + : add, + {} + ); + }, {}); + } catch (error) { + // errors that happen here would be thrown in the contained async calls + throw error; + } + }; + const getIssues = async (title: string) => { const query = `${searchUrl}?jql=${encodeURIComponent( `project="${projectKey}" and summary ~"${title}"` @@ -461,6 +493,7 @@ export const createExternalService = ( }; return { + getFields, getIncident, createIncident, updateIncident, diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts index 7d650a22fba1bb..e142637010a986 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts @@ -79,11 +79,34 @@ export interface CreateCommentParams { comment: Comment; } +export interface FieldsSchema { + type: string; + [key: string]: string; +} + +export interface ExternalServiceFields { + clauseNames: string[]; + custom: boolean; + id: string; + key: string; + name: string; + navigatable: boolean; + orderable: boolean; + schema: FieldsSchema; + searchable: boolean; +} + export type GetIssueTypesResponse = Array<{ id: string; name: string }>; + +export interface FieldSchema { + type: string; + items?: string; +} export type GetFieldsByIssueTypeResponse = Record< string, - { allowedValues: Array<{}>; defaultValue: {} } + { allowedValues: Array<{}>; defaultValue: {}; required: boolean; schema: FieldSchema } >; +export type GetCommonFieldsResponse = GetFieldsByIssueTypeResponse; export type GetIssuesResponse = Array<{ id: string; key: string; title: string }>; export interface GetIssueResponse { @@ -93,15 +116,16 @@ export interface GetIssueResponse { } export interface ExternalService { - getIncident: (id: string) => Promise; - createIncident: (params: CreateIncidentParams) => Promise; - updateIncident: (params: UpdateIncidentParams) => Promise; createComment: (params: CreateCommentParams) => Promise; + createIncident: (params: CreateIncidentParams) => Promise; + getFields: () => Promise; getCapabilities: () => Promise; - getIssueTypes: () => Promise; getFieldsByIssueType: (issueTypeId: string) => Promise; - getIssues: (title: string) => Promise; + getIncident: (id: string) => Promise; getIssue: (id: string) => Promise; + getIssues: (title: string) => Promise; + getIssueTypes: () => Promise; + updateIncident: (params: UpdateIncidentParams) => Promise; } export interface PushToServiceApiParams extends ExecutorSubActionPushParams { @@ -157,6 +181,11 @@ export interface GetIssueTypesHandlerArgs { params: ExecutorSubActionGetIssueTypesParams; } +export interface GetCommonFieldsHandlerArgs { + externalService: ExternalService; + params: ExecutorSubActionGetIssueTypesParams; +} + export interface GetFieldsByIssueTypeHandlerArgs { externalService: ExternalService; params: ExecutorSubActionGetFieldsByIssueTypeParams; @@ -177,15 +206,16 @@ export interface GetIssueHandlerArgs { } export interface ExternalServiceApi { - handshake: (args: HandshakeApiHandlerArgs) => Promise; - pushToService: (args: PushToServiceApiHandlerArgs) => Promise; + getFields: (args: GetCommonFieldsHandlerArgs) => Promise; getIncident: (args: GetIncidentApiHandlerArgs) => Promise; + handshake: (args: HandshakeApiHandlerArgs) => Promise; issueTypes: (args: GetIssueTypesHandlerArgs) => Promise; + pushToService: (args: PushToServiceApiHandlerArgs) => Promise; fieldsByIssueType: ( args: GetFieldsByIssueTypeHandlerArgs ) => Promise; - issues: (args: GetIssuesHandlerArgs) => Promise; issue: (args: GetIssueHandlerArgs) => Promise; + issues: (args: GetIssuesHandlerArgs) => Promise; } export type JiraExecutorResultData = diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/api.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/api.ts index 46d9c114297a9c..29f2594d2b6f8a 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/api.ts @@ -15,6 +15,7 @@ import { GetSeverityHandlerArgs, PushToServiceApiParams, PushToServiceResponse, + GetCommonFieldsHandlerArgs, } from './types'; // TODO: to remove, need to support Case @@ -32,6 +33,10 @@ const getIncidentHandler = async ({ params, }: GetIncidentApiHandlerArgs) => {}; +const getFieldsHandler = async ({ externalService }: GetCommonFieldsHandlerArgs) => { + const res = await externalService.getFields(); + return res; +}; const getIncidentTypesHandler = async ({ externalService }: GetIncidentTypesHandlerArgs) => { const res = await externalService.getIncidentTypes(); return res; @@ -136,9 +141,10 @@ const pushToServiceHandler = async ({ }; export const api: ExternalServiceApi = { - handshake: handshakeHandler, - pushToService: pushToServiceHandler, + getFields: getFieldsHandler, getIncident: getIncidentHandler, + handshake: handshakeHandler, incidentTypes: getIncidentTypesHandler, + pushToService: pushToServiceHandler, severity: getSeverityHandler, }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/index.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/index.ts index 53285a2a350aff..6203dda4120f56 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/index.ts @@ -25,6 +25,7 @@ import { ResilientExecutorResultData, ExecutorSubActionGetIncidentTypesParams, ExecutorSubActionGetSeverityParams, + ExecutorSubActionCommonFieldsParams, } from './types'; import * as i18n from './translations'; import { Logger } from '../../../../../../src/core/server'; @@ -37,7 +38,7 @@ interface GetActionTypeParams { configurationUtilities: ActionsConfigurationUtilities; } -const supportedSubActions: string[] = ['pushToService', 'incidentTypes', 'severity']; +const supportedSubActions: string[] = ['getFields', 'pushToService', 'incidentTypes', 'severity']; // action type definition export function getActionType( @@ -122,6 +123,14 @@ async function executor( logger.debug(`response push to service for incident id: ${data.id}`); } + if (subAction === 'getFields') { + const getFieldsParams = subActionParams as ExecutorSubActionCommonFieldsParams; + data = await api.getFields({ + externalService, + params: getFieldsParams, + }); + } + if (subAction === 'incidentTypes') { const incidentTypesParams = subActionParams as ExecutorSubActionGetIncidentTypesParams; data = await api.incidentTypes({ diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/mocks.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/mocks.ts index 2e841728159a3b..2b2a22a66b7098 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/mocks.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/mocks.ts @@ -8,8 +8,275 @@ import { ExternalService, PushToServiceApiParams, ExecutorSubActionPushParams } import { MapRecord } from '../case/types'; +export const resilientFields = [ + { + id: 17, + name: 'name', + text: 'Name', + prefix: null, + type_id: 0, + tooltip: 'A unique name to identify this particular incident.', + input_type: 'text', + required: 'always', + hide_notification: false, + chosen: false, + default_chosen_by_server: false, + blank_option: false, + internal: true, + uuid: 'ad6ed4f2-8d87-4ba2-81fa-03568a9326cc', + operations: [ + 'equals', + 'not_equals', + 'contains', + 'not_contains', + 'changed', + 'changed_to', + 'not_changed_to', + 'has_a_value', + 'not_has_a_value', + ], + operation_perms: { + changed_to: { + show_in_manual_actions: false, + show_in_auto_actions: true, + show_in_notifications: true, + }, + has_a_value: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_changed_to: { + show_in_manual_actions: false, + show_in_auto_actions: true, + show_in_notifications: true, + }, + equals: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + changed: { + show_in_manual_actions: false, + show_in_auto_actions: true, + show_in_notifications: true, + }, + contains: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_contains: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_equals: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_has_a_value: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + }, + values: [], + perms: { + delete: false, + modify_name: false, + modify_values: false, + modify_blank: false, + modify_required: false, + modify_operations: false, + modify_chosen: false, + modify_default: false, + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + show_in_scripts: true, + modify_type: ['text'], + sort: true, + }, + read_only: false, + changeable: true, + rich_text: false, + templates: [], + deprecated: false, + tags: [], + calculated: false, + is_tracked: false, + allow_default_value: false, + }, + { + id: 15, + name: 'description', + text: 'Description', + prefix: null, + type_id: 0, + tooltip: 'A free form text description of the incident.', + input_type: 'textarea', + hide_notification: false, + chosen: false, + default_chosen_by_server: false, + blank_option: false, + internal: true, + uuid: '420d70b1-98f9-4681-a20b-84f36a9e5e48', + operations: [ + 'equals', + 'not_equals', + 'contains', + 'not_contains', + 'changed', + 'changed_to', + 'not_changed_to', + 'has_a_value', + 'not_has_a_value', + ], + operation_perms: { + changed_to: { + show_in_manual_actions: false, + show_in_auto_actions: true, + show_in_notifications: true, + }, + has_a_value: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_changed_to: { + show_in_manual_actions: false, + show_in_auto_actions: true, + show_in_notifications: true, + }, + equals: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + changed: { + show_in_manual_actions: false, + show_in_auto_actions: true, + show_in_notifications: true, + }, + contains: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_contains: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_equals: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_has_a_value: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + }, + values: [], + perms: { + delete: false, + modify_name: false, + modify_values: false, + modify_blank: false, + modify_required: false, + modify_operations: false, + modify_chosen: false, + modify_default: false, + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + show_in_scripts: true, + modify_type: ['textarea'], + sort: true, + }, + read_only: false, + changeable: true, + rich_text: true, + templates: [], + deprecated: false, + tags: [], + calculated: false, + is_tracked: false, + allow_default_value: false, + }, + { + id: 65, + name: 'create_date', + text: 'Date Created', + prefix: null, + type_id: 0, + tooltip: 'The date the incident was created. This field is read-only.', + input_type: 'datetimepicker', + hide_notification: false, + chosen: false, + default_chosen_by_server: false, + blank_option: false, + internal: true, + uuid: 'b4faf728-881a-4e8b-bf0b-d39b720392a1', + operations: ['due_within', 'overdue_by', 'has_a_value', 'not_has_a_value'], + operation_perms: { + has_a_value: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + not_has_a_value: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + due_within: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + overdue_by: { + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + }, + }, + values: [], + perms: { + delete: false, + modify_name: false, + modify_values: false, + modify_blank: false, + modify_required: false, + modify_operations: false, + modify_chosen: false, + modify_default: false, + show_in_manual_actions: true, + show_in_auto_actions: true, + show_in_notifications: true, + show_in_scripts: true, + modify_type: ['datetimepicker'], + sort: true, + }, + read_only: true, + changeable: false, + rich_text: false, + templates: [], + deprecated: false, + tags: [], + calculated: false, + is_tracked: false, + allow_default_value: false, + }, +]; + const createMock = (): jest.Mocked => { const service = { + getFields: jest.fn().mockImplementation(() => Promise.resolve(resilientFields)), getIncident: jest.fn().mockImplementation(() => Promise.resolve({ id: '1', diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/schema.ts index b6e3a9525dfd4f..c7ceba94140fb1 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/schema.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/schema.ts @@ -53,11 +53,16 @@ export const ExecutorSubActionGetIncidentParamsSchema = schema.object({ }); // Reserved for future implementation +export const ExecutorSubActionCommonFieldsParamsSchema = schema.object({}); export const ExecutorSubActionHandshakeParamsSchema = schema.object({}); export const ExecutorSubActionGetIncidentTypesParamsSchema = schema.object({}); export const ExecutorSubActionGetSeverityParamsSchema = schema.object({}); export const ExecutorParamsSchema = schema.oneOf([ + schema.object({ + subAction: schema.literal('getFields'), + subActionParams: ExecutorSubActionCommonFieldsParamsSchema, + }), schema.object({ subAction: schema.literal('getIncident'), subActionParams: ExecutorSubActionGetIncidentParamsSchema, diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/service.test.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/service.test.ts index 86ea352625a5b8..ecf246cb8fe3c6 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/service.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/service.test.ts @@ -11,7 +11,7 @@ import * as utils from '../lib/axios_utils'; import { ExternalService } from './types'; import { Logger } from '../../../../../../src/core/server'; import { loggingSystemMock } from '../../../../../../src/core/server/mocks'; -import { incidentTypes, severity } from './mocks'; +import { incidentTypes, resilientFields, severity } from './mocks'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -231,7 +231,7 @@ describe('IBM Resilient service', () => { requestMock.mockImplementation(() => { throw new Error('An error has occurred'); }); - expect(service.getIncident('1')).rejects.toThrow( + await expect(service.getIncident('1')).rejects.toThrow( 'Unable to get incident with id 1. Error: An error has occurred' ); }); @@ -310,7 +310,7 @@ describe('IBM Resilient service', () => { throw new Error('An error has occurred'); }); - expect( + await expect( service.createIncident({ incident: { name: 'title', @@ -418,7 +418,7 @@ describe('IBM Resilient service', () => { test('it should throw an error', async () => { mockIncidentUpdate(true); - expect( + await expect( service.updateIncident({ incidentId: '1', incident: { @@ -502,7 +502,7 @@ describe('IBM Resilient service', () => { throw new Error('An error has occurred'); }); - expect( + await expect( service.createComment({ incidentId: '1', comment: { @@ -541,7 +541,7 @@ describe('IBM Resilient service', () => { throw new Error('An error has occurred'); }); - expect(service.getIncidentTypes()).rejects.toThrow( + await expect(service.getIncidentTypes()).rejects.toThrow( '[Action][IBM Resilient]: Unable to get incident types. Error: An error has occurred.' ); }); @@ -578,9 +578,40 @@ describe('IBM Resilient service', () => { throw new Error('An error has occurred'); }); - expect(service.getIncidentTypes()).rejects.toThrow( + await expect(service.getIncidentTypes()).rejects.toThrow( '[Action][IBM Resilient]: Unable to get incident types. Error: An error has occurred.' ); }); }); + + describe('getFields', () => { + test('it should call request with correct arguments', async () => { + requestMock.mockImplementation(() => ({ + data: resilientFields, + })); + await service.getFields(); + + expect(requestMock).toHaveBeenCalledWith({ + axios, + logger, + url: 'https://resilient.elastic.co/rest/orgs/201/types/incident/fields', + }); + }); + test('it returns common fields correctly', async () => { + requestMock.mockImplementation(() => ({ + data: resilientFields, + })); + const res = await service.getFields(); + expect(res).toEqual(resilientFields); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementation(() => { + throw new Error('An error has occurred'); + }); + await expect(service.getFields()).rejects.toThrow( + 'Unable to get fields. Error: An error has occurred' + ); + }); + }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts index 4bf1453641e426..a13204f8bb1d83 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/service.ts @@ -303,12 +303,27 @@ export const createExternalService = ( } }; + const getFields = async () => { + try { + const res = await request({ + axios: axiosInstance, + url: incidentFieldsUrl, + logger, + proxySettings, + }); + return res.data ?? []; + } catch (error) { + throw new Error(getErrorMessage(i18n.NAME, `Unable to get fields. Error: ${error.message}.`)); + } + }; + return { - getIncident, - createIncident, - updateIncident, createComment, + createIncident, + getFields, + getIncident, getIncidentTypes, getSeverity, + updateIncident, }; }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/resilient/types.ts b/x-pack/plugins/actions/server/builtin_action_types/resilient/types.ts index ed622ee473b659..a70420b30a0926 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/resilient/types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/resilient/types.ts @@ -8,14 +8,15 @@ import { TypeOf } from '@kbn/config-schema'; import { - ExternalIncidentServiceConfigurationSchema, - ExternalIncidentServiceSecretConfigurationSchema, ExecutorParamsSchema, - ExecutorSubActionPushParamsSchema, + ExecutorSubActionCommonFieldsParamsSchema, ExecutorSubActionGetIncidentParamsSchema, - ExecutorSubActionHandshakeParamsSchema, ExecutorSubActionGetIncidentTypesParamsSchema, ExecutorSubActionGetSeverityParamsSchema, + ExecutorSubActionHandshakeParamsSchema, + ExecutorSubActionPushParamsSchema, + ExternalIncidentServiceConfigurationSchema, + ExternalIncidentServiceSecretConfigurationSchema, } from './schema'; import { ActionsConfigurationUtilities } from '../../actions_config'; @@ -31,6 +32,10 @@ export type ResilientSecretConfigurationType = TypeOf< typeof ExternalIncidentServiceSecretConfigurationSchema >; +export type ExecutorSubActionCommonFieldsParams = TypeOf< + typeof ExecutorSubActionCommonFieldsParamsSchema +>; + export type ExecutorParams = TypeOf; export type ExecutorSubActionPushParams = TypeOf; @@ -60,6 +65,14 @@ export interface ExternalServiceCommentResponse { } export type ExternalServiceParams = Record; +export interface ExternalServiceFields { + id: string; + input_type: string; + name: string; + read_only: boolean; + required?: string; +} +export type GetCommonFieldsResponse = ExternalServiceFields[]; export type Incident = Pick< ExecutorSubActionPushParams, @@ -86,12 +99,13 @@ export type GetIncidentTypesResponse = Array<{ id: string; name: string }>; export type GetSeverityResponse = Array<{ id: string; name: string }>; export interface ExternalService { - getIncident: (id: string) => Promise; - createIncident: (params: CreateIncidentParams) => Promise; - updateIncident: (params: UpdateIncidentParams) => Promise; createComment: (params: CreateCommentParams) => Promise; + createIncident: (params: CreateIncidentParams) => Promise; + getFields: () => Promise; + getIncident: (id: string) => Promise; getIncidentTypes: () => Promise; getSeverity: () => Promise; + updateIncident: (params: UpdateIncidentParams) => Promise; } export interface PushToServiceApiParams extends ExecutorSubActionPushParams { @@ -132,6 +146,11 @@ export interface HandshakeApiHandlerArgs extends ExternalServiceApiHandlerArgs { params: ExecutorSubActionHandshakeParams; } +export interface GetCommonFieldsHandlerArgs { + externalService: ExternalService; + params: ExecutorSubActionCommonFieldsParams; +} + export interface GetIncidentTypesHandlerArgs { externalService: ExternalService; params: ExecutorSubActionGetIncidentTypesParams; @@ -147,6 +166,7 @@ export interface PushToServiceResponse extends ExternalServiceIncidentResponse { } export interface ExternalServiceApi { + getFields: (args: GetCommonFieldsHandlerArgs) => Promise; handshake: (args: HandshakeApiHandlerArgs) => Promise; pushToService: (args: PushToServiceApiHandlerArgs) => Promise; getIncident: (args: GetIncidentApiHandlerArgs) => Promise; @@ -156,6 +176,7 @@ export interface ExternalServiceApi { export type ResilientExecutorResultData = | PushToServiceResponse + | GetCommonFieldsResponse | GetIncidentTypesResponse | GetSeverityResponse; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts index d49c2f265d04ff..4683b661e21da6 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts @@ -5,7 +5,7 @@ */ import { Logger } from '../../../../../../src/core/server'; -import { externalServiceMock, mapping, apiParams } from './mocks'; +import { externalServiceMock, mapping, apiParams, serviceNowCommonFields } from './mocks'; import { ExternalService } from './types'; import { api } from './api'; let mockedLogger: jest.Mocked; @@ -15,634 +15,619 @@ describe('api', () => { beforeEach(() => { externalService = externalServiceMock.create(); - jest.clearAllMocks(); }); - afterEach(() => { - jest.clearAllMocks(); - }); + describe('create incident', () => { + test('it creates an incident', async () => { + const params = { ...apiParams, externalId: null }; + const res = await api.pushToService({ + externalService, + mapping, + params, + secrets: {}, + logger: mockedLogger, + }); - describe('pushToService', () => { - describe('create incident', () => { - test('it creates an incident', async () => { - const params = { ...apiParams, externalId: null }; - const res = await api.pushToService({ - externalService, - mapping, - params, - secrets: {}, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-1', - title: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - comments: [ - { - commentId: 'case-comment-1', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - { - commentId: 'case-comment-2', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - ], - }); - }); - - test('it creates an incident without comments', async () => { - const params = { ...apiParams, externalId: null, comments: [] }; - const res = await api.pushToService({ - externalService, - mapping, - params, - secrets: {}, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-1', - title: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('it calls createIncident correctly', async () => { - const params = { ...apiParams, externalId: null, comments: [] }; - await api.pushToService({ - externalService, - mapping, - params, - secrets: { username: 'elastic', password: 'elastic' }, - logger: mockedLogger, - }); - - expect(externalService.createIncident).toHaveBeenCalledWith({ - incident: { - severity: '1', - urgency: '2', - impact: '3', - caller_id: 'elastic', - description: - 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', - short_description: - 'Incident title (created at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - expect(externalService.updateIncident).not.toHaveBeenCalled(); - }); - - test('it calls updateIncident correctly when creating an incident and having comments', async () => { - const params = { ...apiParams, externalId: null }; - await api.pushToService({ - externalService, - mapping, - params, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledTimes(2); - expect(externalService.updateIncident).toHaveBeenNthCalledWith(1, { - incident: { - severity: '1', - urgency: '2', - impact: '3', - comments: 'A comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', - short_description: - 'Incident title (created at 2020-03-13T08:34:53.450Z by Elastic User)', + expect(res).toEqual({ + id: 'incident-1', + title: 'INC01', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + comments: [ + { + commentId: 'case-comment-1', + pushedDate: '2020-03-10T12:24:20.000Z', }, - incidentId: 'incident-1', - }); - - expect(externalService.updateIncident).toHaveBeenNthCalledWith(2, { - incident: { - severity: '1', - urgency: '2', - impact: '3', - comments: 'Another comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', - short_description: - 'Incident title (created at 2020-03-13T08:34:53.450Z by Elastic User)', + { + commentId: 'case-comment-2', + pushedDate: '2020-03-10T12:24:20.000Z', }, - incidentId: 'incident-1', - }); + ], }); }); - describe('update incident', () => { - test('it updates an incident', async () => { - const res = await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-2', - title: 'INC02', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - comments: [ - { - commentId: 'case-comment-1', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - { - commentId: 'case-comment-2', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - ], - }); - }); - - test('it updates an incident without comments', async () => { - const params = { ...apiParams, comments: [] }; - const res = await api.pushToService({ - externalService, - mapping, - params, - secrets: {}, - logger: mockedLogger, - }); - - expect(res).toEqual({ - id: 'incident-2', - title: 'INC02', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('it calls updateIncident correctly', async () => { - const params = { ...apiParams }; - await api.pushToService({ - externalService, - mapping, - params, - secrets: {}, - logger: mockedLogger, - }); - - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - description: - 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - short_description: - 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - expect(externalService.createIncident).not.toHaveBeenCalled(); - }); - - test('it calls updateIncident to create a comments correctly', async () => { - const params = { ...apiParams }; - await api.pushToService({ - externalService, - mapping, - params, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledTimes(3); - expect(externalService.updateIncident).toHaveBeenNthCalledWith(1, { - incident: { - severity: '1', - urgency: '2', - impact: '3', - description: - 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - short_description: - 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - incidentId: 'incident-3', - }); - - expect(externalService.updateIncident).toHaveBeenNthCalledWith(2, { - incident: { - severity: '1', - urgency: '2', - impact: '3', - comments: 'A comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - short_description: - 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - incidentId: 'incident-2', - }); + test('it creates an incident without comments', async () => { + const params = { ...apiParams, externalId: null, comments: [] }; + const res = await api.pushToService({ + externalService, + mapping, + params, + secrets: {}, + logger: mockedLogger, + }); + + expect(res).toEqual({ + id: 'incident-1', + title: 'INC01', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', }); }); - describe('mapping variations', () => { - test('overwrite & append', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'append', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - short_description: - 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - }); - - test('nothing & append', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'nothing', - }); - - mapping.set('description', { - target: 'description', - actionType: 'append', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'nothing', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - description: - 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - }); - - test('append & append', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'append', - }); - - mapping.set('description', { - target: 'description', - actionType: 'append', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'append', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - short_description: - 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - }); - - test('nothing & nothing', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'nothing', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'nothing', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - }, - }); - }); - - test('overwrite & nothing', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - short_description: - 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - }); - - test('overwrite & overwrite', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - short_description: - 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - }); - - test('nothing & overwrite', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'nothing', - }); - - mapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'nothing', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - description: - 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }, - }); - }); - - test('append & overwrite', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'append', - }); - - mapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'append', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - short_description: - 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + test('it calls createIncident correctly', async () => { + const params = { ...apiParams, externalId: null, comments: [] }; + await api.pushToService({ + externalService, + mapping, + params, + secrets: { username: 'elastic', password: 'elastic' }, + logger: mockedLogger, + }); + + expect(externalService.createIncident).toHaveBeenCalledWith({ + incident: { + severity: '1', + urgency: '2', + impact: '3', + caller_id: 'elastic', + description: 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: 'Incident title (created at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + expect(externalService.updateIncident).not.toHaveBeenCalled(); + }); + + test('it calls updateIncident correctly when creating an incident and having comments', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ + externalService, + mapping, + params, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledTimes(2); + expect(externalService.updateIncident).toHaveBeenNthCalledWith(1, { + incident: { + severity: '1', + urgency: '2', + impact: '3', + comments: 'A comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', + description: 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: 'Incident title (created at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + incidentId: 'incident-1', + }); + + expect(externalService.updateIncident).toHaveBeenNthCalledWith(2, { + incident: { + severity: '1', + urgency: '2', + impact: '3', + comments: 'Another comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', + description: 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: 'Incident title (created at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + incidentId: 'incident-1', + }); + }); + }); + + describe('update incident', () => { + test('it updates an incident', async () => { + const res = await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + + expect(res).toEqual({ + id: 'incident-2', + title: 'INC02', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + comments: [ + { + commentId: 'case-comment-1', + pushedDate: '2020-03-10T12:24:20.000Z', }, - }); - }); - - test('append & nothing', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'append', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'append', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledWith({ - incidentId: 'incident-3', - incident: { - severity: '1', - urgency: '2', - impact: '3', - short_description: - 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + { + commentId: 'case-comment-2', + pushedDate: '2020-03-10T12:24:20.000Z', }, - }); - }); - - test('comment nothing', async () => { - mapping.set('title', { - target: 'short_description', - actionType: 'overwrite', - }); - - mapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - mapping.set('comments', { - target: 'comments', - actionType: 'nothing', - }); - - mapping.set('short_description', { - target: 'title', - actionType: 'overwrite', - }); - - await api.pushToService({ - externalService, - mapping, - params: apiParams, - secrets: {}, - logger: mockedLogger, - }); - expect(externalService.updateIncident).toHaveBeenCalledTimes(1); + ], + }); + }); + + test('it updates an incident without comments', async () => { + const params = { ...apiParams, comments: [] }; + const res = await api.pushToService({ + externalService, + mapping, + params, + secrets: {}, + logger: mockedLogger, + }); + + expect(res).toEqual({ + id: 'incident-2', + title: 'INC02', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + }); + }); + + test('it calls updateIncident correctly', async () => { + const params = { ...apiParams }; + await api.pushToService({ + externalService, + mapping, + params, + secrets: {}, + logger: mockedLogger, + }); + + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + description: 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + expect(externalService.createIncident).not.toHaveBeenCalled(); + }); + + test('it calls updateIncident to create a comments correctly', async () => { + const params = { ...apiParams }; + await api.pushToService({ + externalService, + mapping, + params, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledTimes(3); + expect(externalService.updateIncident).toHaveBeenNthCalledWith(1, { + incident: { + severity: '1', + urgency: '2', + impact: '3', + description: 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + incidentId: 'incident-3', + }); + + expect(externalService.updateIncident).toHaveBeenNthCalledWith(2, { + incident: { + severity: '1', + urgency: '2', + impact: '3', + comments: 'A comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', + description: 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + incidentId: 'incident-2', + }); + }); + }); + + describe('mapping variations', () => { + test('overwrite & append', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + short_description: 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + description: + 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('nothing & append', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + description: + 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('append & append', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + short_description: + 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + description: + 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('nothing & nothing', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + }, + }); + }); + + test('overwrite & nothing', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + short_description: 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('overwrite & overwrite', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + short_description: 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + description: 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('nothing & overwrite', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + description: 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('append & overwrite', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + short_description: + 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + description: 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('append & nothing', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + severity: '1', + urgency: '2', + impact: '3', + short_description: + 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('comment nothing', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'nothing', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ + externalService, + mapping, + params: apiParams, + secrets: {}, + logger: mockedLogger, + }); + expect(externalService.updateIncident).toHaveBeenCalledTimes(1); + }); + }); + + describe('getFields', () => { + test('it returns the fields correctly', async () => { + const res = await api.getFields({ + externalService, + params: {}, }); + expect(res).toEqual(serviceNowCommonFields); }); }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts index 6d12a3c92dac70..fbd8fdd635d703 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts @@ -12,6 +12,8 @@ import { PushToServiceApiParams, PushToServiceResponse, Incident, + GetCommonFieldsHandlerArgs, + GetCommonFieldsResponse, } from './types'; // TODO: to remove, need to support Case @@ -127,8 +129,16 @@ const pushToServiceHandler = async ({ return res; }; +const getFieldsHandler = async ({ + externalService, +}: GetCommonFieldsHandlerArgs): Promise => { + const res = await externalService.getFields(); + return res; +}; + export const api: ExternalServiceApi = { + getFields: getFieldsHandler, + getIncident: getIncidentHandler, handshake: handshakeHandler, pushToService: pushToServiceHandler, - getIncident: getIncidentHandler, }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts index 41a577918b18ee..d1182b0d3b2fae 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts @@ -25,6 +25,8 @@ import { ServiceNowPublicConfigurationType, ServiceNowSecretConfigurationType, PushToServiceResponse, + ExecutorSubActionCommonFieldsParams, + ServiceNowExecutorResultData, } from './types'; // TODO: to remove, need to support Case @@ -63,7 +65,7 @@ export function getActionType( } // action executor - +const supportedSubActions: string[] = ['getFields', 'pushToService']; async function executor( { logger }: { logger: Logger }, execOptions: ActionTypeExecutorOptions< @@ -71,10 +73,10 @@ async function executor( ServiceNowSecretConfigurationType, ExecutorParams > -): Promise> { +): Promise> { const { actionId, config, params, secrets } = execOptions; const { subAction, subActionParams } = params; - let data: PushToServiceResponse | null = null; + let data: ServiceNowExecutorResultData | null = null; const externalService = createExternalService( { @@ -91,7 +93,7 @@ async function executor( throw new Error(errorMessage); } - if (subAction !== 'pushToService') { + if (!supportedSubActions.includes(subAction)) { const errorMessage = `[Action][ExternalService] subAction ${subAction} not implemented.`; logger.error(errorMessage); throw new Error(errorMessage); @@ -117,5 +119,13 @@ async function executor( logger.debug(`response push to service for incident id: ${data.id}`); } + if (subAction === 'getFields') { + const getFieldsParams = subActionParams as ExecutorSubActionCommonFieldsParams; + data = await api.getFields({ + externalService, + params: getFieldsParams, + }); + } + return { status: 'ok', data: data ?? {}, actionId }; } diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts index 7c2b1bd9d73c1e..2351be36a50c4e 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts @@ -7,8 +7,36 @@ import { ExternalService, PushToServiceApiParams, ExecutorSubActionPushParams } from './types'; import { MapRecord } from '../case/types'; +export const serviceNowCommonFields = [ + { + column_label: 'Close notes', + max_length: '4000', + element: 'close_notes', + }, + { + column_label: 'Description', + max_length: '4000', + element: 'description', + }, + { + column_label: 'Short description', + max_length: '160', + element: 'short_description', + }, + { + column_label: 'Created by', + max_length: '40', + element: 'sys_created_by', + }, + { + column_label: 'Updated by', + max_length: '40', + element: 'sys_updated_by', + }, +]; const createMock = (): jest.Mocked => { const service = { + getFields: jest.fn().mockImplementation(() => Promise.resolve(serviceNowCommonFields)), getIncident: jest.fn().mockImplementation(() => Promise.resolve({ short_description: 'title from servicenow', diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts index 0dd70ea36636e7..77c48aab1f3094 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts @@ -28,6 +28,7 @@ export const ExternalIncidentServiceSecretConfigurationSchema = schema.object( ); export const ExecutorSubActionSchema = schema.oneOf([ + schema.literal('getFields'), schema.literal('getIncident'), schema.literal('pushToService'), schema.literal('handshake'), @@ -53,8 +54,13 @@ export const ExecutorSubActionGetIncidentParamsSchema = schema.object({ // Reserved for future implementation export const ExecutorSubActionHandshakeParamsSchema = schema.object({}); +export const ExecutorSubActionCommonFieldsParamsSchema = schema.object({}); export const ExecutorParamsSchema = schema.oneOf([ + schema.object({ + subAction: schema.literal('getFields'), + subActionParams: ExecutorSubActionCommonFieldsParamsSchema, + }), schema.object({ subAction: schema.literal('getIncident'), subActionParams: ExecutorSubActionGetIncidentParamsSchema, diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts index 2adcdf561ce175..8ec80be1e2b094 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts @@ -11,6 +11,7 @@ import * as utils from '../lib/axios_utils'; import { ExternalService } from './types'; import { Logger } from '../../../../../../src/core/server'; import { loggingSystemMock } from '../../../../../../src/core/server/mocks'; +import { serviceNowCommonFields } from './mocks'; const logger = loggingSystemMock.create().get() as jest.Mocked; jest.mock('axios'); @@ -108,7 +109,7 @@ describe('ServiceNow service', () => { requestMock.mockImplementation(() => { throw new Error('An error has occurred'); }); - expect(service.getIncident('1')).rejects.toThrow( + await expect(service.getIncident('1')).rejects.toThrow( 'Unable to get incident with id 1. Error: An error has occurred' ); }); @@ -155,7 +156,7 @@ describe('ServiceNow service', () => { throw new Error('An error has occurred'); }); - expect( + await expect( service.createIncident({ incident: { short_description: 'title', description: 'desc' }, }) @@ -207,7 +208,7 @@ describe('ServiceNow service', () => { throw new Error('An error has occurred'); }); - expect( + await expect( service.updateIncident({ incidentId: '1', incident: { short_description: 'title', description: 'desc' }, @@ -234,4 +235,36 @@ describe('ServiceNow service', () => { }); }); }); + + describe('getFields', () => { + test('it should call request with correct arguments', async () => { + requestMock.mockImplementation(() => ({ + data: { result: serviceNowCommonFields }, + })); + await service.getFields(); + + expect(requestMock).toHaveBeenCalledWith({ + axios, + logger, + url: + 'https://dev102283.service-now.com/api/now/v2/table/sys_dictionary?sysparm_query=name=task^internal_type=string&active=true&read_only=false&sysparm_fields=max_length,element,column_label', + }); + }); + test('it returns common fields correctly', async () => { + requestMock.mockImplementation(() => ({ + data: { result: serviceNowCommonFields }, + })); + const res = await service.getFields(); + expect(res).toEqual(serviceNowCommonFields); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementation(() => { + throw new Error('An error has occurred'); + }); + await expect(service.getFields()).rejects.toThrow( + 'Unable to get common fields. Error: An error has occurred' + ); + }); + }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts index 9b1da4b4007c66..57f7176e2353c8 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts @@ -16,6 +16,7 @@ import { ProxySettings } from '../../types'; const API_VERSION = 'v2'; const INCIDENT_URL = `api/now/${API_VERSION}/table/incident`; +const SYS_DICTIONARY = `api/now/${API_VERSION}/table/sys_dictionary`; // Based on: https://docs.servicenow.com/bundle/orlando-platform-user-interface/page/use/navigation/reference/r_NavigatingByURLExamples.html const VIEW_INCIDENT_URL = `nav_to.do?uri=incident.do?sys_id=`; @@ -33,6 +34,7 @@ export const createExternalService = ( } const incidentUrl = `${url}/${INCIDENT_URL}`; + const fieldsUrl = `${url}/${SYS_DICTIONARY}?sysparm_query=name=task^internal_type=string&active=true&read_only=false&sysparm_fields=max_length,element,column_label`; const axiosInstance = axios.create({ auth: { username, password }, }); @@ -126,10 +128,28 @@ export const createExternalService = ( } }; + const getFields = async () => { + try { + const res = await request({ + axios: axiosInstance, + url: fieldsUrl, + logger, + proxySettings, + }); + + return res.data.result.length > 0 ? res.data.result : []; + } catch (error) { + throw new Error( + getErrorMessage(i18n.NAME, `Unable to get common fields. Error: ${error.message}`) + ); + } + }; + return { - getIncident, createIncident, - updateIncident, findIncidents, + getFields, + getIncident, + updateIncident, }; }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts index a6a0ac946fe96a..0ee03f883ec05b 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts @@ -8,12 +8,13 @@ import { TypeOf } from '@kbn/config-schema'; import { - ExternalIncidentServiceConfigurationSchema, - ExternalIncidentServiceSecretConfigurationSchema, ExecutorParamsSchema, - ExecutorSubActionPushParamsSchema, + ExecutorSubActionCommonFieldsParamsSchema, ExecutorSubActionGetIncidentParamsSchema, ExecutorSubActionHandshakeParamsSchema, + ExecutorSubActionPushParamsSchema, + ExternalIncidentServiceConfigurationSchema, + ExternalIncidentServiceSecretConfigurationSchema, } from './schema'; import { ActionsConfigurationUtilities } from '../../actions_config'; import { ExternalServiceCommentResponse } from '../case/types'; @@ -27,6 +28,12 @@ export type ServiceNowSecretConfigurationType = TypeOf< typeof ExternalIncidentServiceSecretConfigurationSchema >; +export type ExecutorSubActionCommonFieldsParams = TypeOf< + typeof ExecutorSubActionCommonFieldsParamsSchema +>; + +export type ServiceNowExecutorResultData = PushToServiceResponse | GetCommonFieldsResponse; + export interface CreateCommentRequest { [key: string]: string; } @@ -59,6 +66,7 @@ export interface PushToServiceResponse extends ExternalServiceIncidentResponse { export type ExternalServiceParams = Record; export interface ExternalService { + getFields: () => Promise; getIncident: (id: string) => Promise; createIncident: (params: ExternalServiceParams) => Promise; updateIncident: (params: ExternalServiceParams) => Promise; @@ -102,8 +110,24 @@ export interface GetIncidentApiHandlerArgs extends ExternalServiceApiHandlerArgs export interface HandshakeApiHandlerArgs extends ExternalServiceApiHandlerArgs { params: ExecutorSubActionHandshakeParams; } +export interface ExternalServiceFields { + column_label: string; + name: string; + internal_type: { + link: string; + value: string; + }; + max_length: string; + element: string; +} +export type GetCommonFieldsResponse = ExternalServiceFields[]; +export interface GetCommonFieldsHandlerArgs { + externalService: ExternalService; + params: ExecutorSubActionCommonFieldsParams; +} export interface ExternalServiceApi { + getFields: (args: GetCommonFieldsHandlerArgs) => Promise; handshake: (args: HandshakeApiHandlerArgs) => Promise; pushToService: (args: PushToServiceApiHandlerArgs) => Promise; getIncident: (args: GetIncidentApiHandlerArgs) => Promise; diff --git a/x-pack/plugins/canvas/types/state.ts b/x-pack/plugins/canvas/types/state.ts index 60407b78ab5e33..03bb931dc9b261 100644 --- a/x-pack/plugins/canvas/types/state.ts +++ b/x-pack/plugins/canvas/types/state.ts @@ -4,12 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ +import { KibanaContext } from 'src/plugins/data/common'; import { Datatable, ExpressionValueFilter, ExpressionImage, ExpressionFunction, - KibanaContext, PointSeries, Render, Style, diff --git a/x-pack/plugins/data_enhanced/common/search/es_search/es_search_rxjs_utils.ts b/x-pack/plugins/data_enhanced/common/search/es_search/es_search_rxjs_utils.ts index 2d5d09fd0205e3..f38bec6d1f59f6 100644 --- a/x-pack/plugins/data_enhanced/common/search/es_search/es_search_rxjs_utils.ts +++ b/x-pack/plugins/data_enhanced/common/search/es_search/es_search_rxjs_utils.ts @@ -8,11 +8,11 @@ import { of, merge, timer, throwError } from 'rxjs'; import { takeWhile, switchMap, expand, mergeMap, tap } from 'rxjs/operators'; import { - AbortError, doSearch, IKibanaSearchResponse, isErrorResponse, } from '../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../src/plugins/kibana_utils/common'; import type { IKibanaSearchRequest } from '../../../../../../src/plugins/data/common'; import type { IAsyncSearchOptions } from '../../../common/search/types'; diff --git a/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts b/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts index f47d2b39a89a98..044489d58eb0e4 100644 --- a/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts +++ b/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts @@ -7,7 +7,8 @@ import type { MockedKeys } from '@kbn/utility-types/jest'; import { coreMock } from '../../../../../src/core/public/mocks'; import { EnhancedSearchInterceptor } from './search_interceptor'; import { CoreSetup, CoreStart } from 'kibana/public'; -import { AbortError, UI_SETTINGS } from '../../../../../src/plugins/data/common'; +import { UI_SETTINGS } from '../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../src/plugins/kibana_utils/public'; import { SearchTimeoutError } from 'src/plugins/data/public'; import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; diff --git a/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts b/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts index 4cafcdb29ae8dc..d36741ae6576d0 100644 --- a/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts +++ b/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts @@ -13,7 +13,7 @@ import { SearchInterceptorDeps, UI_SETTINGS, } from '../../../../../src/plugins/data/public'; -import { AbortError, toPromise } from '../../../../../src/plugins/data/common'; +import { AbortError, abortSignalToPromise } from '../../../../../src/plugins/kibana_utils/public'; import { IAsyncSearchRequest, @@ -70,7 +70,7 @@ export class EnhancedSearchInterceptor extends SearchInterceptor { abortSignal: options.abortSignal, timeout: this.searchTimeout, }); - const abortedPromise = toPromise(combinedSignal); + const abortedPromise = abortSignalToPromise(combinedSignal); const strategy = options?.strategy ?? ENHANCED_ES_SEARCH_STRATEGY; this.pendingCount$.next(this.pendingCount$.getValue() + 1); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts index decf1e2158744a..ea4906ec08946b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/constants.ts @@ -3,8 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + import { i18n } from '@kbn/i18n'; +export const CREDENTIALS_TITLE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.credentials.title', + { defaultMessage: 'Credentials' } +); + export enum ApiTokenTypes { Admin = 'admin', Private = 'private', diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.tsx index c8eae8cc13f5ff..72b02dfdc1f61b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/credentials.tsx @@ -28,6 +28,7 @@ import { FlashMessages } from '../../../shared/flash_messages'; import { CredentialsLogic } from './credentials_logic'; import { externalUrl } from '../../../shared/enterprise_search_url/external_url'; +import { CREDENTIALS_TITLE } from './constants'; import { CredentialsList } from './credentials_list'; import { CredentialsFlyout } from './credentials_flyout'; @@ -47,21 +48,11 @@ export const Credentials: React.FC = () => { return ( <> - + -

- {i18n.translate('xpack.enterpriseSearch.appSearch.credentials.title', { - defaultMessage: 'Credentials', - })} -

+

{CREDENTIALS_TITLE}

diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/index.ts index bceda234175a79..0fc64a43ffa851 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/credentials/index.ts @@ -5,3 +5,4 @@ */ export { Credentials } from './credentials'; +export { CREDENTIALS_TITLE } from './constants'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts index ee5b47eda490e6..3c963e415f33b7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/constants.ts @@ -9,10 +9,6 @@ import { i18n } from '@kbn/i18n'; // TODO: It's very likely that we'll move these i18n constants to their respective component // folders once those are migrated over. This is a temporary way of DRYing them out for now. -export const ENGINES_TITLE = i18n.translate('xpack.enterpriseSearch.appSearch.engines.title', { - defaultMessage: 'Engines', -}); - export const OVERVIEW_TITLE = i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.overview.title', { defaultMessage: 'Overview' } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx index e5ee392b34c01c..f92fefc7124b83 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine/engine_nav.tsx @@ -30,8 +30,8 @@ import { ENGINE_API_LOGS_PATH, } from '../../routes'; import { getAppSearchUrl } from '../../../shared/enterprise_search_url'; +import { ENGINES_TITLE } from '../engines'; import { - ENGINES_TITLE, OVERVIEW_TITLE, ANALYTICS_TITLE, DOCUMENTS_TITLE, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/assets/engine_icon.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/engine_icon.tsx similarity index 100% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/assets/engine_icon.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/engine_icon.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/assets/meta_engine_icon.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/meta_engine_icon.tsx similarity index 100% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/assets/meta_engine_icon.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/assets/meta_engine_icon.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.scss b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.scss similarity index 100% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.scss rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.scss diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.test.tsx similarity index 100% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.test.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.test.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.tsx similarity index 96% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.tsx index b7ed1cc895097c..95142782d2272b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/empty_state.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/empty_state.tsx @@ -14,7 +14,7 @@ import { getAppSearchUrl } from '../../../../shared/enterprise_search_url'; import { SetAppSearchChrome as SetPageChrome } from '../../../../shared/kibana_chrome'; import { CREATE_ENGINES_PATH } from '../../../routes'; -import { EngineOverviewHeader } from './header'; +import { EnginesOverviewHeader } from './header'; import './empty_state.scss'; @@ -34,7 +34,7 @@ export const EmptyState: React.FC = () => { return ( <> - + { +describe('EnginesOverviewHeader', () => { it('renders', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper.find('h1')).toHaveLength(1); }); it('renders a launch app search button that sends telemetry on click', () => { - const wrapper = shallow(); + const wrapper = shallow(); const button = wrapper.find('[data-test-subj="launchButton"]'); expect(button.prop('href')).toBe('http://localhost:3002/as'); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/header.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.tsx similarity index 93% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/header.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.tsx index 4bb69bafa09960..3faa74be11e984 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/header.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/header.tsx @@ -19,7 +19,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { TelemetryLogic } from '../../../../shared/telemetry'; import { getAppSearchUrl } from '../../../../shared/enterprise_search_url'; -export const EngineOverviewHeader: React.FC = () => { +export const EnginesOverviewHeader: React.FC = () => { const { sendAppSearchTelemetry } = useActions(TelemetryLogic); const buttonProps = { @@ -42,7 +42,7 @@ export const EngineOverviewHeader: React.FC = () => {

diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/index.ts similarity index 87% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/index.ts rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/index.ts index 794053f184f8c6..cb2e0f825d455f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/index.ts @@ -4,6 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -export { EngineOverviewHeader } from './header'; +export { EnginesOverviewHeader } from './header'; export { LoadingState } from './loading_state'; export { EmptyState } from './empty_state'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.test.tsx similarity index 100% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.test.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.test.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.tsx similarity index 89% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.tsx index 832a133ed43c70..8e2166d2ef105c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/components/loading_state.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/components/loading_state.tsx @@ -8,13 +8,13 @@ import React from 'react'; import { EuiPageContent, EuiSpacer, EuiLoadingContent } from '@elastic/eui'; import { SetAppSearchChrome as SetPageChrome } from '../../../../shared/kibana_chrome'; -import { EngineOverviewHeader } from './header'; +import { EnginesOverviewHeader } from './header'; export const LoadingState: React.FC = () => { return ( <> - + diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts new file mode 100644 index 00000000000000..12545c59b40a02 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const ENGINES_TITLE = i18n.translate('xpack.enterpriseSearch.appSearch.engines.title', { + defaultMessage: 'Engines', +}); + +export const META_ENGINES_TITLE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngines.title', + { defaultMessage: 'Meta Engines' } +); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.scss b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.scss similarity index 96% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.scss rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.scss index 5e8a20ba425add..c956f3da562f65 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.scss +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.scss @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -.engineOverview { +.enginesOverview { padding: $euiSize; @include euiBreakpoint('m', 'l', 'xl') { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx similarity index 80% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx index f87ea2d4227803..61f783a8b6c2eb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx @@ -14,14 +14,14 @@ import { shallow, ReactWrapper } from 'enzyme'; import { mountAsync, mockHttpValues, setMockValues } from '../../../__mocks__'; import { LoadingState, EmptyState } from './components'; -import { EngineTable } from './engine_table'; +import { EnginesTable } from './engines_table'; -import { EngineOverview } from './'; +import { EnginesOverview } from './'; -describe('EngineOverview', () => { +describe('EnginesOverview', () => { describe('non-happy-path states', () => { it('isLoading', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper.find(LoadingState)).toHaveLength(1); }); @@ -36,7 +36,7 @@ describe('EngineOverview', () => { }), }, }); - const wrapper = await mountAsync(, { i18n: true }); + const wrapper = await mountAsync(, { i18n: true }); expect(wrapper.find(EmptyState)).toHaveLength(1); }); @@ -69,9 +69,9 @@ describe('EngineOverview', () => { }); it('renders and calls the engines API', async () => { - const wrapper = await mountAsync(, { i18n: true }); + const wrapper = await mountAsync(, { i18n: true }); - expect(wrapper.find(EngineTable)).toHaveLength(1); + expect(wrapper.find(EnginesTable)).toHaveLength(1); expect(mockApi).toHaveBeenNthCalledWith(1, '/api/app_search/engines', { query: { type: 'indexed', @@ -86,9 +86,9 @@ describe('EngineOverview', () => { hasPlatinumLicense: true, http: { ...mockHttpValues.http, get: mockApi }, }); - const wrapper = await mountAsync(, { i18n: true }); + const wrapper = await mountAsync(, { i18n: true }); - expect(wrapper.find(EngineTable)).toHaveLength(2); + expect(wrapper.find(EnginesTable)).toHaveLength(2); expect(mockApi).toHaveBeenNthCalledWith(2, '/api/app_search/engines', { query: { type: 'meta', @@ -100,10 +100,10 @@ describe('EngineOverview', () => { describe('pagination', () => { const getTablePagination = (wrapper: ReactWrapper) => - wrapper.find(EngineTable).prop('pagination'); + wrapper.find(EnginesTable).prop('pagination'); it('passes down page data from the API', async () => { - const wrapper = await mountAsync(, { i18n: true }); + const wrapper = await mountAsync(, { i18n: true }); const pagination = getTablePagination(wrapper); expect(pagination.totalEngines).toEqual(100); @@ -111,7 +111,7 @@ describe('EngineOverview', () => { }); it('re-polls the API on page change', async () => { - const wrapper = await mountAsync(, { i18n: true }); + const wrapper = await mountAsync(, { i18n: true }); await act(async () => getTablePagination(wrapper).onPaginate(5)); wrapper.update(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx similarity index 83% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx index c0fd2545679107..559fef695d63b5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx @@ -13,7 +13,6 @@ import { EuiTitle, EuiSpacer, } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { SendAppSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; @@ -23,11 +22,11 @@ import { LicensingLogic } from '../../../shared/licensing'; import { EngineIcon } from './assets/engine_icon'; import { MetaEngineIcon } from './assets/meta_engine_icon'; +import { ENGINES_TITLE, META_ENGINES_TITLE } from './constants'; +import { EnginesOverviewHeader, LoadingState, EmptyState } from './components'; +import { EnginesTable } from './engines_table'; -import { EngineOverviewHeader, LoadingState, EmptyState } from './components'; -import { EngineTable } from './engine_table'; - -import './engine_overview.scss'; +import './engines_overview.scss'; interface IGetEnginesParams { type: string; @@ -38,7 +37,7 @@ interface ISetEnginesCallbacks { setResultsTotal: React.Dispatch>; } -export const EngineOverview: React.FC = () => { +export const EnginesOverview: React.FC = () => { const { http } = useValues(HttpLogic); const { hasPlatinumLicense } = useValues(LicensingLogic); @@ -88,21 +87,18 @@ export const EngineOverview: React.FC = () => { - - + +

- - {i18n.translate('xpack.enterpriseSearch.appSearch.enginesOverview.engines', { - defaultMessage: 'Engines', - })} + {ENGINES_TITLE}

- {

- - {i18n.translate('xpack.enterpriseSearch.appSearch.enginesOverview.metaEngines', { - defaultMessage: 'Meta Engines', - })} + {META_ENGINES_TITLE}

- { +describe('EnginesTable', () => { const onPaginate = jest.fn(); // onPaginate updates the engines API call upstream const wrapper = mountWithIntl( - { it('handles empty data', () => { const emptyWrapper = mountWithIntl( - {} }} /> + {} }} + /> ); const emptyTable = emptyWrapper.find(EuiBasicTable); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx similarity index 92% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_table.tsx rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx index abeaf45e6aee8a..a9cf64b3dffda3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/engine_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx @@ -16,28 +16,28 @@ import { getEngineRoute } from '../../routes'; import { ENGINES_PAGE_SIZE } from '../../../../../common/constants'; -export interface IEngineTableData { +interface IEnginesTableData { name: string; created_at: string; document_count: number; field_count: number; } -export interface IEngineTablePagination { +interface IEnginesTablePagination { totalEngines: number; pageIndex: number; onPaginate(pageIndex: number): void; } -export interface IEngineTableProps { - data: IEngineTableData[]; - pagination: IEngineTablePagination; +interface IEnginesTableProps { + data: IEnginesTableData[]; + pagination: IEnginesTablePagination; } -export interface IOnChange { +interface IOnChange { page: { index: number; }; } -export const EngineTable: React.FC = ({ +export const EnginesTable: React.FC = ({ data, pagination: { totalEngines, pageIndex, onPaginate }, }) => { @@ -52,7 +52,7 @@ export const EngineTable: React.FC = ({ }), }); - const columns: Array> = [ + const columns: Array> = [ { field: 'name', name: i18n.translate('xpack.enterpriseSearch.appSearch.enginesOverview.table.column.name', { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/index.ts similarity index 67% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/index.ts rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/index.ts index 48b7645dc39e8b..76ca9239a3c7e1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_overview/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/index.ts @@ -4,4 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { EngineOverview } from './engine_overview'; +export { EnginesOverview } from './engines_overview'; +export { ENGINES_TITLE, META_ENGINES_TITLE } from './constants'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/constants.ts new file mode 100644 index 00000000000000..133d8b604381b3 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/constants.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const ROLE_MAPPINGS_TITLE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.roleMappings.title', + { defaultMessage: 'Role Mappings' } +); diff --git a/x-pack/plugins/rollup/server/lib/__tests__/fixtures/index.js b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/index.ts similarity index 82% rename from x-pack/plugins/rollup/server/lib/__tests__/fixtures/index.js rename to x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/index.ts index e97606c1fadfba..662b91bb3e9254 100644 --- a/x-pack/plugins/rollup/server/lib/__tests__/fixtures/index.js +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { jobs } from './jobs'; +export { ROLE_MAPPINGS_TITLE } from './constants'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/constants.ts new file mode 100644 index 00000000000000..c7b22d740341c5 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/constants.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const SETTINGS_TITLE = i18n.translate('xpack.enterpriseSearch.appSearch.settings.title', { + defaultMessage: 'Settings', +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/index.ts index db74dcb1a1846e..3e162a4a2a1bce 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/index.ts @@ -5,3 +5,4 @@ */ export { Settings } from './settings'; +export { SETTINGS_TITLE } from './constants'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx index e5e86f3e39734a..13079bb380f135 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/settings.tsx @@ -6,30 +6,21 @@ import React from 'react'; -import { i18n } from '@kbn/i18n'; import { EuiPageHeader, EuiPageHeaderSection, EuiPageContentBody, EuiTitle } from '@elastic/eui'; import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { FlashMessages } from '../../../shared/flash_messages'; +import { SETTINGS_TITLE } from './'; + export const Settings: React.FC = () => { return ( <> - + -

- {i18n.translate('xpack.enterpriseSearch.appSearch.settings.title', { - defaultMessage: 'Settings', - })} -

+

{SETTINGS_TITLE}

diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx index 700b903efe59b4..11387734e9f9e3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx @@ -16,7 +16,7 @@ import { shallow } from 'enzyme'; import { Layout, SideNav, SideNavLink } from '../shared/layout'; import { SetupGuide } from './components/setup_guide'; import { ErrorConnecting } from './components/error_connecting'; -import { EngineOverview } from './components/engine_overview'; +import { EnginesOverview } from './components/engines'; import { EngineRouter } from './components/engine'; import { AppSearch, AppSearchUnconfigured, AppSearchConfigured, AppSearchNav } from './'; @@ -57,7 +57,7 @@ describe('AppSearchConfigured', () => { expect(wrapper.find(Layout)).toHaveLength(2); expect(wrapper.find(Layout).last().prop('readOnlyMode')).toBeFalsy(); - expect(wrapper.find(EngineOverview)).toHaveLength(1); + expect(wrapper.find(EnginesOverview)).toHaveLength(1); expect(wrapper.find(EngineRouter)).toHaveLength(1); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx index f32b0b256b8986..4571ef10286e49 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx @@ -8,8 +8,6 @@ import React, { useEffect } from 'react'; import { Route, Redirect, Switch } from 'react-router-dom'; import { useActions, useValues } from 'kea'; -import { i18n } from '@kbn/i18n'; - import { getAppSearchUrl } from '../shared/enterprise_search_url'; import { KibanaLogic } from '../shared/kibana'; import { HttpLogic } from '../shared/http'; @@ -33,9 +31,10 @@ import { import { SetupGuide } from './components/setup_guide'; import { ErrorConnecting } from './components/error_connecting'; import { NotFound } from '../shared/not_found'; -import { EngineOverview } from './components/engine_overview'; -import { Settings } from './components/settings'; -import { Credentials } from './components/credentials'; +import { EnginesOverview, ENGINES_TITLE } from './components/engines'; +import { Settings, SETTINGS_TITLE } from './components/settings'; +import { Credentials, CREDENTIALS_TITLE } from './components/credentials'; +import { ROLE_MAPPINGS_TITLE } from './components/role_mappings'; export const AppSearch: React.FC = (props) => { const { config } = useValues(KibanaLogic); @@ -82,7 +81,7 @@ export const AppSearchConfigured: React.FC = (props) => { - + @@ -113,29 +112,15 @@ export const AppSearchNav: React.FC = ({ subNav }) => { return ( - {i18n.translate('xpack.enterpriseSearch.appSearch.nav.engines', { - defaultMessage: 'Engines', - })} + {ENGINES_TITLE} - {canViewSettings && ( - - {i18n.translate('xpack.enterpriseSearch.appSearch.nav.settings', { - defaultMessage: 'Settings', - })} - - )} + {canViewSettings && {SETTINGS_TITLE}} {canViewAccountCredentials && ( - - {i18n.translate('xpack.enterpriseSearch.appSearch.nav.credentials', { - defaultMessage: 'Credentials', - })} - + {CREDENTIALS_TITLE} )} {canViewRoleMappings && ( - {i18n.translate('xpack.enterpriseSearch.appSearch.nav.roleMappings', { - defaultMessage: 'Role Mappings', - })} + {ROLE_MAPPINGS_TITLE} )} diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/app/app.helpers.tsx b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/app/app.helpers.tsx new file mode 100644 index 00000000000000..de7242a6c5ddf5 --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/app/app.helpers.tsx @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { registerTestBed, TestBed, TestBedConfig } from '../../../../../test_utils'; +import { App } from '../../../public/application/app'; +import { TestSubjects } from '../helpers'; +import { createBreadcrumbsMock } from '../../../public/application/services/breadcrumbs.mock'; +import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public/context'; + +const breadcrumbService = createBreadcrumbsMock(); + +const AppWithContext = (props: any) => { + return ( + + + + ); +}; + +const getTestBedConfig = (initialEntries: string[]): TestBedConfig => ({ + memoryRouter: { + initialEntries, + }, + defaultProps: { + getUrlForApp: () => {}, + navigateToApp: () => {}, + }, +}); + +const initTestBed = (initialEntries: string[]) => + registerTestBed(AppWithContext, getTestBedConfig(initialEntries))(); + +export interface AppTestBed extends TestBed { + actions: { + clickPolicyNameLink: () => void; + clickCreatePolicyButton: () => void; + }; +} + +export const setup = async (initialEntries: string[]): Promise => { + const testBed = await initTestBed(initialEntries); + + const clickPolicyNameLink = async () => { + const { component, find } = testBed; + await act(async () => { + find('policyTablePolicyNameLink').simulate('click', { button: 0 }); + }); + component.update(); + }; + + const clickCreatePolicyButton = async () => { + const { component, find } = testBed; + await act(async () => { + find('createPolicyButton').simulate('click', { button: 0 }); + }); + component.update(); + }; + + return { + ...testBed, + actions: { clickPolicyNameLink, clickCreatePolicyButton }, + }; +}; + +export const getEncodedPolicyEditPath = (policyName: string): string => + `/policies/edit/${encodeURIComponent(policyName)}`; + +export const getDoubleEncodedPolicyEditPath = (policyName: string): string => + encodeURI(getEncodedPolicyEditPath(policyName)); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/app/app.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/app/app.test.ts new file mode 100644 index 00000000000000..9052cf2847baae --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/app/app.test.ts @@ -0,0 +1,252 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + AppTestBed, + getDoubleEncodedPolicyEditPath, + getEncodedPolicyEditPath, + setup, +} from './app.helpers'; +import { setupEnvironment } from '../helpers/setup_environment'; +import { getDefaultHotPhasePolicy, POLICY_NAME } from '../edit_policy/constants'; +import { act } from 'react-dom/test-utils'; + +const SPECIAL_CHARS_NAME = 'test?#$+=&@:'; +const PERCENT_SIGN_NAME = 'test%'; +// navigation doesn't work for % with other special chars or sequence %25 +// known issue https://github.com/elastic/kibana/issues/82440 +const PERCENT_SIGN_WITH_OTHER_CHARS_NAME = 'test%#'; +const PERCENT_SIGN_25_SEQUENCE = 'test%25'; + +window.scrollTo = jest.fn(); + +describe('', () => { + let testBed: AppTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + afterAll(() => { + server.restore(); + }); + + describe('new policy creation', () => { + test('when there are no policies', async () => { + httpRequestsMockHelpers.setLoadPolicies([]); + await act(async () => { + testBed = await setup(['/']); + }); + + const { component, actions } = testBed; + component.update(); + + await actions.clickCreatePolicyButton(); + component.update(); + + expect(testBed.find('policyTitle').text()).toBe(`Create an index lifecycle policy`); + expect(testBed.find('policyNameField').props().value).toBe(''); + }); + + test('when there are policies', async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy(POLICY_NAME)]); + await act(async () => { + testBed = await setup(['/']); + }); + + const { component, actions } = testBed; + component.update(); + + await actions.clickCreatePolicyButton(); + component.update(); + + expect(testBed.find('policyTitle').text()).toBe(`Create an index lifecycle policy`); + expect(testBed.find('policyNameField').props().value).toBe(''); + }); + }); + + describe('navigation with special characters', () => { + beforeAll(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy(SPECIAL_CHARS_NAME)]); + }); + + test('clicking policy name in the table works', async () => { + await act(async () => { + testBed = await setup(['/']); + }); + + const { component, actions } = testBed; + component.update(); + + await actions.clickPolicyNameLink(); + component.update(); + + expect(testBed.find('policyTitle').text()).toBe( + `Edit index lifecycle policy ${SPECIAL_CHARS_NAME}` + ); + }); + + test('loading edit policy page url works', async () => { + await act(async () => { + testBed = await setup([getEncodedPolicyEditPath(SPECIAL_CHARS_NAME)]); + }); + + const { component } = testBed; + component.update(); + + expect(testBed.find('policyTitle').text()).toBe( + `Edit index lifecycle policy ${SPECIAL_CHARS_NAME}` + ); + }); + + // using double encoding to counteract react-router's v5 internal decodeURI call + // when those links are open in a new tab, address bar contains double encoded url + test('loading edit policy page url with double encoding works', async () => { + await act(async () => { + testBed = await setup([getDoubleEncodedPolicyEditPath(SPECIAL_CHARS_NAME)]); + }); + + const { component } = testBed; + component.update(); + + expect(testBed.find('policyTitle').text()).toBe( + `Edit index lifecycle policy ${SPECIAL_CHARS_NAME}` + ); + }); + }); + + describe('navigation with percent sign', () => { + beforeAll(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy(PERCENT_SIGN_NAME)]); + }); + + test('loading edit policy page url works', async () => { + await act(async () => { + testBed = await setup([getEncodedPolicyEditPath(PERCENT_SIGN_NAME)]); + }); + + const { component } = testBed; + component.update(); + + expect(testBed.find('policyTitle').text()).toBe( + `Edit index lifecycle policy ${PERCENT_SIGN_NAME}` + ); + }); + + test('loading edit policy page url with double encoding works', async () => { + await act(async () => { + testBed = await setup([getDoubleEncodedPolicyEditPath(PERCENT_SIGN_NAME)]); + }); + + const { component } = testBed; + component.update(); + + expect(testBed.find('policyTitle').text()).toBe( + `Edit index lifecycle policy ${PERCENT_SIGN_NAME}` + ); + }); + }); + + describe('navigation with percent sign with other special characters', () => { + beforeAll(async () => { + httpRequestsMockHelpers.setLoadPolicies([ + getDefaultHotPhasePolicy(PERCENT_SIGN_WITH_OTHER_CHARS_NAME), + ]); + }); + + test('clicking policy name in the table works', async () => { + await act(async () => { + testBed = await setup(['/']); + }); + + const { component, actions } = testBed; + component.update(); + + await actions.clickPolicyNameLink(); + component.update(); + + expect(testBed.find('policyTitle').text()).toBe( + `Edit index lifecycle policy ${PERCENT_SIGN_WITH_OTHER_CHARS_NAME}` + ); + }); + + test("loading edit policy page url doesn't work", async () => { + await act(async () => { + testBed = await setup([getEncodedPolicyEditPath(PERCENT_SIGN_WITH_OTHER_CHARS_NAME)]); + }); + + const { component } = testBed; + component.update(); + + // known issue https://github.com/elastic/kibana/issues/82440 + expect(testBed.find('policyTitle').text()).not.toBe( + `Edit index lifecycle policy ${PERCENT_SIGN_WITH_OTHER_CHARS_NAME}` + ); + }); + + // using double encoding to counteract react-router's v5 internal decodeURI call + // when those links are open in a new tab, address bar contains double encoded url + test('loading edit policy page url with double encoding works', async () => { + await act(async () => { + testBed = await setup([getDoubleEncodedPolicyEditPath(PERCENT_SIGN_WITH_OTHER_CHARS_NAME)]); + }); + + const { component } = testBed; + component.update(); + + expect(testBed.find('policyTitle').text()).toBe( + `Edit index lifecycle policy ${PERCENT_SIGN_WITH_OTHER_CHARS_NAME}` + ); + }); + }); + + describe('navigation with %25 sequence', () => { + beforeAll(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy(PERCENT_SIGN_25_SEQUENCE)]); + }); + + test('clicking policy name in the table works correctly', async () => { + await act(async () => { + testBed = await setup(['/']); + }); + + const { component, actions } = testBed; + component.update(); + + await actions.clickPolicyNameLink(); + component.update(); + + expect(testBed.find('policyTitle').text()).toBe( + `Edit index lifecycle policy ${PERCENT_SIGN_25_SEQUENCE}` + ); + }); + + test("loading edit policy page url doesn't work", async () => { + await act(async () => { + testBed = await setup([getEncodedPolicyEditPath(PERCENT_SIGN_25_SEQUENCE)]); + }); + + const { component } = testBed; + component.update(); + + // known issue https://github.com/elastic/kibana/issues/82440 + expect(testBed.find('policyTitle').text()).not.toBe( + `Edit index lifecycle policy ${PERCENT_SIGN_25_SEQUENCE}` + ); + }); + + // using double encoding to counteract react-router's v5 internal decodeURI call + // when those links are open in a new tab, address bar contains double encoded url + test('loading edit policy page url with double encoding works', async () => { + await act(async () => { + testBed = await setup([getDoubleEncodedPolicyEditPath(PERCENT_SIGN_25_SEQUENCE)]); + }); + + const { component } = testBed; + component.update(); + + expect(testBed.find('policyTitle').text()).toBe( + `Edit index lifecycle policy ${PERCENT_SIGN_25_SEQUENCE}` + ); + }); + }); +}); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts index 3d430cf31621e9..00c7d705c1f44a 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts @@ -121,6 +121,26 @@ export const DELETE_PHASE_POLICY: PolicyFromES = { name: POLICY_NAME, }; +export const getDefaultHotPhasePolicy = (policyName: string): PolicyFromES => ({ + version: 1, + modified_date: Date.now().toString(), + policy: { + name: policyName, + phases: { + hot: { + min_age: '0ms', + actions: { + rollover: { + max_age: '30d', + max_size: '50gb', + }, + }, + }, + }, + }, + name: policyName, +}); + export const POLICY_WITH_NODE_ATTR_AND_OFF_ALLOCATION: PolicyFromES = { version: 1, modified_date: Date.now().toString(), diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts index 4ee67d1ed8a19e..c91ee3e2a1c068 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts @@ -19,6 +19,7 @@ import { POLICY_WITH_INCLUDE_EXCLUDE, POLICY_WITH_NODE_ATTR_AND_OFF_ALLOCATION, POLICY_WITH_NODE_ROLE_ALLOCATION, + getDefaultHotPhasePolicy, } from './constants'; window.scrollTo = jest.fn(); @@ -33,7 +34,7 @@ describe('', () => { describe('hot phase', () => { describe('serialization', () => { beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([DEFAULT_POLICY]); + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); httpRequestsMockHelpers.setLoadSnapshotPolicies([]); await act(async () => { diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/index.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/index.ts index e8ebc2963d16a5..aff9151da61f95 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/index.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/index.ts @@ -17,5 +17,8 @@ export type TestSubjects = | 'hot-selectedMaxDocuments' | 'hot-selectedMaxAge' | 'hot-selectedMaxAgeUnits' + | 'policyTablePolicyNameLink' + | 'policyTitle' + | 'createPolicyButton' | 'freezeSwitch' | string; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/app.tsx b/x-pack/plugins/index_lifecycle_management/public/application/app.tsx index 856981fe5c4f93..20185b02064bc8 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/app.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/app.tsx @@ -15,7 +15,7 @@ import { PolicyTable } from './sections/policy_table'; import { trackUiMetric } from './services/ui_metric'; import { ROUTES } from './services/navigation'; -export const App = ({ +export const AppWithRouter = ({ history, navigateToApp, getUrlForApp, @@ -23,23 +23,33 @@ export const App = ({ history: ScopedHistory; navigateToApp: ApplicationStart['navigateToApp']; getUrlForApp: ApplicationStart['getUrlForApp']; +}) => ( + + + +); + +export const App = ({ + navigateToApp, + getUrlForApp, +}: { + navigateToApp: ApplicationStart['navigateToApp']; + getUrlForApp: ApplicationStart['getUrlForApp']; }) => { useEffect(() => trackUiMetric(METRIC_TYPE.LOADED, UIM_APP_LOAD), []); return ( - - - - } - /> - } - /> - - + + + } + /> + } + /> + ); }; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/index.tsx b/x-pack/plugins/index_lifecycle_management/public/application/index.tsx index 3d4cc7dbbd1d49..bb1a4810ba2d20 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/index.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/index.tsx @@ -12,7 +12,7 @@ import { CloudSetup } from '../../../cloud/public'; import { KibanaContextProvider } from '../shared_imports'; -import { App } from './app'; +import { AppWithRouter } from './app'; import { BreadcrumbService } from './services/breadcrumbs'; @@ -28,7 +28,11 @@ export const renderApp = ( render( - + , element diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.container.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.container.tsx index ebef80871b83dc..4c0cc2c8957e1e 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.container.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.container.tsx @@ -9,7 +9,7 @@ import { RouteComponentProps } from 'react-router-dom'; import { EuiButton, EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { useKibana } from '../../../shared_imports'; +import { useKibana, attemptToURIDecode } from '../../../shared_imports'; import { useLoadPoliciesList } from '../../services/api'; import { getPolicyByName } from '../../lib/policies'; @@ -90,13 +90,13 @@ export const EditPolicy: React.FunctionComponent = ({ history }) => { verticalPosition="center" horizontalPosition="center" > - +

{isNewPolicy ? i18n.translate('xpack.indexLifecycleMgmt.editPolicy.createPolicyMessage', { diff --git a/x-pack/plugins/index_lifecycle_management/public/shared_imports.ts b/x-pack/plugins/index_lifecycle_management/public/shared_imports.ts index a127574d5bad04..a5844af0bf6dd0 100644 --- a/x-pack/plugins/index_lifecycle_management/public/shared_imports.ts +++ b/x-pack/plugins/index_lifecycle_management/public/shared_imports.ts @@ -32,6 +32,8 @@ export { TextField, } from '../../../../src/plugins/es_ui_shared/static/forms/components'; +export { attemptToURIDecode } from '../../../../src/plugins/es_ui_shared/public'; + export { KibanaContextProvider } from '../../../../src/plugins/kibana_react/public'; export const useKibana = () => _useKibana(); diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/component_template_details.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/component_template_details.tsx index 6d9aa58d6c86b8..2fb16874cf943a 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/component_template_details.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/component_template_details.tsx @@ -52,7 +52,7 @@ export const ComponentTemplateDetailsFlyoutContent: React.FunctionComponent { const { api } = useComponentTemplatesContext(); - const decodedComponentTemplateName = attemptToURIDecode(componentTemplateName); + const decodedComponentTemplateName = attemptToURIDecode(componentTemplateName)!; const { data: componentTemplateDetails, isLoading, error } = api.useLoadComponentTemplate( decodedComponentTemplateName diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list.tsx index 00ea3ebf794eed..e8424ae46c6d25 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list.tsx @@ -84,7 +84,7 @@ export const ComponentTemplateList: React.FunctionComponent = ({ }), icon: 'pencil', handleActionClick: () => - goToEditComponentTemplate(attemptToURIDecode(componentTemplateName)), + goToEditComponentTemplate(attemptToURIDecode(componentTemplateName)!), }, { name: i18n.translate('xpack.idxMgmt.componentTemplateDetails.cloneActionLabel', { @@ -92,7 +92,7 @@ export const ComponentTemplateList: React.FunctionComponent = ({ }), icon: 'copy', handleActionClick: () => - goToCloneComponentTemplate(attemptToURIDecode(componentTemplateName)), + goToCloneComponentTemplate(attemptToURIDecode(componentTemplateName)!), }, { name: i18n.translate('xpack.idxMgmt.componentTemplateDetails.deleteButtonLabel', { @@ -103,7 +103,7 @@ export const ComponentTemplateList: React.FunctionComponent = ({ details._kbnMeta.usedBy.length > 0, closePopoverOnClick: true, handleActionClick: () => { - setComponentTemplatesToDelete([attemptToURIDecode(componentTemplateName)]); + setComponentTemplatesToDelete([attemptToURIDecode(componentTemplateName)!]); }, }, ]; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_clone/component_template_clone.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_clone/component_template_clone.tsx index 6c03fcf5d99729..e6b403543f4b04 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_clone/component_template_clone.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_clone/component_template_clone.tsx @@ -19,7 +19,7 @@ export interface Params { export const ComponentTemplateClone: FunctionComponent> = (props) => { const { sourceComponentTemplateName } = props.match.params; - const decodedSourceName = attemptToURIDecode(sourceComponentTemplateName); + const decodedSourceName = attemptToURIDecode(sourceComponentTemplateName)!; const { toasts, api } = useComponentTemplatesContext(); diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_edit/component_template_edit.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_edit/component_template_edit.tsx index 934f86f7d7590c..500c84a97d222e 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_edit/component_template_edit.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_edit/component_template_edit.tsx @@ -31,7 +31,7 @@ export const ComponentTemplateEdit: React.FunctionComponent(false); const [saveError, setSaveError] = useState(null); - const decodedName = attemptToURIDecode(name); + const decodedName = attemptToURIDecode(name)!; const { error, data: componentTemplate, isLoading } = api.useLoadComponentTemplate(decodedName); diff --git a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx index ba79319b566bfa..20b93d9d71d044 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx @@ -231,7 +231,7 @@ export const DataStreamList: React.FunctionComponent { history.push(`/${Section.DataStreams}`); diff --git a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_list.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_list.tsx index f3e82223c30e6c..3689a875e28b25 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_list.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_list.tsx @@ -101,7 +101,7 @@ export const TemplateList: React.FunctionComponent { - const decodedTemplateName = attemptToURIDecode(name); + const decodedTemplateName = attemptToURIDecode(name)!; const isLegacy = getIsLegacyFromQueryParams(location); const [isSaving, setIsSaving] = useState(false); diff --git a/x-pack/plugins/index_management/public/application/sections/template_edit/template_edit.tsx b/x-pack/plugins/index_management/public/application/sections/template_edit/template_edit.tsx index 3e62f7f880f749..e3cb40b3a36e15 100644 --- a/x-pack/plugins/index_management/public/application/sections/template_edit/template_edit.tsx +++ b/x-pack/plugins/index_management/public/application/sections/template_edit/template_edit.tsx @@ -27,7 +27,7 @@ export const TemplateEdit: React.FunctionComponent { - const decodedTemplateName = attemptToURIDecode(name); + const decodedTemplateName = attemptToURIDecode(name)!; const isLegacy = getIsLegacyFromQueryParams(location); const [isSaving, setIsSaving] = useState(false); diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_clone/pipelines_clone.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_clone/pipelines_clone.tsx index 9465117b6b5895..df609079731560 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_clone/pipelines_clone.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_clone/pipelines_clone.tsx @@ -25,7 +25,7 @@ export const PipelinesClone: FunctionComponent> const { sourceName } = props.match.params; const { services } = useKibana(); - const decodedSourceName = attemptToURIDecode(sourceName); + const decodedSourceName = attemptToURIDecode(sourceName)!; const { error, data: pipeline, isLoading, isInitialRequest } = services.api.useLoadPipeline( decodedSourceName ); diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_edit/pipelines_edit.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_edit/pipelines_edit.tsx index 7e2e85ab23fb30..2b53fdb6a6375e 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_edit/pipelines_edit.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_edit/pipelines_edit.tsx @@ -38,7 +38,7 @@ export const PipelinesEdit: React.FunctionComponent(false); const [saveError, setSaveError] = useState(null); - const decodedPipelineName = attemptToURIDecode(name); + const decodedPipelineName = attemptToURIDecode(name)!; const { error, data: pipeline, isLoading } = services.api.useLoadPipeline(decodedPipelineName); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx index 2e24b64ecca26a..97165a85130780 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx @@ -23,7 +23,7 @@ import { IconType } from '@elastic/eui/src/components/icon/icon'; import { Ast, toExpression } from '@kbn/interpreter/common'; import { i18n } from '@kbn/i18n'; import classNames from 'classnames'; -import { ExecutionContextSearch } from 'src/plugins/expressions'; +import { DataPublicPluginStart, ExecutionContextSearch } from 'src/plugins/data/public'; import { Action, PreviewState } from './state_management'; import { Datasource, Visualization, FramePublicAPI, DatasourcePublicAPI } from '../../types'; import { getSuggestions, switchToSuggestion } from './suggestion_helpers'; @@ -33,7 +33,6 @@ import { } from '../../../../../../src/plugins/expressions/public'; import { prependDatasourceExpression } from './expression_helpers'; import { trackUiEvent, trackSuggestionEvent } from '../../lens_ui_telemetry'; -import { DataPublicPluginStart } from '../../../../../../src/plugins/data/public'; import { validateDatasourceAndVisualization } from './state_helpers'; const MAX_SUGGESTIONS_DISPLAYED = 5; diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index e0dd3b3fe01ae9..00cb932a6d4e21 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -20,7 +20,11 @@ import { EuiTitle, } from '@elastic/eui'; import { CoreStart, CoreSetup } from 'kibana/public'; -import { ExecutionContextSearch } from 'src/plugins/expressions'; +import { + DataPublicPluginStart, + ExecutionContextSearch, + TimefilterContract, +} from 'src/plugins/data/public'; import { ExpressionRendererEvent, ExpressionRenderError, @@ -44,10 +48,6 @@ import { VisualizeFieldContext, } from '../../../../../../../src/plugins/ui_actions/public'; import { VIS_EVENT_TO_TRIGGER } from '../../../../../../../src/plugins/visualizations/public'; -import { - DataPublicPluginStart, - TimefilterContract, -} from '../../../../../../../src/plugins/data/public'; import { WorkspacePanelWrapper } from './workspace_panel_wrapper'; import { DropIllustration } from '../../../assets/drop_illustration'; import { LensInspectorAdapters } from '../../types'; diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx index 33e5dee99081ff..8139631daa971a 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx @@ -8,6 +8,7 @@ import _ from 'lodash'; import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { + ExecutionContextSearch, Filter, IIndexPattern, Query, @@ -15,7 +16,6 @@ import { TimeRange, IndexPattern, } from 'src/plugins/data/public'; -import { ExecutionContextSearch } from 'src/plugins/expressions'; import { PaletteOutput } from 'src/plugins/charts/public'; import { Subscription } from 'rxjs'; diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx b/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx index 7479577805bdd0..4a3ba971381fb3 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/expression_wrapper.tsx @@ -12,7 +12,7 @@ import { ExpressionRendererEvent, ReactExpressionRendererType, } from 'src/plugins/expressions/public'; -import { ExecutionContextSearch } from 'src/plugins/expressions'; +import { ExecutionContextSearch } from 'src/plugins/data/public'; import { getOriginalRequestErrorMessage } from '../error_helper'; export interface ExpressionWrapperProps { diff --git a/x-pack/plugins/lens/public/editor_frame_service/merge_tables.test.ts b/x-pack/plugins/lens/public/editor_frame_service/merge_tables.test.ts index 07c16665d11b44..02c07d809e09f6 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/merge_tables.test.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/merge_tables.test.ts @@ -6,6 +6,7 @@ import moment from 'moment'; import { mergeTables } from './merge_tables'; +import { ExpressionValueSearchContext } from 'src/plugins/data/public'; import { Datatable, ExecutionContext } from 'src/plugins/expressions'; import { LensInspectorAdapters } from './types'; @@ -52,7 +53,7 @@ describe('lens_merge_tables', () => { const adapters: LensInspectorAdapters = { tables: {} }; mergeTables.fn(null, { layerIds: ['first', 'second'], tables: [sampleTable1, sampleTable2] }, { inspectorAdapters: adapters, - } as ExecutionContext); + } as ExecutionContext); expect(adapters.tables!.first).toBe(sampleTable1); expect(adapters.tables!.second).toBe(sampleTable2); }); diff --git a/x-pack/plugins/lens/public/editor_frame_service/merge_tables.ts b/x-pack/plugins/lens/public/editor_frame_service/merge_tables.ts index 03ef7cf9cc6374..109b30144fc201 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/merge_tables.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/merge_tables.ts @@ -9,9 +9,8 @@ import { ExecutionContext, Datatable, ExpressionFunctionDefinition, - ExpressionValueSearchContext, } from 'src/plugins/expressions/public'; -import { search } from '../../../../../src/plugins/data/public'; +import { ExpressionValueSearchContext, search } from '../../../../../src/plugins/data/public'; const { toAbsoluteDates } = search.aggs; import { LensMultiTable } from '../types'; @@ -27,7 +26,7 @@ export const mergeTables: ExpressionFunctionDefinition< ExpressionValueSearchContext | null, MergeTables, LensMultiTable, - ExecutionContext + ExecutionContext > = { name: 'lens_merge_tables', type: 'lens_multitable', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx index c8a8ffa7b128fd..d43a905434c02a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx @@ -744,6 +744,36 @@ describe('ranges', () => { /^Bytes format:/ ); }); + + it('should not reset formatters when switching between custom ranges and auto histogram', () => { + const setStateSpy = jest.fn(); + // now set a format on the range operation + (state.layers.first.columns.col1 as RangeIndexPatternColumn).params.format = { + id: 'custom', + params: { decimals: 3 }, + }; + + const instance = mount( + + ); + + // This series of act closures are made to make it work properly the update flush + act(() => { + instance.find(EuiLink).first().prop('onClick')!({} as ReactMouseEvent); + }); + + expect(setStateSpy.mock.calls[1][0].layers.first.columns.col1.params.format).toEqual({ + id: 'custom', + params: { decimals: 3 }, + }); + }); }); }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx index 1050eef45a71cd..46d9e4e6c22de2 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx @@ -225,7 +225,7 @@ export const rangeOperation: OperationDefinition diff --git a/x-pack/plugins/lens/public/shared_components/toolbar_popover.tsx b/x-pack/plugins/lens/public/shared_components/toolbar_popover.tsx index 20837424dc7b59..cf2268c6eadf2e 100644 --- a/x-pack/plugins/lens/public/shared_components/toolbar_popover.tsx +++ b/x-pack/plugins/lens/public/shared_components/toolbar_popover.tsx @@ -11,6 +11,7 @@ import { EuiIconLegend } from '../assets/legend'; const typeToIconMap: { [type: string]: string | IconType } = { legend: EuiIconLegend as IconType, + labels: 'visText', values: 'number', }; diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index d238e052a7c7fe..730f8508e28897 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -29,7 +29,6 @@ import { I18nProvider } from '@kbn/i18n/react'; import { ExpressionFunctionDefinition, ExpressionRenderDefinition, - ExpressionValueSearchContext, Datatable, DatatableRow, } from 'src/plugins/expressions/public'; @@ -45,7 +44,7 @@ import { import { XYArgs, SeriesType, visualizationTypes } from './types'; import { VisualizationContainer } from '../visualization_container'; import { isHorizontalChart, getSeriesColor } from './state_helpers'; -import { parseInterval } from '../../../../../src/plugins/data/common'; +import { ExpressionValueSearchContext, search } from '../../../../../src/plugins/data/public'; import { ChartsPluginSetup, PaletteRegistry, @@ -384,7 +383,8 @@ export function XYChart({ // add minInterval only for single point in domain if (data.dateRange && isSingleTimestampInXDomain()) { const params = xAxisColumn?.meta?.sourceParams?.params as Record; - if (params?.interval !== 'auto') return parseInterval(params?.interval)?.asMilliseconds(); + if (params?.interval !== 'auto') + return search.aggs.parseInterval(params?.interval)?.asMilliseconds(); const { fromDate, toDate } = data.dateRange; const duration = moment(toDate).diff(moment(fromDate)); diff --git a/x-pack/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js b/x-pack/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js index 643cc3efb0136d..e021831d2f4381 100644 --- a/x-pack/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js +++ b/x-pack/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js @@ -161,9 +161,7 @@ export class RollupIndexPatternCreationConfig extends IndexPatternCreationConfig getFetchForWildcardOptions = () => { return { type: this.type, - params: { - rollup_index: this.rollupIndex, - }, + rollupIndex: this.rollupIndex, }; }; } diff --git a/x-pack/plugins/rollup/server/lib/map_capabilities.ts b/x-pack/plugins/rollup/server/lib/map_capabilities.ts deleted file mode 100644 index 233c6d1dd4b4b6..00000000000000 --- a/x-pack/plugins/rollup/server/lib/map_capabilities.ts +++ /dev/null @@ -1,24 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { mergeJobConfigurations } from './jobs_compatibility'; - -export function getCapabilitiesForRollupIndices(indices: { [key: string]: any }) { - const indexNames = Object.keys(indices); - const capabilities = {} as { [key: string]: any }; - - indexNames.forEach((index) => { - try { - capabilities[index] = mergeJobConfigurations(indices[index].rollup_jobs); - } catch (e) { - capabilities[index] = { - error: e.message, - }; - } - }); - - return capabilities; -} diff --git a/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.ts b/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.ts index f439ac555aed93..dcf6629d353974 100644 --- a/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.ts +++ b/x-pack/plugins/rollup/server/lib/search_strategies/rollup_search_strategy.ts @@ -6,8 +6,11 @@ import { keyBy, isString } from 'lodash'; import { ILegacyScopedClusterClient } from 'src/core/server'; import { ReqFacade } from '../../../../../../src/plugins/vis_type_timeseries/server'; -import { mergeCapabilitiesWithFields } from '../merge_capabilities_with_fields'; -import { getCapabilitiesForRollupIndices } from '../map_capabilities'; + +import { + mergeCapabilitiesWithFields, + getCapabilitiesForRollupIndices, +} from '../../../../../../src/plugins/data/server'; const getRollupIndices = (rollupData: { [key: string]: any }) => Object.keys(rollupData); diff --git a/x-pack/plugins/rollup/server/plugin.ts b/x-pack/plugins/rollup/server/plugin.ts index fe193150fc1cae..51920af7c8cbc5 100644 --- a/x-pack/plugins/rollup/server/plugin.ts +++ b/x-pack/plugins/rollup/server/plugin.ts @@ -36,8 +36,7 @@ import { registerRollupSearchStrategy } from './lib/search_strategies'; import { elasticsearchJsPlugin } from './client/elasticsearch_rollup'; import { isEsError } from './shared_imports'; import { formatEsError } from './lib/format_es_error'; -import { getCapabilitiesForRollupIndices } from './lib/map_capabilities'; -import { mergeCapabilitiesWithFields } from './lib/merge_capabilities_with_fields'; +import { getCapabilitiesForRollupIndices } from '../../../../src/plugins/data/server'; interface RollupContext { client: ILegacyScopedClusterClient; @@ -107,7 +106,6 @@ export class RollupPlugin implements Plugin { isEsError, formatEsError, getCapabilitiesForRollupIndices, - mergeCapabilitiesWithFields, }, sharedImports: { IndexPatternsFetcher, diff --git a/x-pack/plugins/rollup/server/routes/api/index_patterns/index.ts b/x-pack/plugins/rollup/server/routes/api/index_patterns/index.ts deleted file mode 100644 index 7bf525ca4aa984..00000000000000 --- a/x-pack/plugins/rollup/server/routes/api/index_patterns/index.ts +++ /dev/null @@ -1,12 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { RouteDependencies } from '../../../types'; -import { registerFieldsForWildcardRoute } from './register_fields_for_wildcard_route'; - -export function registerIndexPatternsRoutes(dependencies: RouteDependencies) { - registerFieldsForWildcardRoute(dependencies); -} diff --git a/x-pack/plugins/rollup/server/routes/api/index_patterns/register_fields_for_wildcard_route.ts b/x-pack/plugins/rollup/server/routes/api/index_patterns/register_fields_for_wildcard_route.ts deleted file mode 100644 index df9907fbf731a1..00000000000000 --- a/x-pack/plugins/rollup/server/routes/api/index_patterns/register_fields_for_wildcard_route.ts +++ /dev/null @@ -1,142 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { keyBy } from 'lodash'; -import { schema } from '@kbn/config-schema'; -import { Field } from '../../../lib/merge_capabilities_with_fields'; -import { RouteDependencies } from '../../../types'; -import type { IndexPatternsFetcher as IndexPatternsFetcherType } from '../../../../../../../src/plugins/data/server'; - -const parseMetaFields = (metaFields: string | string[]) => { - let parsedFields: string[] = []; - if (typeof metaFields === 'string') { - parsedFields = JSON.parse(metaFields); - } else { - parsedFields = metaFields; - } - return parsedFields; -}; - -const getFieldsForWildcardRequest = async ( - context: any, - request: any, - response: any, - IndexPatternsFetcher: typeof IndexPatternsFetcherType -) => { - const { asCurrentUser } = context.core.elasticsearch.client; - const indexPatterns = new IndexPatternsFetcher(asCurrentUser); - const { pattern, meta_fields: metaFields } = request.query; - - let parsedFields: string[] = []; - try { - parsedFields = parseMetaFields(metaFields); - } catch (error) { - return response.badRequest({ - body: error, - }); - } - - try { - const fields = await indexPatterns.getFieldsForWildcard({ - pattern, - metaFields: parsedFields, - }); - - return response.ok({ - body: { fields }, - headers: { - 'content-type': 'application/json', - }, - }); - } catch (error) { - return response.notFound(); - } -}; - -/** - * Get list of fields for rollup index pattern, in the format of regular index pattern fields - */ -export const registerFieldsForWildcardRoute = ({ - router, - license, - lib: { isEsError, formatEsError, getCapabilitiesForRollupIndices, mergeCapabilitiesWithFields }, - sharedImports: { IndexPatternsFetcher }, -}: RouteDependencies) => { - const querySchema = schema.object({ - pattern: schema.string(), - meta_fields: schema.arrayOf(schema.string(), { - defaultValue: [], - }), - params: schema.string({ - validate(value) { - try { - const params = JSON.parse(value); - const keys = Object.keys(params); - const { rollup_index: rollupIndex } = params; - - if (!rollupIndex) { - return '[request query.params]: "rollup_index" is required'; - } else if (keys.length > 1) { - const invalidParams = keys.filter((key) => key !== 'rollup_index'); - return `[request query.params]: ${invalidParams.join(', ')} is not allowed`; - } - } catch (err) { - return '[request query.params]: expected JSON string'; - } - }, - }), - }); - - router.get( - { - path: '/api/index_patterns/rollup/_fields_for_wildcard', - validate: { - query: querySchema, - }, - }, - license.guardApiRoute(async (context, request, response) => { - const { params, meta_fields: metaFields } = request.query; - - try { - // Make call and use field information from response - const { payload } = await getFieldsForWildcardRequest( - context, - request, - response, - IndexPatternsFetcher - ); - const fields = payload.fields; - const parsedParams = JSON.parse(params); - const rollupIndex = parsedParams.rollup_index; - const rollupFields: Field[] = []; - const fieldsFromFieldCapsApi: { [key: string]: any } = keyBy(fields, 'name'); - const rollupIndexCapabilities = getCapabilitiesForRollupIndices( - await context.rollup!.client.callAsCurrentUser('rollup.rollupIndexCapabilities', { - indexPattern: rollupIndex, - }) - )[rollupIndex].aggs; - - // Keep meta fields - metaFields.forEach( - (field: string) => - fieldsFromFieldCapsApi[field] && rollupFields.push(fieldsFromFieldCapsApi[field]) - ); - - const mergedRollupFields = mergeCapabilitiesWithFields( - rollupIndexCapabilities, - fieldsFromFieldCapsApi, - rollupFields - ); - return response.ok({ body: { fields: mergedRollupFields } }); - } catch (err) { - if (isEsError(err)) { - return response.customError({ statusCode: err.statusCode, body: err }); - } - return response.internalError({ body: err }); - } - }) - ); -}; diff --git a/x-pack/plugins/rollup/server/routes/index.ts b/x-pack/plugins/rollup/server/routes/index.ts index b25480855b4a21..322003c0ee325c 100644 --- a/x-pack/plugins/rollup/server/routes/index.ts +++ b/x-pack/plugins/rollup/server/routes/index.ts @@ -6,13 +6,11 @@ import { RouteDependencies } from '../types'; -import { registerIndexPatternsRoutes } from './api/index_patterns'; import { registerIndicesRoutes } from './api/indices'; import { registerJobsRoutes } from './api/jobs'; import { registerSearchRoutes } from './api/search'; export function registerApiRoutes(dependencies: RouteDependencies) { - registerIndexPatternsRoutes(dependencies); registerIndicesRoutes(dependencies); registerJobsRoutes(dependencies); registerSearchRoutes(dependencies); diff --git a/x-pack/plugins/rollup/server/types.ts b/x-pack/plugins/rollup/server/types.ts index b167806cf8d5df..89e13e69c4da29 100644 --- a/x-pack/plugins/rollup/server/types.ts +++ b/x-pack/plugins/rollup/server/types.ts @@ -8,6 +8,7 @@ import { IRouter } from 'src/core/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { VisTypeTimeseriesSetup } from 'src/plugins/vis_type_timeseries/server'; +import { getCapabilitiesForRollupIndices } from 'src/plugins/data/server'; import { IndexManagementPluginSetup } from '../../index_management/server'; import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server'; import { LicensingPluginSetup } from '../../licensing/server'; @@ -15,8 +16,6 @@ import { License } from './services'; import { IndexPatternsFetcher } from './shared_imports'; import { isEsError } from './shared_imports'; import { formatEsError } from './lib/format_es_error'; -import { getCapabilitiesForRollupIndices } from './lib/map_capabilities'; -import { mergeCapabilitiesWithFields } from './lib/merge_capabilities_with_fields'; export interface Dependencies { indexManagement?: IndexManagementPluginSetup; @@ -33,7 +32,6 @@ export interface RouteDependencies { isEsError: typeof isEsError; formatEsError: typeof formatEsError; getCapabilitiesForRollupIndices: typeof getCapabilitiesForRollupIndices; - mergeCapabilitiesWithFields: typeof mergeCapabilitiesWithFields; }; sharedImports: { IndexPatternsFetcher: typeof IndexPatternsFetcher; diff --git a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx index 2b7ed0079f2919..37747f9a1ccfa4 100644 --- a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx +++ b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx @@ -260,6 +260,10 @@ export class UsersGridPage extends Component { { diff --git a/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx b/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx index b40f34273d99f0..68c4a4ff02b947 100644 --- a/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx +++ b/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx @@ -110,6 +110,10 @@ export class SpacesGridPage extends Component { response.body); } - describe('update', () => { + // FLAKY: https://github.com/elastic/kibana/issues/82804 + describe.skip('update', () => { const objectRemover = new ObjectRemover(supertest); after(() => objectRemover.removeAll()); diff --git a/x-pack/test/api_integration/apis/kibana/stats/stats.js b/x-pack/test/api_integration/apis/kibana/stats/stats.js index f0a41f1f008ba3..ae4ddad66863b5 100644 --- a/x-pack/test/api_integration/apis/kibana/stats/stats.js +++ b/x-pack/test/api_integration/apis/kibana/stats/stats.js @@ -30,7 +30,7 @@ export default function ({ getService }) { }); it('should return 401 for extended', async () => { - await supertestNoAuth.get('/api/stats?extended').expect(401); + await supertestNoAuth.get('/api/stats?extended').auth(null, null).expect(401); }); }); diff --git a/x-pack/test/api_integration/apis/management/rollup/constants.js b/x-pack/test/api_integration/apis/management/rollup/constants.js index fe899c4c10c880..0313434cf716c4 100644 --- a/x-pack/test/api_integration/apis/management/rollup/constants.js +++ b/x-pack/test/api_integration/apis/management/rollup/constants.js @@ -5,7 +5,7 @@ */ export const API_BASE_PATH = '/api/rollup'; -export const INDEX_PATTERNS_EXTENSION_BASE_PATH = '/api/index_patterns/rollup'; +export const INDEX_PATTERNS_EXTENSION_BASE_PATH = '/api/index_patterns'; export const ROLLUP_INDEX_NAME = 'rollup_index'; export const INDEX_TO_ROLLUP_MAPPINGS = { properties: { diff --git a/x-pack/test/api_integration/apis/management/rollup/index_patterns_extensions.js b/x-pack/test/api_integration/apis/management/rollup/index_patterns_extensions.js index 357b952e7e66d4..0a93e8b8bd1e37 100644 --- a/x-pack/test/api_integration/apis/management/rollup/index_patterns_extensions.js +++ b/x-pack/test/api_integration/apis/management/rollup/index_patterns_extensions.js @@ -26,7 +26,6 @@ export default function ({ getService }) { describe('query params validation', () => { let uri; let body; - let params; it('"pattern" is required', async () => { uri = `${BASE_URI}`; @@ -36,62 +35,17 @@ export default function ({ getService }) { ); }); - it('"params" is required', async () => { - params = { pattern: 'foo' }; - uri = `${BASE_URI}?${stringify(params, { sort: false })}`; - ({ body } = await supertest.get(uri).expect(400)); - expect(body.message).to.contain( - '[request query.params]: expected value of type [string]' - ); - }); - - it('"params" must be a valid JSON string', async () => { - params = { pattern: 'foo', params: 'foobarbaz' }; - uri = `${BASE_URI}?${stringify(params, { sort: false })}`; - ({ body } = await supertest.get(uri).expect(400)); - expect(body.message).to.contain('[request query.params]: expected JSON string'); - }); - - it('"params" requires a "rollup_index" property', async () => { - params = { pattern: 'foo', params: JSON.stringify({}) }; - uri = `${BASE_URI}?${stringify(params, { sort: false })}`; - ({ body } = await supertest.get(uri).expect(400)); - expect(body.message).to.contain('[request query.params]: "rollup_index" is required'); - }); - - it('"params" only accepts a "rollup_index" property', async () => { - params = { - pattern: 'foo', - params: JSON.stringify({ rollup_index: 'my_index', someProp: 'bar' }), - }; - uri = `${BASE_URI}?${stringify(params, { sort: false })}`; - ({ body } = await supertest.get(uri).expect(400)); - expect(body.message).to.contain('[request query.params]: someProp is not allowed'); - }); - - it('"meta_fields" must be an Array', async () => { - params = { - pattern: 'foo', - params: JSON.stringify({ rollup_index: 'bar' }), - meta_fields: 'stringValue', - }; - uri = `${BASE_URI}?${stringify(params, { sort: false })}`; - ({ body } = await supertest.get(uri).expect(400)); - expect(body.message).to.contain( - '[request query.meta_fields]: could not parse array value from json input' - ); - }); - it('should return 404 the rollup index to query does not exist', async () => { uri = `${BASE_URI}?${stringify( { pattern: 'foo', - params: JSON.stringify({ rollup_index: 'bar' }), + type: 'rollup', + rollup_index: 'bar', }, { sort: false } )}`; ({ body } = await supertest.get(uri).expect(404)); - expect(body.message).to.contain('[index_not_found_exception] no such index [bar]'); + expect(body.message).to.contain('No indices match pattern "foo"'); }); }); @@ -105,7 +59,8 @@ export default function ({ getService }) { // Query for wildcard const params = { pattern: indexName, - params: JSON.stringify({ rollup_index: rollupIndex }), + type: 'rollup', + rollup_index: rollupIndex, }; const uri = `${BASE_URI}?${stringify(params, { sort: false })}`; const { body } = await supertest.get(uri).expect(200); diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index 2072f4aa1c571c..11e4111696ccf9 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -88,6 +88,7 @@ export default async function ({ readConfigFile }) { '--xpack.security.encryptionKey="wuGNaIhoMpk5sO4UBxgr3NyW1sFcLgIf"', // server restarts should not invalidate active sessions '--xpack.encryptedSavedObjects.encryptionKey="DkdXazszSCYexXqz4YktBGHCRkV6hyNK"', '--timelion.ui.enabled=true', + '--savedObjects.maxImportPayloadBytes=10485760', // for OSS test management/_import_objects ], }, uiSettings: { diff --git a/x-pack/test/functional/es_archives/endpoint/resolver_tree/alert_events/data.json.gz b/x-pack/test/functional/es_archives/endpoint/resolver_tree/alert_events/data.json.gz new file mode 100644 index 00000000000000..997a7a5322a115 Binary files /dev/null and b/x-pack/test/functional/es_archives/endpoint/resolver_tree/alert_events/data.json.gz differ diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/resolver.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/resolver.ts index b45c082423628c..d49f5bf17aab1e 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/resolver.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/resolver.ts @@ -279,6 +279,29 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { } await pageObjects.hosts.runNodeEvents(expectedLibraryData); }); + + it('Check Related Events for event.alert Node', async () => { + await esArchiver.load('empty_kibana'); + await esArchiver.load('endpoint/resolver_tree/alert_events', { useCreate: true }); + await queryBar.setQuery(''); + await queryBar.submitQuery(); + const expectedAlertData = [ + '1 library', + '157 file', + '520 registry', + '3 file', + '5 library', + '5 library', + ]; + await pageObjects.hosts.navigateToEventsPanel(); + await pageObjects.hosts.executeQueryAndOpenResolver('event.dataset : endpoint.alerts'); + await (await testSubjects.find('resolver:graph-controls:zoom-out')).click(); + await browser.setWindowSize(2100, 1500); + for (let i = 0; i < 2; i++) { + await (await testSubjects.find('resolver:graph-controls:east-button')).click(); + } + await pageObjects.hosts.runNodeEvents(expectedAlertData); + }); }); }); } diff --git a/x-pack/test/security_solution_endpoint/config.ts b/x-pack/test/security_solution_endpoint/config.ts index 9ee9e061edf4c0..9499c235a5f0d5 100644 --- a/x-pack/test/security_solution_endpoint/config.ts +++ b/x-pack/test/security_solution_endpoint/config.ts @@ -30,7 +30,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { ['securitySolutionManagement']: { pathname: '/app/security/administration', }, - ...xpackFunctionalConfig.get('apps'), ['security']: { pathname: '/app/security', }, diff --git a/x-pack/test/security_solution_endpoint/page_objects/hosts_page.ts b/x-pack/test/security_solution_endpoint/page_objects/hosts_page.ts index 988fadbbdfe338..c76a5a7c22f607 100644 --- a/x-pack/test/security_solution_endpoint/page_objects/hosts_page.ts +++ b/x-pack/test/security_solution_endpoint/page_objects/hosts_page.ts @@ -121,6 +121,8 @@ export function SecurityHostsPageProvider({ getService, getPageObjects }: FtrPro for (let i = 0; i < NodeSubmenuItems.length; i++) { await (await testSubjects.findAll('resolver:map:node-submenu-item'))[i].click(); const Events = await testSubjects.findAll('resolver:map:node-submenu-item'); + // this sleep is for the AMP enabled run + await pageObjects.common.sleep(300); const EventName = await Events[i]._webElement.getText(); const LinkText = await testSubjects.find('resolver:breadcrumbs:last'); const linkText = await LinkText._webElement.getText();